diff --git a/backend/src/server/routes/v1/identity-router.ts b/backend/src/server/routes/v1/identity-router.ts index 97ff78493..13758bf38 100644 --- a/backend/src/server/routes/v1/identity-router.ts +++ b/backend/src/server/routes/v1/identity-router.ts @@ -1,12 +1,6 @@ import { z } from "zod"; -import { - IdentitiesSchema, - IdentityAuthMethod, - IdentityOrgMembershipsSchema, - OrgMembershipRole, - OrgRolesSchema -} from "@app/db/schemas"; +import { IdentitiesSchema, IdentityOrgMembershipsSchema, OrgMembershipRole, OrgRolesSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { IDENTITIES } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -223,7 +217,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { description: true }).optional(), identity: IdentitiesSchema.pick({ name: true, id: true }).extend({ - authMethods: z.array(z.nativeEnum(IdentityAuthMethod)) + authMethods: z.array(z.string()) }) }) }) @@ -327,7 +321,9 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { temporaryAccessEndTime: z.date().nullable().optional() }) ), - identity: IdentitiesSchema.pick({ name: true, id: true, authMethod: true }), + identity: IdentitiesSchema.pick({ name: true, id: true }).extend({ + authMethods: z.array(z.string()) + }), project: SanitizedProjectSchema.pick({ name: true, id: true }) }) ) diff --git a/backend/src/server/routes/v2/identity-org-router.ts b/backend/src/server/routes/v2/identity-org-router.ts index 36856266a..52940eb44 100644 --- a/backend/src/server/routes/v2/identity-org-router.ts +++ b/backend/src/server/routes/v2/identity-org-router.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { IdentitiesSchema, IdentityAuthMethod, IdentityOrgMembershipsSchema, OrgRolesSchema } from "@app/db/schemas"; +import { IdentitiesSchema, IdentityOrgMembershipsSchema, OrgRolesSchema } from "@app/db/schemas"; import { ORGANIZATIONS } from "@app/lib/api-docs"; import { OrderByDirection } from "@app/lib/types"; import { readLimit } from "@app/server/config/rateLimiter"; @@ -59,7 +59,7 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => { description: true }).optional(), identity: IdentitiesSchema.pick({ name: true, id: true }).extend({ - authMethods: z.array(z.nativeEnum(IdentityAuthMethod)) + authMethods: z.array(z.string()) }) }) ).array(), diff --git a/backend/src/server/routes/v2/identity-project-router.ts b/backend/src/server/routes/v2/identity-project-router.ts index adb070ad9..da2b904d7 100644 --- a/backend/src/server/routes/v2/identity-project-router.ts +++ b/backend/src/server/routes/v2/identity-project-router.ts @@ -264,7 +264,9 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) temporaryAccessEndTime: z.date().nullable().optional() }) ), - identity: IdentitiesSchema.pick({ name: true, id: true, authMethod: true }), + identity: IdentitiesSchema.pick({ name: true, id: true }).extend({ + authMethods: z.array(z.string()) + }), project: SanitizedProjectSchema.pick({ name: true, id: true }) }) .array(), @@ -285,6 +287,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) orderDirection: req.query.orderDirection, search: req.query.search }); + return { identityMemberships, totalCount }; } }); diff --git a/backend/src/services/identity-project/identity-project-dal.ts b/backend/src/services/identity-project/identity-project-dal.ts index 3e7ca7946..e3583d14a 100644 --- a/backend/src/services/identity-project/identity-project-dal.ts +++ b/backend/src/services/identity-project/identity-project-dal.ts @@ -1,12 +1,24 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName, TIdentities } from "@app/db/schemas"; +import { + TableName, + TIdentities, + TIdentityAwsAuths, + TIdentityAzureAuths, + TIdentityGcpAuths, + TIdentityKubernetesAuths, + TIdentityOidcAuths, + TIdentityTokenAuths, + TIdentityUniversalAuths +} from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex"; import { OrderByDirection } from "@app/lib/types"; import { ProjectIdentityOrderBy, TListProjectIdentityDTO } from "@app/services/identity-project/identity-project-types"; +import { buildAuthMethods } from "../identity/identity-fns"; + export type TIdentityProjectDALFactory = ReturnType; export const identityProjectDALFactory = (db: TDbClient) => { @@ -33,11 +45,48 @@ export const identityProjectDALFactory = (db: TDbClient) => { `${TableName.IdentityProjectMembership}.id`, `${TableName.IdentityProjectAdditionalPrivilege}.projectMembershipId` ) + + .leftJoin( + TableName.IdentityUniversalAuth, + `${TableName.IdentityProjectMembership}.identityId`, + `${TableName.IdentityUniversalAuth}.identityId` + ) + .leftJoin( + TableName.IdentityGcpAuth, + `${TableName.IdentityProjectMembership}.identityId`, + `${TableName.IdentityGcpAuth}.identityId` + ) + .leftJoin( + TableName.IdentityAwsAuth, + `${TableName.IdentityProjectMembership}.identityId`, + `${TableName.IdentityAwsAuth}.identityId` + ) + .leftJoin( + TableName.IdentityKubernetesAuth, + `${TableName.IdentityProjectMembership}.identityId`, + `${TableName.IdentityKubernetesAuth}.identityId` + ) + .leftJoin( + TableName.IdentityOidcAuth, + `${TableName.IdentityProjectMembership}.identityId`, + `${TableName.IdentityOidcAuth}.identityId` + ) + .leftJoin( + TableName.IdentityAzureAuth, + `${TableName.IdentityProjectMembership}.identityId`, + `${TableName.IdentityAzureAuth}.identityId` + ) + .leftJoin( + TableName.IdentityTokenAuth, + `${TableName.IdentityProjectMembership}.identityId`, + `${TableName.IdentityTokenAuth}.identityId` + ) + .select( db.ref("id").withSchema(TableName.IdentityProjectMembership), db.ref("createdAt").withSchema(TableName.IdentityProjectMembership), db.ref("updatedAt").withSchema(TableName.IdentityProjectMembership), - db.ref("authMethod").as("identityAuthMethod").withSchema(TableName.Identity), + db.ref("id").as("identityId").withSchema(TableName.Identity), db.ref("name").as("identityName").withSchema(TableName.Identity), db.ref("id").withSchema(TableName.IdentityProjectMembership), @@ -52,12 +101,33 @@ export const identityProjectDALFactory = (db: TDbClient) => { db.ref("temporaryAccessStartTime").withSchema(TableName.IdentityProjectMembershipRole), db.ref("temporaryAccessEndTime").withSchema(TableName.IdentityProjectMembershipRole), db.ref("projectId").withSchema(TableName.IdentityProjectMembership), - db.ref("name").as("projectName").withSchema(TableName.Project) + db.ref("name").as("projectName").withSchema(TableName.Project), + db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth), + db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth), + db.ref("id").as("awsId").withSchema(TableName.IdentityAwsAuth), + db.ref("id").as("kubernetesId").withSchema(TableName.IdentityKubernetesAuth), + db.ref("id").as("oidcId").withSchema(TableName.IdentityOidcAuth), + db.ref("id").as("azureId").withSchema(TableName.IdentityAzureAuth), + db.ref("id").as("tokenId").withSchema(TableName.IdentityTokenAuth) ); const members = sqlNestRelationships({ data: docs, - parentMapper: ({ identityName, identityAuthMethod, id, createdAt, updatedAt, projectId, projectName }) => ({ + parentMapper: ({ + identityName, + uaId, + awsId, + gcpId, + kubernetesId, + oidcId, + azureId, + tokenId, + id, + createdAt, + updatedAt, + projectId, + projectName + }) => ({ id, identityId, createdAt, @@ -65,7 +135,15 @@ export const identityProjectDALFactory = (db: TDbClient) => { identity: { id: identityId, name: identityName, - authMethod: identityAuthMethod + authMethods: buildAuthMethods({ + uaId, + awsId, + gcpId, + kubernetesId, + oidcId, + azureId, + tokenId + }) }, project: { id: projectId, @@ -168,6 +246,43 @@ export const identityProjectDALFactory = (db: TDbClient) => { `${TableName.IdentityProjectMembership}.id`, `${TableName.IdentityProjectAdditionalPrivilege}.projectMembershipId` ) + + .leftJoin( + TableName.IdentityUniversalAuth, + `${TableName.Identity}.id`, + `${TableName.IdentityUniversalAuth}.identityId` + ) + .leftJoin( + TableName.IdentityGcpAuth, + `${TableName.Identity}.id`, + `${TableName.IdentityGcpAuth}.identityId` + ) + .leftJoin( + TableName.IdentityAwsAuth, + `${TableName.Identity}.id`, + `${TableName.IdentityAwsAuth}.identityId` + ) + .leftJoin( + TableName.IdentityKubernetesAuth, + `${TableName.Identity}.id`, + `${TableName.IdentityKubernetesAuth}.identityId` + ) + .leftJoin( + TableName.IdentityOidcAuth, + `${TableName.Identity}.id`, + `${TableName.IdentityOidcAuth}.identityId` + ) + .leftJoin( + TableName.IdentityAzureAuth, + `${TableName.Identity}.id`, + `${TableName.IdentityAzureAuth}.identityId` + ) + .leftJoin( + TableName.IdentityTokenAuth, + `${TableName.Identity}.id`, + `${TableName.IdentityTokenAuth}.identityId` + ) + .select( db.ref("id").withSchema(TableName.IdentityProjectMembership), db.ref("createdAt").withSchema(TableName.IdentityProjectMembership), @@ -186,7 +301,14 @@ export const identityProjectDALFactory = (db: TDbClient) => { db.ref("temporaryRange").withSchema(TableName.IdentityProjectMembershipRole), db.ref("temporaryAccessStartTime").withSchema(TableName.IdentityProjectMembershipRole), db.ref("temporaryAccessEndTime").withSchema(TableName.IdentityProjectMembershipRole), - db.ref("name").as("projectName").withSchema(TableName.Project) + db.ref("name").as("projectName").withSchema(TableName.Project), + db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth), + db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth), + db.ref("id").as("awsId").withSchema(TableName.IdentityAwsAuth), + db.ref("id").as("kubernetesId").withSchema(TableName.IdentityKubernetesAuth), + db.ref("id").as("oidcId").withSchema(TableName.IdentityOidcAuth), + db.ref("id").as("azureId").withSchema(TableName.IdentityAzureAuth), + db.ref("id").as("tokenId").withSchema(TableName.IdentityTokenAuth) ); // TODO: scott - joins seem to reorder identities so need to order again, for the sake of urgency will optimize at a later point @@ -204,7 +326,21 @@ export const identityProjectDALFactory = (db: TDbClient) => { const members = sqlNestRelationships({ data: docs, - parentMapper: ({ identityId, identityName, identityAuthMethod, id, createdAt, updatedAt, projectName }) => ({ + parentMapper: ({ + identityId, + identityName, + uaId, + awsId, + gcpId, + kubernetesId, + oidcId, + azureId, + tokenId, + id, + createdAt, + updatedAt, + projectName + }) => ({ id, identityId, createdAt, @@ -212,7 +348,15 @@ export const identityProjectDALFactory = (db: TDbClient) => { identity: { id: identityId, name: identityName, - authMethod: identityAuthMethod + authMethods: buildAuthMethods({ + uaId, + awsId, + gcpId, + kubernetesId, + oidcId, + azureId, + tokenId + }) }, project: { id: projectId, diff --git a/backend/src/services/identity/identity-fns.ts b/backend/src/services/identity/identity-fns.ts new file mode 100644 index 000000000..0d18aec5a --- /dev/null +++ b/backend/src/services/identity/identity-fns.ts @@ -0,0 +1,29 @@ +import { IdentityAuthMethod } from "@app/db/schemas"; + +export const buildAuthMethods = ({ + uaId, + gcpId, + awsId, + kubernetesId, + oidcId, + azureId, + tokenId +}: { + uaId?: string; + gcpId?: string; + awsId?: string; + kubernetesId?: string; + oidcId?: string; + azureId?: string; + tokenId?: string; +}) => { + return [ + ...(uaId ? [IdentityAuthMethod.UNIVERSAL_AUTH] : []), + ...(gcpId ? [IdentityAuthMethod.GCP_AUTH] : []), + ...(awsId ? [IdentityAuthMethod.AWS_AUTH] : []), + ...(kubernetesId ? [IdentityAuthMethod.KUBERNETES_AUTH] : []), + ...(oidcId ? [IdentityAuthMethod.OIDC_AUTH] : []), + ...(azureId ? [IdentityAuthMethod.AZURE_AUTH] : []), + ...(tokenId ? [IdentityAuthMethod.TOKEN_AUTH] : []) + ].filter((authMethod) => authMethod); +}; diff --git a/backend/src/services/identity/identity-org-dal.ts b/backend/src/services/identity/identity-org-dal.ts index 31ffff07f..bbdf96a2b 100644 --- a/backend/src/services/identity/identity-org-dal.ts +++ b/backend/src/services/identity/identity-org-dal.ts @@ -2,7 +2,6 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; import { - IdentityAuthMethod, TableName, TIdentityAwsAuths, TIdentityAzureAuths, @@ -19,33 +18,7 @@ import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex" import { OrderByDirection } from "@app/lib/types"; import { OrgIdentityOrderBy, TListOrgIdentitiesByOrgIdDTO } from "@app/services/identity/identity-types"; -const buildAuthMethods = ({ - uaId, - gcpId, - awsId, - kubernetesId, - oidcId, - azureId, - tokenId -}: { - uaId?: string; - gcpId?: string; - awsId?: string; - kubernetesId?: string; - oidcId?: string; - azureId?: string; - tokenId?: string; -}) => { - return [ - ...(uaId ? [IdentityAuthMethod.UNIVERSAL_AUTH] : []), - ...(gcpId ? [IdentityAuthMethod.GCP_AUTH] : []), - ...(awsId ? [IdentityAuthMethod.AWS_AUTH] : []), - ...(kubernetesId ? [IdentityAuthMethod.KUBERNETES_AUTH] : []), - ...(oidcId ? [IdentityAuthMethod.OIDC_AUTH] : []), - ...(azureId ? [IdentityAuthMethod.AZURE_AUTH] : []), - ...(tokenId ? [IdentityAuthMethod.TOKEN_AUTH] : []) - ].filter((authMethod) => authMethod); -}; +import { buildAuthMethods } from "./identity-fns"; export type TIdentityOrgDALFactory = ReturnType;