From 605ccb13e98b7e5d2b65941d5632726c6fe18f9c Mon Sep 17 00:00:00 2001 From: = Date: Tue, 18 Jun 2024 16:44:12 +0530 Subject: [PATCH 1/6] feat: added endpoints and docs for identity get by id and list operation --- backend/src/lib/api-docs/constants.ts | 7 ++ .../src/server/routes/v1/identity-router.ts | 92 ++++++++++++++++++- .../src/services/identity/identity-org-dal.ts | 6 +- .../src/services/identity/identity-service.ts | 29 +++++- .../src/services/identity/identity-types.ts | 4 + .../endpoints/identities/get-by-id.mdx | 5 + .../endpoints/identities/list.mdx | 4 + docs/mint.json | 6 +- 8 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 docs/api-reference/endpoints/identities/get-by-id.mdx create mode 100644 docs/api-reference/endpoints/identities/list.mdx diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index d768066fa7..3ac4e5734c 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -42,6 +42,13 @@ export const IDENTITIES = { }, DELETE: { identityId: "The ID of the identity to delete." + }, + GET_BY_ID: { + identityId: "The ID of the identity to get details.", + orgId: "The ID of the org of the identity" + }, + LIST: { + orgId: "The ID of the organization to list identities." } } as const; diff --git a/backend/src/server/routes/v1/identity-router.ts b/backend/src/server/routes/v1/identity-router.ts index e174cf974a..158261eb1b 100644 --- a/backend/src/server/routes/v1/identity-router.ts +++ b/backend/src/server/routes/v1/identity-router.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { IdentitiesSchema, OrgMembershipRole } 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 { creationLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -170,4 +170,94 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { return { identity }; } }); + + server.route({ + method: "GET", + url: "/:identityId", + config: { + rateLimit: writeLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Get an identity by id", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + identityId: z.string().describe(IDENTITIES.GET_BY_ID.identityId) + }), + response: { + 200: z.object({ + identity: IdentityOrgMembershipsSchema.extend({ + customRole: OrgRolesSchema.pick({ + id: true, + name: true, + slug: true, + permissions: true, + description: true + }).optional(), + identity: IdentitiesSchema.pick({ name: true, id: true, authMethod: true }) + }) + }) + } + }, + handler: async (req) => { + const identity = await server.services.identity.getIdentityById({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + id: req.params.identityId + }); + + return { identity }; + } + }); + + server.route({ + method: "GET", + url: "/", + config: { + rateLimit: writeLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "List identities", + security: [ + { + bearerAuth: [] + } + ], + querystring: z.object({ + orgId: z.string().describe(IDENTITIES.LIST.orgId) + }), + response: { + 200: z.object({ + identities: IdentityOrgMembershipsSchema.extend({ + customRole: OrgRolesSchema.pick({ + id: true, + name: true, + slug: true, + permissions: true, + description: true + }).optional(), + identity: IdentitiesSchema.pick({ name: true, id: true, authMethod: true }) + }).array() + }) + } + }, + handler: async (req) => { + const identities = await server.services.identity.listOrgIdentities({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + orgId: req.query.orgId + }); + + return { identities }; + } + }); }; diff --git a/backend/src/services/identity/identity-org-dal.ts b/backend/src/services/identity/identity-org-dal.ts index 95d742f334..0d31997254 100644 --- a/backend/src/services/identity/identity-org-dal.ts +++ b/backend/src/services/identity/identity-org-dal.ts @@ -27,10 +27,10 @@ export const identityOrgDALFactory = (db: TDbClient) => { } }; - const findByOrgId = async (orgId: string, tx?: Knex) => { + const find = async (filter: Partial, tx?: Knex) => { try { const docs = await (tx || db)(TableName.IdentityOrgMembership) - .where(`${TableName.IdentityOrgMembership}.orgId`, orgId) + .where(filter) .join(TableName.Identity, `${TableName.IdentityOrgMembership}.identityId`, `${TableName.Identity}.id`) .leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`) .select(selectAllTableCols(TableName.IdentityOrgMembership)) @@ -79,5 +79,5 @@ export const identityOrgDALFactory = (db: TDbClient) => { } }; - return { ...identityOrgOrm, findOne, findByOrgId }; + return { ...identityOrgOrm, find, findOne }; }; diff --git a/backend/src/services/identity/identity-service.ts b/backend/src/services/identity/identity-service.ts index 2863bf23eb..7d44cfdd4e 100644 --- a/backend/src/services/identity/identity-service.ts +++ b/backend/src/services/identity/identity-service.ts @@ -1,6 +1,6 @@ import { ForbiddenError } from "@casl/ability"; -import { OrgMembershipRole, TOrgRoles } from "@app/db/schemas"; +import { OrgMembershipRole, TableName, TOrgRoles } from "@app/db/schemas"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { isAtLeastAsPrivileged } from "@app/lib/casl"; @@ -10,7 +10,7 @@ import { TOrgPermission } from "@app/lib/types"; import { ActorType } from "../auth/auth-type"; import { TIdentityDALFactory } from "./identity-dal"; import { TIdentityOrgDALFactory } from "./identity-org-dal"; -import { TCreateIdentityDTO, TDeleteIdentityDTO, TUpdateIdentityDTO } from "./identity-types"; +import { TCreateIdentityDTO, TDeleteIdentityDTO, TGetIdentityByIdDTO, TUpdateIdentityDTO } from "./identity-types"; type TIdentityServiceFactoryDep = { identityDAL: TIdentityDALFactory; @@ -126,6 +126,24 @@ export const identityServiceFactory = ({ return { ...identity, orgId: identityOrgMembership.orgId }; }; + const getIdentityById = async ({ id, actor, actorId, actorOrgId, actorAuthMethod }: TGetIdentityByIdDTO) => { + const doc = await identityOrgMembershipDAL.find({ + [`${TableName.IdentityOrgMembership}.identityId` as "identityId"]: id + }); + const identity = doc[0]; + if (!identity) throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); + + const { permission } = await permissionService.getOrgPermission( + actor, + actorId, + identity.orgId, + actorAuthMethod, + actorOrgId + ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); + return identity; + }; + const deleteIdentity = async ({ actorId, actor, actorOrgId, actorAuthMethod, id }: TDeleteIdentityDTO) => { const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id }); if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); @@ -157,7 +175,9 @@ export const identityServiceFactory = ({ const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); - const identityMemberships = await identityOrgMembershipDAL.findByOrgId(orgId); + const identityMemberships = await identityOrgMembershipDAL.find({ + [`${TableName.IdentityOrgMembership}.orgId` as "orgId"]: orgId + }); return identityMemberships; }; @@ -165,6 +185,7 @@ export const identityServiceFactory = ({ createIdentity, updateIdentity, deleteIdentity, - listOrgIdentities + listOrgIdentities, + getIdentityById }; }; diff --git a/backend/src/services/identity/identity-types.ts b/backend/src/services/identity/identity-types.ts index 10b943667c..5125413e85 100644 --- a/backend/src/services/identity/identity-types.ts +++ b/backend/src/services/identity/identity-types.ts @@ -16,6 +16,10 @@ export type TDeleteIdentityDTO = { id: string; } & Omit; +export type TGetIdentityByIdDTO = { + id: string; +} & Omit; + export interface TIdentityTrustedIp { ipAddress: string; type: IPType; diff --git a/docs/api-reference/endpoints/identities/get-by-id.mdx b/docs/api-reference/endpoints/identities/get-by-id.mdx new file mode 100644 index 0000000000..f721d3556a --- /dev/null +++ b/docs/api-reference/endpoints/identities/get-by-id.mdx @@ -0,0 +1,5 @@ +--- +title: "Get By ID" +openapi: "GET /api/v1/identities/{identityId}" +--- + diff --git a/docs/api-reference/endpoints/identities/list.mdx b/docs/api-reference/endpoints/identities/list.mdx new file mode 100644 index 0000000000..d8972e3a91 --- /dev/null +++ b/docs/api-reference/endpoints/identities/list.mdx @@ -0,0 +1,4 @@ +--- +title: "List" +openapi: "GET /api/v1/identities" +--- diff --git a/docs/mint.json b/docs/mint.json index 1caad07156..9e07b01b1d 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -1,6 +1,6 @@ { "name": "Infisical", - "openapi": "https://app.infisical.com/api/docs/json", + "openapi": "http://localhost:8080/api/docs/json", "logo": { "dark": "/logo/dark.svg", "light": "/logo/light.svg", @@ -416,7 +416,9 @@ "pages": [ "api-reference/endpoints/identities/create", "api-reference/endpoints/identities/update", - "api-reference/endpoints/identities/delete" + "api-reference/endpoints/identities/delete", + "api-reference/endpoints/identities/get-by-id", + "api-reference/endpoints/identities/list" ] }, { From 0dc132dda33673eda28e9de66ba958ae86b69b11 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 18 Jun 2024 23:41:18 +0530 Subject: [PATCH 2/6] feat: added universal auth endpoints for revoke and client secret endpoint to fetch details --- .../ee/services/audit-log/audit-log-types.ts | 19 +++ backend/src/lib/api-docs/constants.ts | 7 + backend/src/server/routes/v1/identity-ua.ts | 134 +++++++++++++++--- .../identity-ua/identity-ua-service.ts | 113 +++++++++++++-- .../services/identity-ua/identity-ua-types.ts | 9 ++ .../get-client-secret-by-id.mdx | 4 + .../endpoints/universal-auth/revoke.mdx | 4 + docs/mint.json | 2 + 8 files changed, 262 insertions(+), 30 deletions(-) create mode 100644 docs/api-reference/endpoints/universal-auth/get-client-secret-by-id.mdx create mode 100644 docs/api-reference/endpoints/universal-auth/revoke.mdx diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index 8a0d2aef92..52fda0ba47 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -65,6 +65,7 @@ export enum EventType { ADD_IDENTITY_UNIVERSAL_AUTH = "add-identity-universal-auth", UPDATE_IDENTITY_UNIVERSAL_AUTH = "update-identity-universal-auth", GET_IDENTITY_UNIVERSAL_AUTH = "get-identity-universal-auth", + REVOKE_IDENTITY_UNIVERSAL_AUTH = "revoke-identity-universal-auth", LOGIN_IDENTITY_KUBERNETES_AUTH = "login-identity-kubernetes-auth", ADD_IDENTITY_KUBERNETES_AUTH = "add-identity-kubernetes-auth", UPDATE_IDENTITY_KUBENETES_AUTH = "update-identity-kubernetes-auth", @@ -72,6 +73,7 @@ export enum EventType { CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret", REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret", GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret", + GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET_BY_ID = "get-identity-universal-auth-client-secret-by-id", LOGIN_IDENTITY_GCP_AUTH = "login-identity-gcp-auth", ADD_IDENTITY_GCP_AUTH = "add-identity-gcp-auth", UPDATE_IDENTITY_GCP_AUTH = "update-identity-gcp-auth", @@ -434,6 +436,13 @@ interface GetIdentityUniversalAuthEvent { }; } +interface DeleteIdentityUniversalAuthEvent { + type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH; + metadata: { + identityId: string; + }; +} + interface LoginIdentityKubernetesAuthEvent { type: EventType.LOGIN_IDENTITY_KUBERNETES_AUTH; metadata: { @@ -493,6 +502,14 @@ interface GetIdentityUniversalAuthClientSecretsEvent { }; } +interface GetIdentityUniversalAuthClientSecretByIdEvent { + type: EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET_BY_ID; + metadata: { + identityId: string; + clientSecretId: string; + }; +} + interface RevokeIdentityUniversalAuthClientSecretEvent { type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET; metadata: { @@ -1003,6 +1020,7 @@ export type Event = | LoginIdentityUniversalAuthEvent | AddIdentityUniversalAuthEvent | UpdateIdentityUniversalAuthEvent + | DeleteIdentityUniversalAuthEvent | GetIdentityUniversalAuthEvent | LoginIdentityKubernetesAuthEvent | AddIdentityKubernetesAuthEvent @@ -1010,6 +1028,7 @@ export type Event = | GetIdentityKubernetesAuthEvent | CreateIdentityUniversalAuthClientSecretEvent | GetIdentityUniversalAuthClientSecretsEvent + | GetIdentityUniversalAuthClientSecretByIdEvent | RevokeIdentityUniversalAuthClientSecretEvent | LoginIdentityGcpAuthEvent | AddIdentityGcpAuthEvent diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 3ac4e5734c..5e8c85286d 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -72,6 +72,9 @@ export const UNIVERSAL_AUTH = { RETRIEVE: { identityId: "The ID of the identity to retrieve." }, + REVOKE: { + identityId: "The ID of the identity to revoke." + }, UPDATE: { identityId: "The ID of the identity to update.", clientSecretTrustedIps: "The new list of IPs or CIDR ranges that the Client Secret can be used from.", @@ -90,6 +93,10 @@ export const UNIVERSAL_AUTH = { LIST_CLIENT_SECRETS: { identityId: "The ID of the identity to list client secrets for." }, + GET_CLIENT_SECRET: { + identityId: "The ID of the identity to get the client secret from.", + clientSecretId: "The ID of the client secret to get details." + }, REVOKE_CLIENT_SECRET: { identityId: "The ID of the identity to revoke the client secret from.", clientSecretId: "The ID of the client secret to revoke." diff --git a/backend/src/server/routes/v1/identity-ua.ts b/backend/src/server/routes/v1/identity-ua.ts index 670f52416d..d2d60d1126 100644 --- a/backend/src/server/routes/v1/identity-ua.ts +++ b/backend/src/server/routes/v1/identity-ua.ts @@ -134,7 +134,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const identityUniversalAuth = await server.services.identityUa.attachUa({ + const identityUniversalAuth = await server.services.identityUa.attachUniversalAuth({ actor: req.permission.type, actorId: req.permission.id, actorOrgId: req.permission.orgId, @@ -219,7 +219,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const identityUniversalAuth = await server.services.identityUa.updateUa({ + const identityUniversalAuth = await server.services.identityUa.updateUniversalAuth({ actor: req.permission.type, actorId: req.permission.id, actorOrgId: req.permission.orgId, @@ -272,7 +272,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const identityUniversalAuth = await server.services.identityUa.getIdentityUa({ + const identityUniversalAuth = await server.services.identityUa.getIdentityUniversalAuth({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -295,6 +295,53 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }); + server.route({ + method: "DELETE", + url: "/universal-auth/identities/:identityId", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Delete Universal Auth configuration on identity", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + identityId: z.string().describe(UNIVERSAL_AUTH.REVOKE.identityId) + }), + response: { + 200: z.object({ + identityUniversalAuth: IdentityUniversalAuthsSchema + }) + } + }, + handler: async (req) => { + const identityUniversalAuth = await server.services.identityUa.revokeIdentityUniversalAuth({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: identityUniversalAuth.orgId, + event: { + type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH, + metadata: { + identityId: identityUniversalAuth.identityId + } + } + }); + + return { identityUniversalAuth }; + } + }); + server.route({ method: "POST", url: "/universal-auth/identities/:identityId/client-secrets", @@ -325,14 +372,15 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const { clientSecret, clientSecretData, orgId } = await server.services.identityUa.createUaClientSecret({ - actor: req.permission.type, - actorId: req.permission.id, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - identityId: req.params.identityId, - ...req.body - }); + const { clientSecret, clientSecretData, orgId } = + await server.services.identityUa.createUniversalAuthClientSecret({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId, + ...req.body + }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, @@ -374,24 +422,76 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const { clientSecrets: clientSecretData, orgId } = await server.services.identityUa.getUaClientSecrets({ + const { clientSecrets: clientSecretData, orgId } = await server.services.identityUa.getUniversalAuthClientSecrets( + { + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId + } + ); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId, + event: { + type: EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS, + metadata: { + identityId: req.params.identityId + } + } + }); + return { clientSecretData }; + } + }); + + server.route({ + method: "GET", + url: "/universal-auth/identities/:identityId/client-secrets/:clientSecretId", + config: { + rateLimit: writeLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Get Universal Auth Client Secret for identity", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + identityId: z.string().describe(UNIVERSAL_AUTH.GET_CLIENT_SECRET.identityId), + clientSecretId: z.string().describe(UNIVERSAL_AUTH.GET_CLIENT_SECRET.clientSecretId) + }), + response: { + 200: z.object({ + clientSecretData: sanitizedClientSecretSchema + }) + } + }, + handler: async (req) => { + const clientSecretData = await server.services.identityUa.getUniversalAuthClientSecretById({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - identityId: req.params.identityId + identityId: req.params.identityId, + clientSecretId: req.params.clientSecretId }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - orgId, + orgId: clientSecretData.orgId, event: { - type: EventType.GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS, + type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET, metadata: { - identityId: req.params.identityId + identityId: clientSecretData.identityId, + clientSecretId: clientSecretData.id } } }); + return { clientSecretData }; } }); @@ -421,7 +521,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const clientSecretData = await server.services.identityUa.revokeUaClientSecret({ + const clientSecretData = await server.services.identityUa.revokeUniversalAuthClientSecret({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, diff --git a/backend/src/services/identity-ua/identity-ua-service.ts b/backend/src/services/identity-ua/identity-ua-service.ts index 5e940871b5..3d9f0c3cb4 100644 --- a/backend/src/services/identity-ua/identity-ua-service.ts +++ b/backend/src/services/identity-ua/identity-ua-service.ts @@ -25,7 +25,9 @@ import { TCreateUaClientSecretDTO, TGetUaClientSecretsDTO, TGetUaDTO, + TGetUniversalAuthClientSecretByIdDTO, TRevokeUaClientSecretDTO, + TRevokeUaDTO, TUpdateUaDTO } from "./identity-ua-types"; @@ -136,7 +138,7 @@ export const identityUaServiceFactory = ({ return { accessToken, identityUa, validClientSecretInfo, identityAccessToken, identityMembershipOrg }; }; - const attachUa = async ({ + const attachUniversalAuth = async ({ accessTokenMaxTTL, identityId, accessTokenNumUsesLimit, @@ -227,7 +229,7 @@ export const identityUaServiceFactory = ({ return { ...identityUa, orgId: identityMembershipOrg.orgId }; }; - const updateUa = async ({ + const updateUniversalAuth = async ({ accessTokenMaxTTL, identityId, accessTokenNumUsesLimit, @@ -312,7 +314,7 @@ export const identityUaServiceFactory = ({ return { ...updatedUaAuth, orgId: identityMembershipOrg.orgId }; }; - const getIdentityUa = async ({ identityId, actorId, actor, actorAuthMethod, actorOrgId }: TGetUaDTO) => { + const getIdentityUniversalAuth = async ({ identityId, actorId, actor, actorAuthMethod, actorOrgId }: TGetUaDTO) => { const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral) @@ -333,7 +335,50 @@ export const identityUaServiceFactory = ({ return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId }; }; - const createUaClientSecret = async ({ + const revokeIdentityUniversalAuth = async ({ + identityId, + actorId, + actor, + actorAuthMethod, + actorOrgId + }: TRevokeUaDTO) => { + const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); + if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); + if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral) + throw new BadRequestError({ + message: "The identity does not have universal auth" + }); + const { permission } = await permissionService.getOrgPermission( + actor, + actorId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + + const { permission: rolePermission } = await permissionService.getOrgPermission( + ActorType.IDENTITY, + identityMembershipOrg.identityId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); + if (!hasPriviledge) + throw new ForbiddenRequestError({ + message: "Failed to revoke universal auth of identity with more privileged role" + }); + + const revokedIdentityUniversalAuth = await identityUaDAL.transaction(async (tx) => { + const deletedUniversalAuth = await identityUaDAL.delete({ identityId }, tx); + await identityDAL.updateById(identityId, { authMethod: null }, tx); + return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + }); + return revokedIdentityUniversalAuth; + }; + + const createUniversalAuthClientSecret = async ({ actor, actorId, actorOrgId, @@ -396,7 +441,7 @@ export const identityUaServiceFactory = ({ }; }; - const getUaClientSecrets = async ({ + const getUniversalAuthClientSecrets = async ({ actor, actorId, actorOrgId, @@ -442,7 +487,47 @@ export const identityUaServiceFactory = ({ return { clientSecrets, orgId: identityMembershipOrg.orgId }; }; - const revokeUaClientSecret = async ({ + const getUniversalAuthClientSecretById = async ({ + identityId, + actorId, + actor, + actorOrgId, + actorAuthMethod, + clientSecretId + }: TGetUniversalAuthClientSecretByIdDTO) => { + const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); + if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); + if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral) + throw new BadRequestError({ + message: "The identity does not have universal auth" + }); + const { permission } = await permissionService.getOrgPermission( + actor, + actorId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity); + + const { permission: rolePermission } = await permissionService.getOrgPermission( + ActorType.IDENTITY, + identityMembershipOrg.identityId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); + if (!hasPriviledge) + throw new ForbiddenRequestError({ + message: "Failed to read identity client secret of project with more privileged role" + }); + + const clientSecret = await identityUaClientSecretDAL.findById(clientSecretId); + return { ...clientSecret, identityId, orgId: identityMembershipOrg.orgId }; + }; + + const revokeUniversalAuthClientSecret = async ({ identityId, actorId, actor, @@ -475,7 +560,7 @@ export const identityUaServiceFactory = ({ const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); if (!hasPriviledge) throw new ForbiddenRequestError({ - message: "Failed to add identity to project with more privileged role" + message: "Failed to revoke identity client secret with more privileged role" }); const clientSecret = await identityUaClientSecretDAL.updateById(clientSecretId, { @@ -486,11 +571,13 @@ export const identityUaServiceFactory = ({ return { login, - attachUa, - updateUa, - getIdentityUa, - createUaClientSecret, - getUaClientSecrets, - revokeUaClientSecret + attachUniversalAuth, + updateUniversalAuth, + getIdentityUniversalAuth, + revokeIdentityUniversalAuth, + createUniversalAuthClientSecret, + getUniversalAuthClientSecrets, + revokeUniversalAuthClientSecret, + getUniversalAuthClientSecretById }; }; diff --git a/backend/src/services/identity-ua/identity-ua-types.ts b/backend/src/services/identity-ua/identity-ua-types.ts index 2cc4762a81..2045c21432 100644 --- a/backend/src/services/identity-ua/identity-ua-types.ts +++ b/backend/src/services/identity-ua/identity-ua-types.ts @@ -22,6 +22,10 @@ export type TGetUaDTO = { identityId: string; } & Omit; +export type TRevokeUaDTO = { + identityId: string; +} & Omit; + export type TCreateUaClientSecretDTO = { identityId: string; description: string; @@ -37,3 +41,8 @@ export type TRevokeUaClientSecretDTO = { identityId: string; clientSecretId: string; } & Omit; + +export type TGetUniversalAuthClientSecretByIdDTO = { + identityId: string; + clientSecretId: string; +} & Omit; diff --git a/docs/api-reference/endpoints/universal-auth/get-client-secret-by-id.mdx b/docs/api-reference/endpoints/universal-auth/get-client-secret-by-id.mdx new file mode 100644 index 0000000000..477ee875cd --- /dev/null +++ b/docs/api-reference/endpoints/universal-auth/get-client-secret-by-id.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Client Secret By ID" +openapi: "GET /api/v1/auth/universal-auth/identities/{identityId}/client-secrets/{clientSecretId}" +--- diff --git a/docs/api-reference/endpoints/universal-auth/revoke.mdx b/docs/api-reference/endpoints/universal-auth/revoke.mdx new file mode 100644 index 0000000000..e2a19e93c3 --- /dev/null +++ b/docs/api-reference/endpoints/universal-auth/revoke.mdx @@ -0,0 +1,4 @@ +--- +title: "Revoke" +openapi: "DELETE /api/v1/auth/universal-auth/identities/{identityId}" +--- diff --git a/docs/mint.json b/docs/mint.json index 9e07b01b1d..9a50bd0793 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -428,9 +428,11 @@ "api-reference/endpoints/universal-auth/attach", "api-reference/endpoints/universal-auth/retrieve", "api-reference/endpoints/universal-auth/update", + "api-reference/endpoints/universal-auth/revoke", "api-reference/endpoints/universal-auth/create-client-secret", "api-reference/endpoints/universal-auth/list-client-secrets", "api-reference/endpoints/universal-auth/revoke-client-secret", + "api-reference/endpoints/universal-auth/get-client-secret-by-id", "api-reference/endpoints/universal-auth/renew-access-token", "api-reference/endpoints/universal-auth/revoke-access-token" ] From 4072a40fe9dac4737314c5e9972c579e79a45fbe Mon Sep 17 00:00:00 2001 From: = Date: Thu, 20 Jun 2024 21:17:52 +0530 Subject: [PATCH 3/6] feat: completed all revoke for other identity auth --- .../ee/services/audit-log/audit-log-types.ts | 36 ++++++++++++ backend/src/lib/api-docs/constants.ts | 21 +++++++ .../routes/v1/identity-aws-iam-auth-router.ts | 47 +++++++++++++++ .../routes/v1/identity-azure-auth-router.ts | 48 ++++++++++++++++ .../routes/v1/identity-gcp-auth-router.ts | 48 ++++++++++++++++ .../v1/identity-kubernetes-auth-router.ts | 51 +++++++++++++++++ .../identity-aws-auth-service.ts | 54 ++++++++++++++++-- .../identity-aws-auth-types.ts | 4 ++ .../identity-azure-auth-service.ts | 57 +++++++++++++++++-- .../identity-azure-auth-types.ts | 4 ++ .../identity-gcp-auth-service.ts | 54 ++++++++++++++++-- .../identity-gcp-auth-types.ts | 4 ++ .../identity-kubernetes-auth-service.ts | 54 ++++++++++++++++-- .../identity-kubernetes-auth-types.ts | 4 ++ docs/mint.json | 2 +- 15 files changed, 471 insertions(+), 17 deletions(-) diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index 52fda0ba47..0c6ff51c8e 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -70,6 +70,7 @@ export enum EventType { ADD_IDENTITY_KUBERNETES_AUTH = "add-identity-kubernetes-auth", UPDATE_IDENTITY_KUBENETES_AUTH = "update-identity-kubernetes-auth", GET_IDENTITY_KUBERNETES_AUTH = "get-identity-kubernetes-auth", + REVOKE_IDENTITY_KUBERNETES_AUTH = "revoke-identity-kubernetes-auth", CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret", REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret", GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret", @@ -77,15 +78,18 @@ export enum EventType { LOGIN_IDENTITY_GCP_AUTH = "login-identity-gcp-auth", ADD_IDENTITY_GCP_AUTH = "add-identity-gcp-auth", UPDATE_IDENTITY_GCP_AUTH = "update-identity-gcp-auth", + REVOKE_IDENTITY_GCP_AUTH = "revoke-identity-gcp-auth", GET_IDENTITY_GCP_AUTH = "get-identity-gcp-auth", LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth", ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth", UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth", + REVOKE_IDENTITY_AWS_AUTH = "revoke-identity-aws-auth", GET_IDENTITY_AWS_AUTH = "get-identity-aws-auth", LOGIN_IDENTITY_AZURE_AUTH = "login-identity-azure-auth", ADD_IDENTITY_AZURE_AUTH = "add-identity-azure-auth", UPDATE_IDENTITY_AZURE_AUTH = "update-identity-azure-auth", GET_IDENTITY_AZURE_AUTH = "get-identity-azure-auth", + REVOKE_IDENTITY_AZURE_AUTH = "revoke-identity-azure-auth", CREATE_ENVIRONMENT = "create-environment", UPDATE_ENVIRONMENT = "update-environment", DELETE_ENVIRONMENT = "delete-environment", @@ -466,6 +470,13 @@ interface AddIdentityKubernetesAuthEvent { }; } +interface DeleteIdentityKubernetesAuthEvent { + type: EventType.REVOKE_IDENTITY_KUBERNETES_AUTH; + metadata: { + identityId: string; + }; +} + interface UpdateIdentityKubernetesAuthEvent { type: EventType.UPDATE_IDENTITY_KUBENETES_AUTH; metadata: { @@ -542,6 +553,13 @@ interface AddIdentityGcpAuthEvent { }; } +interface DeleteIdentityGcpAuthEvent { + type: EventType.REVOKE_IDENTITY_GCP_AUTH; + metadata: { + identityId: string; + }; +} + interface UpdateIdentityGcpAuthEvent { type: EventType.UPDATE_IDENTITY_GCP_AUTH; metadata: { @@ -587,6 +605,13 @@ interface AddIdentityAwsAuthEvent { }; } +interface DeleteIdentityAwsAuthEvent { + type: EventType.REVOKE_IDENTITY_AWS_AUTH; + metadata: { + identityId: string; + }; +} + interface UpdateIdentityAwsAuthEvent { type: EventType.UPDATE_IDENTITY_AWS_AUTH; metadata: { @@ -630,6 +655,13 @@ interface AddIdentityAzureAuthEvent { }; } +interface DeleteIdentityAzureAuthEvent { + type: EventType.REVOKE_IDENTITY_AZURE_AUTH; + metadata: { + identityId: string; + }; +} + interface UpdateIdentityAzureAuthEvent { type: EventType.UPDATE_IDENTITY_AZURE_AUTH; metadata: { @@ -1023,6 +1055,7 @@ export type Event = | DeleteIdentityUniversalAuthEvent | GetIdentityUniversalAuthEvent | LoginIdentityKubernetesAuthEvent + | DeleteIdentityKubernetesAuthEvent | AddIdentityKubernetesAuthEvent | UpdateIdentityKubernetesAuthEvent | GetIdentityKubernetesAuthEvent @@ -1032,14 +1065,17 @@ export type Event = | RevokeIdentityUniversalAuthClientSecretEvent | LoginIdentityGcpAuthEvent | AddIdentityGcpAuthEvent + | DeleteIdentityGcpAuthEvent | UpdateIdentityGcpAuthEvent | GetIdentityGcpAuthEvent | LoginIdentityAwsAuthEvent | AddIdentityAwsAuthEvent | UpdateIdentityAwsAuthEvent | GetIdentityAwsAuthEvent + | DeleteIdentityAwsAuthEvent | LoginIdentityAzureAuthEvent | AddIdentityAzureAuthEvent + | DeleteIdentityAzureAuthEvent | UpdateIdentityAzureAuthEvent | GetIdentityAzureAuthEvent | CreateEnvironmentEvent diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 5e8c85286d..802610967e 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -118,6 +118,27 @@ export const AWS_AUTH = { iamRequestBody: "The base64-encoded body of the signed request. Most likely, the base64-encoding of Action=GetCallerIdentity&Version=2011-06-15.", iamRequestHeaders: "The base64-encoded headers of the sts:GetCallerIdentity signed request." + }, + REVOKE: { + identityId: "The ID of the identity to revoke." + } +} as const; + +export const AZURE_AUTH = { + REVOKE: { + identityId: "The ID of the identity to revoke." + } +} as const; + +export const GCP_AUTH = { + REVOKE: { + identityId: "The ID of the identity to revoke." + } +} as const; + +export const KUBERNETES_AUTH = { + REVOKE: { + identityId: "The ID of the identity to revoke." } } as const; diff --git a/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts b/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts index f8c0451683..d3530797c3 100644 --- a/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts +++ b/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts @@ -266,4 +266,51 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) return { identityAwsAuth }; } }); + + server.route({ + method: "DELETE", + url: "/aws-auth/identities/:identityId", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Delete AWS Auth configuration on identity", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + identityId: z.string().describe(AWS_AUTH.REVOKE.identityId) + }), + response: { + 200: z.object({ + identityAwsAuth: IdentityAwsAuthsSchema + }) + } + }, + handler: async (req) => { + const identityAwsAuth = await server.services.identityAwsAuth.revokeIdentityAwsAuth({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: identityAwsAuth.orgId, + event: { + type: EventType.REVOKE_IDENTITY_AWS_AUTH, + metadata: { + identityId: identityAwsAuth.identityId + } + } + }); + + return { identityAwsAuth }; + } + }); }; diff --git a/backend/src/server/routes/v1/identity-azure-auth-router.ts b/backend/src/server/routes/v1/identity-azure-auth-router.ts index d10cd131b2..bd18102cca 100644 --- a/backend/src/server/routes/v1/identity-azure-auth-router.ts +++ b/backend/src/server/routes/v1/identity-azure-auth-router.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { IdentityAzureAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { AZURE_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -259,4 +260,51 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider return { identityAzureAuth }; } }); + + server.route({ + method: "DELETE", + url: "/azure-auth/identities/:identityId", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Delete Azure Auth configuration on identity", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + identityId: z.string().describe(AZURE_AUTH.REVOKE.identityId) + }), + response: { + 200: z.object({ + identityAzureAuth: IdentityAzureAuthsSchema + }) + } + }, + handler: async (req) => { + const identityAzureAuth = await server.services.identityAzureAuth.revokeIdentityAzureAuth({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: identityAzureAuth.orgId, + event: { + type: EventType.REVOKE_IDENTITY_AZURE_AUTH, + metadata: { + identityId: identityAzureAuth.identityId + } + } + }); + + return { identityAzureAuth }; + } + }); }; diff --git a/backend/src/server/routes/v1/identity-gcp-auth-router.ts b/backend/src/server/routes/v1/identity-gcp-auth-router.ts index 34940eb13e..64e76bc1e1 100644 --- a/backend/src/server/routes/v1/identity-gcp-auth-router.ts +++ b/backend/src/server/routes/v1/identity-gcp-auth-router.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { IdentityGcpAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { GCP_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -265,4 +266,51 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider) return { identityGcpAuth }; } }); + + server.route({ + method: "DELETE", + url: "/gcp-auth/identities/:identityId", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Delete GCP Auth configuration on identity", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + identityId: z.string().describe(GCP_AUTH.REVOKE.identityId) + }), + response: { + 200: z.object({ + identityGcpAuth: IdentityGcpAuthsSchema + }) + } + }, + handler: async (req) => { + const identityGcpAuth = await server.services.identityGcpAuth.revokeIdentityGcpAuth({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: identityGcpAuth.orgId, + event: { + type: EventType.REVOKE_IDENTITY_GCP_AUTH, + metadata: { + identityId: identityGcpAuth.identityId + } + } + }); + + return { identityGcpAuth }; + } + }); }; diff --git a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts index 2273459166..fc26525f79 100644 --- a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts +++ b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { IdentityKubernetesAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { KUBERNETES_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -280,4 +281,54 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide return { identityKubernetesAuth: IdentityKubernetesAuthResponseSchema.parse(identityKubernetesAuth) }; } }); + + server.route({ + method: "DELETE", + url: "/kubernetes-auth/identities/:identityId", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Delete Kubernetes Auth configuration on identity", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + identityId: z.string().describe(KUBERNETES_AUTH.REVOKE.identityId) + }), + response: { + 200: z.object({ + identityKubernetesAuth: IdentityKubernetesAuthResponseSchema.omit({ + caCert: true, + tokenReviewerJwt: true + }) + }) + } + }, + handler: async (req) => { + const identityKubernetesAuth = await server.services.identityKubernetesAuth.revokeIdentityKubernetesAuth({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: identityKubernetesAuth.orgId, + event: { + type: EventType.REVOKE_IDENTITY_KUBERNETES_AUTH, + metadata: { + identityId: identityKubernetesAuth.identityId + } + } + }); + + return { identityKubernetesAuth }; + } + }); }; diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts index a589449093..0df860f109 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts @@ -7,11 +7,12 @@ import { IdentityAuthMethod } from "@app/db/schemas"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; +import { isAtLeastAsPrivileged } from "@app/lib/casl"; import { getConfig } from "@app/lib/config/env"; -import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; +import { BadRequestError, ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors"; import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip"; -import { AuthTokenType } from "../auth/auth-type"; +import { ActorType, AuthTokenType } from "../auth/auth-type"; import { TIdentityDALFactory } from "../identity/identity-dal"; import { TIdentityOrgDALFactory } from "../identity/identity-org-dal"; import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal"; @@ -24,12 +25,13 @@ import { TGetAwsAuthDTO, TGetCallerIdentityResponse, TLoginAwsAuthDTO, + TRevokeAwsAuthDTO, TUpdateAwsAuthDTO } from "./identity-aws-auth-types"; type TIdentityAwsAuthServiceFactoryDep = { identityAccessTokenDAL: Pick; - identityAwsAuthDAL: Pick; + identityAwsAuthDAL: Pick; identityOrgMembershipDAL: Pick; identityDAL: Pick; licenseService: Pick; @@ -301,10 +303,54 @@ export const identityAwsAuthServiceFactory = ({ return { ...awsIdentityAuth, orgId: identityMembershipOrg.orgId }; }; + const revokeIdentityAwsAuth = async ({ + identityId, + actorId, + actor, + actorAuthMethod, + actorOrgId + }: TRevokeAwsAuthDTO) => { + const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); + if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); + if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.AWS_AUTH) + throw new BadRequestError({ + message: "The identity does not have aws auth" + }); + const { permission } = await permissionService.getOrgPermission( + actor, + actorId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + + const { permission: rolePermission } = await permissionService.getOrgPermission( + ActorType.IDENTITY, + identityMembershipOrg.identityId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); + if (!hasPriviledge) + throw new ForbiddenRequestError({ + message: "Failed to revoke aws auth of identity with more privileged role" + }); + + const revokedIdentityAwsAuth = await identityAwsAuthDAL.transaction(async (tx) => { + const deletedUniversalAuth = await identityAwsAuthDAL.delete({ identityId }, tx); + await identityDAL.updateById(identityId, { authMethod: null }, tx); + return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + }); + return revokedIdentityAwsAuth; + }; + return { login, attachAwsAuth, updateAwsAuth, - getAwsAuth + getAwsAuth, + revokeIdentityAwsAuth }; }; diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-types.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-types.ts index e45783ae1d..c24186ee0e 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-types.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-types.ts @@ -52,3 +52,7 @@ export type TGetCallerIdentityResponse = { ResponseMetadata: { RequestId: string }; }; }; + +export type TRevokeAwsAuthDTO = { + identityId: string; +} & Omit; diff --git a/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts b/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts index fa439bdc00..0844437451 100644 --- a/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts +++ b/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts @@ -5,11 +5,12 @@ import { IdentityAuthMethod } from "@app/db/schemas"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; +import { isAtLeastAsPrivileged } from "@app/lib/casl"; import { getConfig } from "@app/lib/config/env"; -import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; +import { BadRequestError, ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors"; import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip"; -import { AuthTokenType } from "../auth/auth-type"; +import { ActorType, AuthTokenType } from "../auth/auth-type"; import { TIdentityDALFactory } from "../identity/identity-dal"; import { TIdentityOrgDALFactory } from "../identity/identity-org-dal"; import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal"; @@ -20,11 +21,15 @@ import { TAttachAzureAuthDTO, TGetAzureAuthDTO, TLoginAzureAuthDTO, + TRevokeAzureAuthDTO, TUpdateAzureAuthDTO } from "./identity-azure-auth-types"; type TIdentityAzureAuthServiceFactoryDep = { - identityAzureAuthDAL: Pick; + identityAzureAuthDAL: Pick< + TIdentityAzureAuthDALFactory, + "findOne" | "transaction" | "create" | "updateById" | "delete" + >; identityOrgMembershipDAL: Pick; identityAccessTokenDAL: Pick; identityDAL: Pick; @@ -277,10 +282,54 @@ export const identityAzureAuthServiceFactory = ({ return { ...identityAzureAuth, orgId: identityMembershipOrg.orgId }; }; + const revokeIdentityAzureAuth = async ({ + identityId, + actorId, + actor, + actorAuthMethod, + actorOrgId + }: TRevokeAzureAuthDTO) => { + const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); + if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); + if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.AZURE_AUTH) + throw new BadRequestError({ + message: "The identity does not have azure auth" + }); + const { permission } = await permissionService.getOrgPermission( + actor, + actorId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + + const { permission: rolePermission } = await permissionService.getOrgPermission( + ActorType.IDENTITY, + identityMembershipOrg.identityId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); + if (!hasPriviledge) + throw new ForbiddenRequestError({ + message: "Failed to revoke azure auth of identity with more privileged role" + }); + + const revokedIdentityAzureAuth = await identityAzureAuthDAL.transaction(async (tx) => { + const deletedUniversalAuth = await identityAzureAuthDAL.delete({ identityId }, tx); + await identityDAL.updateById(identityId, { authMethod: null }, tx); + return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + }); + return revokedIdentityAzureAuth; + }; + return { login, attachAzureAuth, updateAzureAuth, - getAzureAuth + getAzureAuth, + revokeIdentityAzureAuth }; }; diff --git a/backend/src/services/identity-azure-auth/identity-azure-auth-types.ts b/backend/src/services/identity-azure-auth/identity-azure-auth-types.ts index 65459003c0..ec03451dbc 100644 --- a/backend/src/services/identity-azure-auth/identity-azure-auth-types.ts +++ b/backend/src/services/identity-azure-auth/identity-azure-auth-types.ts @@ -118,3 +118,7 @@ export type TDecodedAzureAuthJwt = { [key: string]: string; }; }; + +export type TRevokeAzureAuthDTO = { + identityId: string; +} & Omit; diff --git a/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts b/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts index 5f829cb335..97436598e8 100644 --- a/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts +++ b/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts @@ -5,11 +5,12 @@ import { IdentityAuthMethod } from "@app/db/schemas"; import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; +import { isAtLeastAsPrivileged } from "@app/lib/casl"; import { getConfig } from "@app/lib/config/env"; -import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; +import { BadRequestError, ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors"; import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip"; -import { AuthTokenType } from "../auth/auth-type"; +import { ActorType, AuthTokenType } from "../auth/auth-type"; import { TIdentityDALFactory } from "../identity/identity-dal"; import { TIdentityOrgDALFactory } from "../identity/identity-org-dal"; import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal"; @@ -21,11 +22,12 @@ import { TGcpIdentityDetails, TGetGcpAuthDTO, TLoginGcpAuthDTO, + TRevokeGcpAuthDTO, TUpdateGcpAuthDTO } from "./identity-gcp-auth-types"; type TIdentityGcpAuthServiceFactoryDep = { - identityGcpAuthDAL: Pick; + identityGcpAuthDAL: Pick; identityOrgMembershipDAL: Pick; identityAccessTokenDAL: Pick; identityDAL: Pick; @@ -315,10 +317,54 @@ export const identityGcpAuthServiceFactory = ({ return { ...identityGcpAuth, orgId: identityMembershipOrg.orgId }; }; + const revokeIdentityGcpAuth = async ({ + identityId, + actorId, + actor, + actorAuthMethod, + actorOrgId + }: TRevokeGcpAuthDTO) => { + const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); + if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); + if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.AWS_AUTH) + throw new BadRequestError({ + message: "The identity does not have aws auth" + }); + const { permission } = await permissionService.getOrgPermission( + actor, + actorId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + + const { permission: rolePermission } = await permissionService.getOrgPermission( + ActorType.IDENTITY, + identityMembershipOrg.identityId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); + if (!hasPriviledge) + throw new ForbiddenRequestError({ + message: "Failed to revoke gcp auth of identity with more privileged role" + }); + + const revokedIdentityGcpAuth = await identityGcpAuthDAL.transaction(async (tx) => { + const deletedUniversalAuth = await identityGcpAuthDAL.delete({ identityId }, tx); + await identityDAL.updateById(identityId, { authMethod: null }, tx); + return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + }); + return revokedIdentityGcpAuth; + }; + return { login, attachGcpAuth, updateGcpAuth, - getGcpAuth + getGcpAuth, + revokeIdentityGcpAuth }; }; diff --git a/backend/src/services/identity-gcp-auth/identity-gcp-auth-types.ts b/backend/src/services/identity-gcp-auth/identity-gcp-auth-types.ts index 60ab36b58a..45e64b24b6 100644 --- a/backend/src/services/identity-gcp-auth/identity-gcp-auth-types.ts +++ b/backend/src/services/identity-gcp-auth/identity-gcp-auth-types.ts @@ -76,3 +76,7 @@ export type TDecodedGcpIamAuthJwt = { [key: string]: string; }; }; + +export type TRevokeGcpAuthDTO = { + identityId: string; +} & Omit; diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index f1e1c6be0a..2c73d025b7 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -7,6 +7,7 @@ import { IdentityAuthMethod, SecretKeyEncoding, TIdentityKubernetesAuthsUpdate } import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; +import { isAtLeastAsPrivileged } from "@app/lib/casl"; import { getConfig } from "@app/lib/config/env"; import { decryptSymmetric, @@ -16,11 +17,11 @@ import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption"; -import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; +import { BadRequestError, ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors"; import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip"; import { TOrgBotDALFactory } from "@app/services/org/org-bot-dal"; -import { AuthTokenType } from "../auth/auth-type"; +import { ActorType, AuthTokenType } from "../auth/auth-type"; import { TIdentityDALFactory } from "../identity/identity-dal"; import { TIdentityOrgDALFactory } from "../identity/identity-org-dal"; import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal"; @@ -32,13 +33,14 @@ import { TCreateTokenReviewResponse, TGetKubernetesAuthDTO, TLoginKubernetesAuthDTO, + TRevokeKubernetesAuthDTO, TUpdateKubernetesAuthDTO } from "./identity-kubernetes-auth-types"; type TIdentityKubernetesAuthServiceFactoryDep = { identityKubernetesAuthDAL: Pick< TIdentityKubernetesAuthDALFactory, - "create" | "findOne" | "transaction" | "updateById" + "create" | "findOne" | "transaction" | "updateById" | "delete" >; identityAccessTokenDAL: Pick; identityOrgMembershipDAL: Pick; @@ -533,10 +535,54 @@ export const identityKubernetesAuthServiceFactory = ({ return { ...identityKubernetesAuth, caCert, tokenReviewerJwt, orgId: identityMembershipOrg.orgId }; }; + const revokeIdentityKubernetesAuth = async ({ + identityId, + actorId, + actor, + actorAuthMethod, + actorOrgId + }: TRevokeKubernetesAuthDTO) => { + const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); + if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); + if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.KUBERNETES_AUTH) + throw new BadRequestError({ + message: "The identity does not have kubenetes auth" + }); + const { permission } = await permissionService.getOrgPermission( + actor, + actorId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + + const { permission: rolePermission } = await permissionService.getOrgPermission( + ActorType.IDENTITY, + identityMembershipOrg.identityId, + identityMembershipOrg.orgId, + actorAuthMethod, + actorOrgId + ); + const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); + if (!hasPriviledge) + throw new ForbiddenRequestError({ + message: "Failed to revoke kubenetes auth of identity with more privileged role" + }); + + const revokedIdentityKubernetesAuth = await identityKubernetesAuthDAL.transaction(async (tx) => { + const deletedUniversalAuth = await identityKubernetesAuthDAL.delete({ identityId }, tx); + await identityDAL.updateById(identityId, { authMethod: null }, tx); + return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + }); + return revokedIdentityKubernetesAuth; + }; + return { login, attachKubernetesAuth, updateKubernetesAuth, - getKubernetesAuth + getKubernetesAuth, + revokeIdentityKubernetesAuth }; }; diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-types.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-types.ts index dbb42dce89..f1cde2be9a 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-types.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-types.ts @@ -59,3 +59,7 @@ export type TCreateTokenReviewResponse = { }; status: TCreateTokenReviewSuccessResponse | TCreateTokenReviewErrorResponse; }; + +export type TRevokeKubernetesAuthDTO = { + identityId: string; +} & Omit; diff --git a/docs/mint.json b/docs/mint.json index 9a50bd0793..d418f553ce 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -1,6 +1,6 @@ { "name": "Infisical", - "openapi": "http://localhost:8080/api/docs/json", + "openapi": "https://app.infisical.com/api/docs/json", "logo": { "dark": "/logo/dark.svg", "light": "/logo/light.svg", From b6cc17d62aecdcd1bab8782ce64e0b9e7f004232 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 23 Jun 2024 01:21:26 +0530 Subject: [PATCH 4/6] feat: updated var names and permission, rate limit changes based on comments --- .../src/server/routes/v1/identity-aws-iam-auth-router.ts | 2 +- backend/src/server/routes/v1/identity-azure-auth-router.ts | 2 +- backend/src/server/routes/v1/identity-gcp-auth-router.ts | 2 +- .../src/server/routes/v1/identity-kubernetes-auth-router.ts | 2 +- .../{identity-ua.ts => identity-universal-auth-router.ts} | 4 ++-- backend/src/server/routes/v1/index.ts | 2 +- .../services/identity-aws-auth/identity-aws-auth-service.ts | 6 +++--- .../identity-azure-auth/identity-azure-auth-service.ts | 6 +++--- .../services/identity-gcp-auth/identity-gcp-auth-service.ts | 6 +++--- .../identity-kubernetes-auth-service.ts | 6 +++--- backend/src/services/identity-ua/identity-ua-service.ts | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) rename backend/src/server/routes/v1/{identity-ua.ts => identity-universal-auth-router.ts} (100%) diff --git a/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts b/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts index d3530797c3..8a85323a60 100644 --- a/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts +++ b/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts @@ -271,7 +271,7 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) method: "DELETE", url: "/aws-auth/identities/:identityId", config: { - rateLimit: readLimit + rateLimit: writeLimit }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { diff --git a/backend/src/server/routes/v1/identity-azure-auth-router.ts b/backend/src/server/routes/v1/identity-azure-auth-router.ts index bd18102cca..6b4a7fb37d 100644 --- a/backend/src/server/routes/v1/identity-azure-auth-router.ts +++ b/backend/src/server/routes/v1/identity-azure-auth-router.ts @@ -265,7 +265,7 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider method: "DELETE", url: "/azure-auth/identities/:identityId", config: { - rateLimit: readLimit + rateLimit: writeLimit }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { diff --git a/backend/src/server/routes/v1/identity-gcp-auth-router.ts b/backend/src/server/routes/v1/identity-gcp-auth-router.ts index 64e76bc1e1..0deeb95d30 100644 --- a/backend/src/server/routes/v1/identity-gcp-auth-router.ts +++ b/backend/src/server/routes/v1/identity-gcp-auth-router.ts @@ -271,7 +271,7 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider) method: "DELETE", url: "/gcp-auth/identities/:identityId", config: { - rateLimit: readLimit + rateLimit: writeLimit }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { diff --git a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts index fc26525f79..4c54f1e7cb 100644 --- a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts +++ b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts @@ -286,7 +286,7 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide method: "DELETE", url: "/kubernetes-auth/identities/:identityId", config: { - rateLimit: readLimit + rateLimit: writeLimit }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { diff --git a/backend/src/server/routes/v1/identity-ua.ts b/backend/src/server/routes/v1/identity-universal-auth-router.ts similarity index 100% rename from backend/src/server/routes/v1/identity-ua.ts rename to backend/src/server/routes/v1/identity-universal-auth-router.ts index d2d60d1126..b5a63f0dbc 100644 --- a/backend/src/server/routes/v1/identity-ua.ts +++ b/backend/src/server/routes/v1/identity-universal-auth-router.ts @@ -299,7 +299,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { method: "DELETE", url: "/universal-auth/identities/:identityId", config: { - rateLimit: readLimit + rateLimit: writeLimit }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { @@ -450,7 +450,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { method: "GET", url: "/universal-auth/identities/:identityId/client-secrets/:clientSecretId", config: { - rateLimit: writeLimit + rateLimit: readLimit }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { diff --git a/backend/src/server/routes/v1/index.ts b/backend/src/server/routes/v1/index.ts index eee7dac65d..c2969b382e 100644 --- a/backend/src/server/routes/v1/index.ts +++ b/backend/src/server/routes/v1/index.ts @@ -9,7 +9,7 @@ import { registerIdentityAzureAuthRouter } from "./identity-azure-auth-router"; import { registerIdentityGcpAuthRouter } from "./identity-gcp-auth-router"; import { registerIdentityKubernetesRouter } from "./identity-kubernetes-auth-router"; import { registerIdentityRouter } from "./identity-router"; -import { registerIdentityUaRouter } from "./identity-ua"; +import { registerIdentityUaRouter } from "./identity-universal-auth-router"; import { registerIntegrationAuthRouter } from "./integration-auth-router"; import { registerIntegrationRouter } from "./integration-router"; import { registerInviteOrgRouter } from "./invite-org-router"; diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts index 0df860f109..9cb39aece0 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts @@ -323,7 +323,7 @@ export const identityAwsAuthServiceFactory = ({ actorAuthMethod, actorOrgId ); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); const { permission: rolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, @@ -339,9 +339,9 @@ export const identityAwsAuthServiceFactory = ({ }); const revokedIdentityAwsAuth = await identityAwsAuthDAL.transaction(async (tx) => { - const deletedUniversalAuth = await identityAwsAuthDAL.delete({ identityId }, tx); + const deletedAwsAuth = await identityAwsAuthDAL.delete({ identityId }, tx); await identityDAL.updateById(identityId, { authMethod: null }, tx); - return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + return { ...deletedAwsAuth?.[0], orgId: identityMembershipOrg.orgId }; }); return revokedIdentityAwsAuth; }; diff --git a/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts b/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts index 0844437451..0d52bf6a05 100644 --- a/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts +++ b/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts @@ -302,7 +302,7 @@ export const identityAzureAuthServiceFactory = ({ actorAuthMethod, actorOrgId ); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); const { permission: rolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, @@ -318,9 +318,9 @@ export const identityAzureAuthServiceFactory = ({ }); const revokedIdentityAzureAuth = await identityAzureAuthDAL.transaction(async (tx) => { - const deletedUniversalAuth = await identityAzureAuthDAL.delete({ identityId }, tx); + const deletedAzureAuth = await identityAzureAuthDAL.delete({ identityId }, tx); await identityDAL.updateById(identityId, { authMethod: null }, tx); - return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + return { ...deletedAzureAuth?.[0], orgId: identityMembershipOrg.orgId }; }); return revokedIdentityAzureAuth; }; diff --git a/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts b/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts index 97436598e8..824e593ceb 100644 --- a/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts +++ b/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts @@ -337,7 +337,7 @@ export const identityGcpAuthServiceFactory = ({ actorAuthMethod, actorOrgId ); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); const { permission: rolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, @@ -353,9 +353,9 @@ export const identityGcpAuthServiceFactory = ({ }); const revokedIdentityGcpAuth = await identityGcpAuthDAL.transaction(async (tx) => { - const deletedUniversalAuth = await identityGcpAuthDAL.delete({ identityId }, tx); + const deletedGcpAuth = await identityGcpAuthDAL.delete({ identityId }, tx); await identityDAL.updateById(identityId, { authMethod: null }, tx); - return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + return { ...deletedGcpAuth?.[0], orgId: identityMembershipOrg.orgId }; }); return revokedIdentityGcpAuth; }; diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index 2c73d025b7..820777b465 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -555,7 +555,7 @@ export const identityKubernetesAuthServiceFactory = ({ actorAuthMethod, actorOrgId ); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); const { permission: rolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, @@ -571,9 +571,9 @@ export const identityKubernetesAuthServiceFactory = ({ }); const revokedIdentityKubernetesAuth = await identityKubernetesAuthDAL.transaction(async (tx) => { - const deletedUniversalAuth = await identityKubernetesAuthDAL.delete({ identityId }, tx); + const deletedKubernetesAuth = await identityKubernetesAuthDAL.delete({ identityId }, tx); await identityDAL.updateById(identityId, { authMethod: null }, tx); - return { ...deletedUniversalAuth?.[0], orgId: identityMembershipOrg.orgId }; + return { ...deletedKubernetesAuth?.[0], orgId: identityMembershipOrg.orgId }; }); return revokedIdentityKubernetesAuth; }; diff --git a/backend/src/services/identity-ua/identity-ua-service.ts b/backend/src/services/identity-ua/identity-ua-service.ts index 3d9f0c3cb4..00dfa5d600 100644 --- a/backend/src/services/identity-ua/identity-ua-service.ts +++ b/backend/src/services/identity-ua/identity-ua-service.ts @@ -355,7 +355,7 @@ export const identityUaServiceFactory = ({ actorAuthMethod, actorOrgId ); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity); const { permission: rolePermission } = await permissionService.getOrgPermission( ActorType.IDENTITY, From 084fc7c99e4b594a6a37951be266583b5b7b8810 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 23 Jun 2024 01:25:27 +0530 Subject: [PATCH 5/6] feat: resolved gcp auth revoke error --- .../services/identity-gcp-auth/identity-gcp-auth-service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts b/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts index 824e593ceb..edac7c132f 100644 --- a/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts +++ b/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts @@ -326,9 +326,9 @@ export const identityGcpAuthServiceFactory = ({ }: TRevokeGcpAuthDTO) => { const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); - if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.AWS_AUTH) + if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.GCP_AUTH) throw new BadRequestError({ - message: "The identity does not have aws auth" + message: "The identity does not have gcp auth" }); const { permission } = await permissionService.getOrgPermission( actor, From a15a0a257c4c3be3d62bbd52d7f5021763581a92 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Mon, 24 Jun 2024 20:38:11 +0200 Subject: [PATCH 6/6] Update identity-router.ts --- backend/src/server/routes/v1/identity-router.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/server/routes/v1/identity-router.ts b/backend/src/server/routes/v1/identity-router.ts index 158261eb1b..a425f963e1 100644 --- a/backend/src/server/routes/v1/identity-router.ts +++ b/backend/src/server/routes/v1/identity-router.ts @@ -3,7 +3,7 @@ import { z } from "zod"; 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 { creationLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { creationLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -175,7 +175,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { method: "GET", url: "/:identityId", config: { - rateLimit: writeLimit + rateLimit: readLimit }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: {