feat: added universal auth endpoints for revoke and client secret endpoint to fetch details

This commit is contained in:
=
2024-06-20 21:18:45 +05:30
parent 605ccb13e9
commit 0dc132dda3
8 changed files with 264 additions and 32 deletions
@@ -65,6 +65,7 @@ export enum EventType {
ADD_IDENTITY_UNIVERSAL_AUTH = "add-identity-universal-auth", ADD_IDENTITY_UNIVERSAL_AUTH = "add-identity-universal-auth",
UPDATE_IDENTITY_UNIVERSAL_AUTH = "update-identity-universal-auth", UPDATE_IDENTITY_UNIVERSAL_AUTH = "update-identity-universal-auth",
GET_IDENTITY_UNIVERSAL_AUTH = "get-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", LOGIN_IDENTITY_KUBERNETES_AUTH = "login-identity-kubernetes-auth",
ADD_IDENTITY_KUBERNETES_AUTH = "add-identity-kubernetes-auth", ADD_IDENTITY_KUBERNETES_AUTH = "add-identity-kubernetes-auth",
UPDATE_IDENTITY_KUBENETES_AUTH = "update-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", CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-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_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", LOGIN_IDENTITY_GCP_AUTH = "login-identity-gcp-auth",
ADD_IDENTITY_GCP_AUTH = "add-identity-gcp-auth", ADD_IDENTITY_GCP_AUTH = "add-identity-gcp-auth",
UPDATE_IDENTITY_GCP_AUTH = "update-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 { interface LoginIdentityKubernetesAuthEvent {
type: EventType.LOGIN_IDENTITY_KUBERNETES_AUTH; type: EventType.LOGIN_IDENTITY_KUBERNETES_AUTH;
metadata: { 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 { interface RevokeIdentityUniversalAuthClientSecretEvent {
type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET; type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET;
metadata: { metadata: {
@@ -1003,6 +1020,7 @@ export type Event =
| LoginIdentityUniversalAuthEvent | LoginIdentityUniversalAuthEvent
| AddIdentityUniversalAuthEvent | AddIdentityUniversalAuthEvent
| UpdateIdentityUniversalAuthEvent | UpdateIdentityUniversalAuthEvent
| DeleteIdentityUniversalAuthEvent
| GetIdentityUniversalAuthEvent | GetIdentityUniversalAuthEvent
| LoginIdentityKubernetesAuthEvent | LoginIdentityKubernetesAuthEvent
| AddIdentityKubernetesAuthEvent | AddIdentityKubernetesAuthEvent
@@ -1010,6 +1028,7 @@ export type Event =
| GetIdentityKubernetesAuthEvent | GetIdentityKubernetesAuthEvent
| CreateIdentityUniversalAuthClientSecretEvent | CreateIdentityUniversalAuthClientSecretEvent
| GetIdentityUniversalAuthClientSecretsEvent | GetIdentityUniversalAuthClientSecretsEvent
| GetIdentityUniversalAuthClientSecretByIdEvent
| RevokeIdentityUniversalAuthClientSecretEvent | RevokeIdentityUniversalAuthClientSecretEvent
| LoginIdentityGcpAuthEvent | LoginIdentityGcpAuthEvent
| AddIdentityGcpAuthEvent | AddIdentityGcpAuthEvent
+7
View File
@@ -72,6 +72,9 @@ export const UNIVERSAL_AUTH = {
RETRIEVE: { RETRIEVE: {
identityId: "The ID of the identity to retrieve." identityId: "The ID of the identity to retrieve."
}, },
REVOKE: {
identityId: "The ID of the identity to revoke."
},
UPDATE: { UPDATE: {
identityId: "The ID of the identity to 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.", 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: { LIST_CLIENT_SECRETS: {
identityId: "The ID of the identity to list client secrets for." 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: { REVOKE_CLIENT_SECRET: {
identityId: "The ID of the identity to revoke the client secret from.", identityId: "The ID of the identity to revoke the client secret from.",
clientSecretId: "The ID of the client secret to revoke." clientSecretId: "The ID of the client secret to revoke."
+119 -19
View File
@@ -134,7 +134,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
} }
}, },
handler: async (req) => { handler: async (req) => {
const identityUniversalAuth = await server.services.identityUa.attachUa({ const identityUniversalAuth = await server.services.identityUa.attachUniversalAuth({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
@@ -219,7 +219,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
} }
}, },
handler: async (req) => { handler: async (req) => {
const identityUniversalAuth = await server.services.identityUa.updateUa({ const identityUniversalAuth = await server.services.identityUa.updateUniversalAuth({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
@@ -272,7 +272,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
} }
}, },
handler: async (req) => { handler: async (req) => {
const identityUniversalAuth = await server.services.identityUa.getIdentityUa({ const identityUniversalAuth = await server.services.identityUa.getIdentityUniversalAuth({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod, 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({ server.route({
method: "POST", method: "POST",
url: "/universal-auth/identities/:identityId/client-secrets", url: "/universal-auth/identities/:identityId/client-secrets",
@@ -325,14 +372,15 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
} }
}, },
handler: async (req) => { handler: async (req) => {
const { clientSecret, clientSecretData, orgId } = await server.services.identityUa.createUaClientSecret({ const { clientSecret, clientSecretData, orgId } =
actor: req.permission.type, await server.services.identityUa.createUniversalAuthClientSecret({
actorId: req.permission.id, actor: req.permission.type,
actorAuthMethod: req.permission.authMethod, actorId: req.permission.id,
actorOrgId: req.permission.orgId, actorAuthMethod: req.permission.authMethod,
identityId: req.params.identityId, actorOrgId: req.permission.orgId,
...req.body identityId: req.params.identityId,
}); ...req.body
});
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
...req.auditLogInfo, ...req.auditLogInfo,
@@ -374,13 +422,15 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
} }
}, },
handler: async (req) => { 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, actor: req.permission.type,
actorAuthMethod: req.permission.authMethod, actorId: req.permission.id,
actorOrgId: req.permission.orgId, actorAuthMethod: req.permission.authMethod,
identityId: req.params.identityId actorOrgId: req.permission.orgId,
}); identityId: req.params.identityId
}
);
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
...req.auditLogInfo, ...req.auditLogInfo,
@@ -396,6 +446,56 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
} }
}); });
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,
clientSecretId: req.params.clientSecretId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: clientSecretData.orgId,
event: {
type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET,
metadata: {
identityId: clientSecretData.identityId,
clientSecretId: clientSecretData.id
}
}
});
return { clientSecretData };
}
});
server.route({ server.route({
method: "POST", method: "POST",
url: "/universal-auth/identities/:identityId/client-secrets/:clientSecretId/revoke", url: "/universal-auth/identities/:identityId/client-secrets/:clientSecretId/revoke",
@@ -421,7 +521,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
} }
}, },
handler: async (req) => { handler: async (req) => {
const clientSecretData = await server.services.identityUa.revokeUaClientSecret({ const clientSecretData = await server.services.identityUa.revokeUniversalAuthClientSecret({
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod, actorAuthMethod: req.permission.authMethod,
@@ -25,7 +25,9 @@ import {
TCreateUaClientSecretDTO, TCreateUaClientSecretDTO,
TGetUaClientSecretsDTO, TGetUaClientSecretsDTO,
TGetUaDTO, TGetUaDTO,
TGetUniversalAuthClientSecretByIdDTO,
TRevokeUaClientSecretDTO, TRevokeUaClientSecretDTO,
TRevokeUaDTO,
TUpdateUaDTO TUpdateUaDTO
} from "./identity-ua-types"; } from "./identity-ua-types";
@@ -136,7 +138,7 @@ export const identityUaServiceFactory = ({
return { accessToken, identityUa, validClientSecretInfo, identityAccessToken, identityMembershipOrg }; return { accessToken, identityUa, validClientSecretInfo, identityAccessToken, identityMembershipOrg };
}; };
const attachUa = async ({ const attachUniversalAuth = async ({
accessTokenMaxTTL, accessTokenMaxTTL,
identityId, identityId,
accessTokenNumUsesLimit, accessTokenNumUsesLimit,
@@ -227,7 +229,7 @@ export const identityUaServiceFactory = ({
return { ...identityUa, orgId: identityMembershipOrg.orgId }; return { ...identityUa, orgId: identityMembershipOrg.orgId };
}; };
const updateUa = async ({ const updateUniversalAuth = async ({
accessTokenMaxTTL, accessTokenMaxTTL,
identityId, identityId,
accessTokenNumUsesLimit, accessTokenNumUsesLimit,
@@ -312,7 +314,7 @@ export const identityUaServiceFactory = ({
return { ...updatedUaAuth, orgId: identityMembershipOrg.orgId }; 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 }); const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" }); if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral) if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
@@ -333,7 +335,50 @@ export const identityUaServiceFactory = ({
return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId }; 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, actor,
actorId, actorId,
actorOrgId, actorOrgId,
@@ -396,7 +441,7 @@ export const identityUaServiceFactory = ({
}; };
}; };
const getUaClientSecrets = async ({ const getUniversalAuthClientSecrets = async ({
actor, actor,
actorId, actorId,
actorOrgId, actorOrgId,
@@ -442,7 +487,47 @@ export const identityUaServiceFactory = ({
return { clientSecrets, orgId: identityMembershipOrg.orgId }; 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, identityId,
actorId, actorId,
actor, actor,
@@ -475,7 +560,7 @@ export const identityUaServiceFactory = ({
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge) if (!hasPriviledge)
throw new ForbiddenRequestError({ 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, { const clientSecret = await identityUaClientSecretDAL.updateById(clientSecretId, {
@@ -486,11 +571,13 @@ export const identityUaServiceFactory = ({
return { return {
login, login,
attachUa, attachUniversalAuth,
updateUa, updateUniversalAuth,
getIdentityUa, getIdentityUniversalAuth,
createUaClientSecret, revokeIdentityUniversalAuth,
getUaClientSecrets, createUniversalAuthClientSecret,
revokeUaClientSecret getUniversalAuthClientSecrets,
revokeUniversalAuthClientSecret,
getUniversalAuthClientSecretById
}; };
}; };
@@ -22,6 +22,10 @@ export type TGetUaDTO = {
identityId: string; identityId: string;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
export type TRevokeUaDTO = {
identityId: string;
} & Omit<TProjectPermission, "projectId">;
export type TCreateUaClientSecretDTO = { export type TCreateUaClientSecretDTO = {
identityId: string; identityId: string;
description: string; description: string;
@@ -37,3 +41,8 @@ export type TRevokeUaClientSecretDTO = {
identityId: string; identityId: string;
clientSecretId: string; clientSecretId: string;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
export type TGetUniversalAuthClientSecretByIdDTO = {
identityId: string;
clientSecretId: string;
} & Omit<TProjectPermission, "projectId">;
@@ -0,0 +1,4 @@
---
title: "Get Client Secret By ID"
openapi: "GET /api/v1/auth/universal-auth/identities/{identityId}/client-secrets/{clientSecretId}"
---
@@ -0,0 +1,4 @@
---
title: "Revoke"
openapi: "DELETE /api/v1/auth/universal-auth/identities/{identityId}"
---
+2
View File
@@ -428,9 +428,11 @@
"api-reference/endpoints/universal-auth/attach", "api-reference/endpoints/universal-auth/attach",
"api-reference/endpoints/universal-auth/retrieve", "api-reference/endpoints/universal-auth/retrieve",
"api-reference/endpoints/universal-auth/update", "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/create-client-secret",
"api-reference/endpoints/universal-auth/list-client-secrets", "api-reference/endpoints/universal-auth/list-client-secrets",
"api-reference/endpoints/universal-auth/revoke-client-secret", "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/renew-access-token",
"api-reference/endpoints/universal-auth/revoke-access-token" "api-reference/endpoints/universal-auth/revoke-access-token"
] ]