feat: standardize org ID's on auth requests

This commit is contained in:
Daniel Hougaard
2024-03-17 18:48:09 +01:00
parent 92441e018f
commit 96abbd9f80
5 changed files with 36 additions and 6 deletions
@@ -30,6 +30,7 @@ export type TAuthMode =
serviceToken: TServiceTokens & { createdByEmail: string }; serviceToken: TServiceTokens & { createdByEmail: string };
actor: ActorType.SERVICE; actor: ActorType.SERVICE;
serviceTokenId: string; serviceTokenId: string;
orgId: string;
} }
| { | {
authMode: AuthMode.IDENTITY_ACCESS_TOKEN; authMode: AuthMode.IDENTITY_ACCESS_TOKEN;
@@ -99,8 +100,12 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
if (!authMode) return; if (!authMode) return;
switch (authMode) { switch (authMode) {
// May or may not have an orgId. If it doesn't have an org ID, it's likely because the token is from an org that doesn't enforce org-level auth.
case AuthMode.JWT: { case AuthMode.JWT: {
const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(token); const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(
token,
req.headers?.["x-infisical-organization-id"]
);
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor, orgId }; req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor, orgId };
break; break;
} }
@@ -116,21 +121,25 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
}; };
break; break;
} }
// Will always contain an orgId.
case AuthMode.SERVICE_TOKEN: { case AuthMode.SERVICE_TOKEN: {
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token); const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token);
req.auth = { req.auth = {
authMode: AuthMode.SERVICE_TOKEN as const, authMode: AuthMode.SERVICE_TOKEN as const,
serviceToken, serviceToken,
orgId: serviceToken.orgId,
serviceTokenId: serviceToken.id, serviceTokenId: serviceToken.id,
actor actor
}; };
break; break;
} }
// Will never contain an orgId. API keys are not tied to an organization.
case AuthMode.API_KEY: { case AuthMode.API_KEY: {
const user = await server.services.apiKey.fnValidateApiKey(token as string); const user = await server.services.apiKey.fnValidateApiKey(token as string);
req.auth = { authMode: AuthMode.API_KEY as const, userId: user.id, actor, user }; req.auth = { authMode: AuthMode.API_KEY as const, userId: user.id, actor, user };
break; break;
} }
// OK
case AuthMode.SCIM_TOKEN: { case AuthMode.SCIM_TOKEN: {
const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token); const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token);
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId }; req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId };
@@ -13,7 +13,7 @@ export const injectPermission = fp(async (server) => {
} else if (req.auth.actor === ActorType.IDENTITY) { } else if (req.auth.actor === ActorType.IDENTITY) {
req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId, orgId: req.auth.orgId }; req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId, orgId: req.auth.orgId };
} else if (req.auth.actor === ActorType.SERVICE) { } else if (req.auth.actor === ActorType.SERVICE) {
req.permission = { type: ActorType.SERVICE, id: req.auth.serviceTokenId }; req.permission = { type: ActorType.SERVICE, id: req.auth.serviceTokenId, orgId: req.auth.orgId };
} else if (req.auth.actor === ActorType.SCIM_CLIENT) { } else if (req.auth.actor === ActorType.SCIM_CLIENT) {
req.permission = { type: ActorType.SCIM_CLIENT, id: req.auth.scimTokenId, orgId: req.auth.orgId }; req.permission = { type: ActorType.SCIM_CLIENT, id: req.auth.scimTokenId, orgId: req.auth.orgId };
} }
+2 -1
View File
@@ -264,7 +264,7 @@ export const registerRoutes = async (
queueService queueService
}); });
const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL }); const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL, orgDAL });
const userService = userServiceFactory({ userDAL }); const userService = userServiceFactory({ userDAL });
const loginService = authLoginServiceFactory({ userDAL, smtpService, tokenService }); const loginService = authLoginServiceFactory({ userDAL, smtpService, tokenService });
const passwordService = authPaswordServiceFactory({ const passwordService = authPaswordServiceFactory({
@@ -517,6 +517,7 @@ export const registerRoutes = async (
const serviceTokenService = serviceTokenServiceFactory({ const serviceTokenService = serviceTokenServiceFactory({
projectEnvDAL, projectEnvDAL,
serviceTokenDAL, serviceTokenDAL,
orgDAL,
userDAL, userDAL,
permissionService permissionService
}); });
@@ -7,6 +7,7 @@ import { getConfig } from "@app/lib/config/env";
import { UnauthorizedError } from "@app/lib/errors"; import { UnauthorizedError } from "@app/lib/errors";
import { AuthModeJwtTokenPayload } from "../auth/auth-type"; import { AuthModeJwtTokenPayload } from "../auth/auth-type";
import { TOrgDALFactory } from "../org/org-dal";
import { TUserDALFactory } from "../user/user-dal"; import { TUserDALFactory } from "../user/user-dal";
import { TTokenDALFactory } from "./auth-token-dal"; import { TTokenDALFactory } from "./auth-token-dal";
import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenForUserDTO } from "./auth-token-types"; import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenForUserDTO } from "./auth-token-types";
@@ -14,6 +15,7 @@ import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenFo
type TAuthTokenServiceFactoryDep = { type TAuthTokenServiceFactoryDep = {
tokenDAL: TTokenDALFactory; tokenDAL: TTokenDALFactory;
userDAL: Pick<TUserDALFactory, "findById">; userDAL: Pick<TUserDALFactory, "findById">;
orgDAL: Pick<TOrgDALFactory, "findMembership">;
}; };
export type TAuthTokenServiceFactory = ReturnType<typeof tokenServiceFactory>; export type TAuthTokenServiceFactory = ReturnType<typeof tokenServiceFactory>;
@@ -54,7 +56,7 @@ export const getTokenConfig = (tokenType: TokenType) => {
} }
}; };
export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFactoryDep) => { export const tokenServiceFactory = ({ tokenDAL, userDAL, orgDAL }: TAuthTokenServiceFactoryDep) => {
const createTokenForUser = async ({ type, userId, orgId }: TCreateTokenForUserDTO) => { const createTokenForUser = async ({ type, userId, orgId }: TCreateTokenForUserDTO) => {
const { token, ...tkCfg } = getTokenConfig(type); const { token, ...tkCfg } = getTokenConfig(type);
const appCfg = getConfig(); const appCfg = getConfig();
@@ -130,7 +132,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact
const revokeAllMySessions = async (userId: string) => tokenDAL.deleteTokenSession({ userId }); const revokeAllMySessions = async (userId: string) => tokenDAL.deleteTokenSession({ userId });
// to parse jwt identity in inject identity plugin // to parse jwt identity in inject identity plugin
const fnValidateJwtIdentity = async (token: AuthModeJwtTokenPayload) => { const fnValidateJwtIdentity = async (token: AuthModeJwtTokenPayload, organizationIdHeader?: string | string[]) => {
const session = await tokenDAL.findOneTokenSession({ const session = await tokenDAL.findOneTokenSession({
id: token.tokenVersionId, id: token.tokenVersionId,
userId: token.userId userId: token.userId
@@ -141,7 +143,22 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact
const user = await userDAL.findById(session.userId); const user = await userDAL.findById(session.userId);
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" }); if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
return { user, tokenVersionId: token.tokenVersionId, orgId: token.organizationId }; let orgId = token.organizationId;
if (!token.organizationId && organizationIdHeader) {
// If the token doesn't have an organization ID, but an organization ID is provided in the header, we need to check if the user is a member of the organization before concluding the organization ID is valid.
const userMembership = (
await orgDAL.findMembership({
userId: user.id,
orgId: organizationIdHeader as string
})
)[0];
if (!userMembership) throw new UnauthorizedError({ name: "User not a member of the organization" });
orgId = userMembership.orgId;
}
return { user, tokenVersionId: token.tokenVersionId, orgId };
}; };
return { return {
@@ -9,6 +9,7 @@ import { getConfig } from "@app/lib/config/env";
import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
import { ActorType } from "../auth/auth-type"; import { ActorType } from "../auth/auth-type";
import { TOrgDALFactory } from "../org/org-dal";
import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
import { TUserDALFactory } from "../user/user-dal"; import { TUserDALFactory } from "../user/user-dal";
import { TServiceTokenDALFactory } from "./service-token-dal"; import { TServiceTokenDALFactory } from "./service-token-dal";
@@ -23,6 +24,7 @@ type TServiceTokenServiceFactoryDep = {
serviceTokenDAL: TServiceTokenDALFactory; serviceTokenDAL: TServiceTokenDALFactory;
userDAL: TUserDALFactory; userDAL: TUserDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
orgDAL: Pick<TOrgDALFactory, "findOrgByProjectId">;
projectEnvDAL: Pick<TProjectEnvDALFactory, "findBySlugs">; projectEnvDAL: Pick<TProjectEnvDALFactory, "findBySlugs">;
}; };
@@ -31,6 +33,7 @@ export type TServiceTokenServiceFactory = ReturnType<typeof serviceTokenServiceF
export const serviceTokenServiceFactory = ({ export const serviceTokenServiceFactory = ({
serviceTokenDAL, serviceTokenDAL,
userDAL, userDAL,
orgDAL,
permissionService, permissionService,
projectEnvDAL projectEnvDAL
}: TServiceTokenServiceFactoryDep) => { }: TServiceTokenServiceFactoryDep) => {