mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
fix: sub-org support in login endpoint for machine identities
This commit is contained in:
@@ -170,10 +170,13 @@ export const IDENTITIES = {
|
||||
}
|
||||
} as const;
|
||||
|
||||
const IDENTITY_AUTH_SUB_ORGANIZATION_NAME = "sub-organization slug to scope the token to";
|
||||
|
||||
export const UNIVERSAL_AUTH = {
|
||||
LOGIN: {
|
||||
clientId: "Your Machine Identity Client ID.",
|
||||
clientSecret: "Your Machine Identity Client Secret."
|
||||
clientSecret: "Your Machine Identity Client Secret.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -247,7 +250,8 @@ export const LDAP_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the machine identity to login.",
|
||||
username: "The username of the LDAP user to login.",
|
||||
password: "The password of the LDAP user to login."
|
||||
password: "The password of the LDAP user to login.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
templateId: "The ID of the identity auth template to attach the configuration onto.",
|
||||
@@ -312,7 +316,8 @@ export const ALICLOUD_AUTH = {
|
||||
Timestamp: "The timestamp of the request in UTC, formatted as 'YYYY-MM-DDTHH:mm:ssZ'.",
|
||||
SignatureVersion: "The signature version. For STS GetCallerIdentity, this should be '1.0'.",
|
||||
SignatureNonce: "A unique random string to prevent replay attacks.",
|
||||
Signature: "The signature string calculated based on the request parameters and AccessKey Secret."
|
||||
Signature: "The signature string calculated based on the request parameters and AccessKey Secret.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -340,7 +345,8 @@ export const ALICLOUD_AUTH = {
|
||||
|
||||
export const TLS_CERT_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the machine identity to login."
|
||||
identityId: "The ID of the machine identity to login.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -378,7 +384,8 @@ export const AWS_AUTH = {
|
||||
"The base64-encoded HTTP URL used in the signed request. Most likely, the base64-encoding of https://sts.amazonaws.com/.",
|
||||
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."
|
||||
iamRequestHeaders: "The base64-encoded headers of the sts:GetCallerIdentity signed request.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -416,7 +423,8 @@ export const OCI_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the machine identity to login.",
|
||||
userOcid: "The OCID of the user attempting login.",
|
||||
headers: "The headers of the signed request."
|
||||
headers: "The headers of the signed request.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -448,7 +456,8 @@ export const OCI_AUTH = {
|
||||
|
||||
export const AZURE_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the machine identity to login."
|
||||
identityId: "The ID of the machine identity to login.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -482,7 +491,8 @@ export const AZURE_AUTH = {
|
||||
|
||||
export const GCP_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the machine identity to login."
|
||||
identityId: "The ID of the machine identity to login.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -520,7 +530,8 @@ export const GCP_AUTH = {
|
||||
|
||||
export const KUBERNETES_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the machine identity to login."
|
||||
identityId: "The ID of the machine identity to login.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -600,7 +611,8 @@ export const TOKEN_AUTH = {
|
||||
},
|
||||
CREATE_TOKEN: {
|
||||
identityId: "The ID of the machine identity to create the token for.",
|
||||
name: "The name of the token to create."
|
||||
name: "The name of the token to create.",
|
||||
subOrganizationName: "The sub organization slug to scope the token to."
|
||||
},
|
||||
UPDATE_TOKEN: {
|
||||
tokenId: "The ID of the token to update metadata for.",
|
||||
@@ -613,7 +625,8 @@ export const TOKEN_AUTH = {
|
||||
|
||||
export const OIDC_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the machine identity to login."
|
||||
identityId: "The ID of the machine identity to login.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
@@ -653,7 +666,8 @@ export const OIDC_AUTH = {
|
||||
|
||||
export const JWT_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the machine identity to login."
|
||||
identityId: "The ID of the machine identity to login.",
|
||||
subOrganizationName: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
|
||||
},
|
||||
ATTACH: {
|
||||
identityId: "The ID of the machine identity to attach the configuration onto.",
|
||||
|
||||
@@ -38,6 +38,7 @@ export const registerIdentityAliCloudAuthRouter = async (server: FastifyZodProvi
|
||||
message: "AccessKeyId must be alphanumeric"
|
||||
})
|
||||
.describe(ALICLOUD_AUTH.LOGIN.AccessKeyId),
|
||||
subOrganizationName: z.string().trim().optional().describe(ALICLOUD_AUTH.LOGIN.subOrganizationName),
|
||||
SignatureMethod: z.enum(["HMAC-SHA1"]).describe(ALICLOUD_AUTH.LOGIN.SignatureMethod),
|
||||
Timestamp: z
|
||||
.string()
|
||||
@@ -74,7 +75,10 @@ export const registerIdentityAliCloudAuthRouter = async (server: FastifyZodProvi
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityAliCloudAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityAliCloudAuth.login(req.body);
|
||||
await server.services.identityAliCloudAuth.login({
|
||||
...req.body,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
|
||||
@@ -28,7 +28,8 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider)
|
||||
identityId: z.string().trim().describe(AWS_AUTH.LOGIN.identityId),
|
||||
iamHttpRequestMethod: z.string().default("POST").describe(AWS_AUTH.LOGIN.iamHttpRequestMethod),
|
||||
iamRequestBody: z.string().describe(AWS_AUTH.LOGIN.iamRequestBody),
|
||||
iamRequestHeaders: z.string().describe(AWS_AUTH.LOGIN.iamRequestHeaders)
|
||||
iamRequestHeaders: z.string().describe(AWS_AUTH.LOGIN.iamRequestHeaders),
|
||||
subOrganizationName: z.string().trim().optional().describe(AWS_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -41,7 +42,10 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider)
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityAwsAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityAwsAuth.login(req.body);
|
||||
await server.services.identityAwsAuth.login({
|
||||
...req.body,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
|
||||
@@ -23,7 +23,8 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider
|
||||
description: "Login with Azure Auth for machine identity",
|
||||
body: z.object({
|
||||
identityId: z.string().trim().describe(AZURE_AUTH.LOGIN.identityId),
|
||||
jwt: z.string()
|
||||
jwt: z.string(),
|
||||
subOrganizationName: z.string().trim().optional().describe(AZURE_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
|
||||
@@ -23,7 +23,8 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider)
|
||||
description: "Login with GCP Auth for machine identity",
|
||||
body: z.object({
|
||||
identityId: z.string().trim().describe(GCP_AUTH.LOGIN.identityId),
|
||||
jwt: z.string()
|
||||
jwt: z.string(),
|
||||
subOrganizationName: z.string().trim().optional().describe(GCP_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -36,7 +37,10 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider)
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityGcpAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityGcpAuth.login(req.body);
|
||||
await server.services.identityGcpAuth.login({
|
||||
...req.body,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
|
||||
@@ -99,7 +99,8 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider)
|
||||
description: "Login with JWT Auth for machine identity",
|
||||
body: z.object({
|
||||
identityId: z.string().trim().describe(JWT_AUTH.LOGIN.identityId),
|
||||
jwt: z.string().trim()
|
||||
jwt: z.string().trim(),
|
||||
subOrganizationName: z.string().trim().optional().describe(JWT_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -114,7 +115,8 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider)
|
||||
const { identityJwtAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityJwtAuth.login({
|
||||
identityId: req.body.identityId,
|
||||
jwt: req.body.jwt
|
||||
jwt: req.body.jwt,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
|
||||
@@ -44,7 +44,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
|
||||
description: "Login with Kubernetes Auth for machine identity",
|
||||
body: z.object({
|
||||
identityId: z.string().trim().describe(KUBERNETES_AUTH.LOGIN.identityId),
|
||||
jwt: z.string().trim()
|
||||
jwt: z.string().trim(),
|
||||
subOrganizationName: z.string().trim().optional().describe(KUBERNETES_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -59,7 +60,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
|
||||
const { identityKubernetesAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityKubernetesAuth.login({
|
||||
identityId: req.body.identityId,
|
||||
jwt: req.body.jwt
|
||||
jwt: req.body.jwt,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
|
||||
@@ -124,7 +124,8 @@ export const registerIdentityLdapAuthRouter = async (server: FastifyZodProvider)
|
||||
body: z.object({
|
||||
identityId: z.string().trim().describe(LDAP_AUTH.LOGIN.identityId),
|
||||
username: z.string().describe(LDAP_AUTH.LOGIN.username),
|
||||
password: z.string().describe(LDAP_AUTH.LOGIN.password)
|
||||
password: z.string().describe(LDAP_AUTH.LOGIN.password),
|
||||
subOrganizationName: z.string().trim().optional().describe(LDAP_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -163,7 +164,8 @@ export const registerIdentityLdapAuthRouter = async (server: FastifyZodProvider)
|
||||
const { identityId, user } = req.passportMachineIdentity;
|
||||
|
||||
const { accessToken, identityLdapAuth, identity } = await server.services.identityLdapAuth.login({
|
||||
identityId
|
||||
identityId,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
|
||||
@@ -40,7 +40,8 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
|
||||
});
|
||||
}
|
||||
})
|
||||
.describe(OCI_AUTH.LOGIN.headers)
|
||||
.describe(OCI_AUTH.LOGIN.headers),
|
||||
subOrganizationName: z.string().trim().optional().describe(OCI_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -53,7 +54,10 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityOciAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityOciAuth.login(req.body);
|
||||
await server.services.identityOciAuth.login({
|
||||
...req.body,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
|
||||
@@ -47,7 +47,8 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider)
|
||||
description: "Login with OIDC Auth for machine identity",
|
||||
body: z.object({
|
||||
identityId: z.string().trim().describe(OIDC_AUTH.LOGIN.identityId),
|
||||
jwt: z.string().trim()
|
||||
jwt: z.string().trim(),
|
||||
subOrganizationName: z.string().trim().optional().describe(OIDC_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -62,7 +63,8 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider)
|
||||
const { identityOidcAuth, accessToken, identityAccessToken, identity, oidcTokenData } =
|
||||
await server.services.identityOidcAuth.login({
|
||||
identityId: req.body.identityId,
|
||||
jwt: req.body.jwt
|
||||
jwt: req.body.jwt,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
|
||||
@@ -46,7 +46,8 @@ export const registerIdentityTlsCertAuthRouter = async (server: FastifyZodProvid
|
||||
tags: [ApiDocsTags.TlsCertAuth],
|
||||
description: "Login with TLS Certificate Auth for machine identity",
|
||||
body: z.object({
|
||||
identityId: z.string().trim().describe(TLS_CERT_AUTH.LOGIN.identityId)
|
||||
identityId: z.string().trim().describe(TLS_CERT_AUTH.LOGIN.identityId),
|
||||
subOrganizationName: z.string().trim().optional().describe(TLS_CERT_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -67,7 +68,8 @@ export const registerIdentityTlsCertAuthRouter = async (server: FastifyZodProvid
|
||||
const { identityTlsCertAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityTlsCertAuth.login({
|
||||
identityId: req.body.identityId,
|
||||
clientCertificate: clientCertificate as string
|
||||
clientCertificate: clientCertificate as string,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
|
||||
@@ -307,7 +307,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
|
||||
identityId: z.string().describe(TOKEN_AUTH.CREATE_TOKEN.identityId)
|
||||
}),
|
||||
body: z.object({
|
||||
name: z.string().optional().describe(TOKEN_AUTH.CREATE_TOKEN.name)
|
||||
name: z.string().optional().describe(TOKEN_AUTH.CREATE_TOKEN.name),
|
||||
subOrganizationName: z.string().trim().optional().describe(TOKEN_AUTH.CREATE_TOKEN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -328,7 +329,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
|
||||
actorOrgId: req.permission.orgId,
|
||||
identityId: req.params.identityId,
|
||||
isActorSuperAdmin: isSuperAdmin(req.auth),
|
||||
...req.body
|
||||
...req.body,
|
||||
subOrganizationName: req.body.subOrganizationName
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
|
||||
@@ -35,7 +35,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
description: "Login with Universal Auth for machine identity",
|
||||
body: z.object({
|
||||
clientId: z.string().trim().describe(UNIVERSAL_AUTH.LOGIN.clientId),
|
||||
clientSecret: z.string().trim().describe(UNIVERSAL_AUTH.LOGIN.clientSecret)
|
||||
clientSecret: z.string().trim().describe(UNIVERSAL_AUTH.LOGIN.clientSecret),
|
||||
subOrganizationName: z.string().trim().optional().describe(UNIVERSAL_AUTH.LOGIN.subOrganizationName)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -55,7 +56,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
identity,
|
||||
accessTokenTTL,
|
||||
accessTokenMaxTTL
|
||||
} = await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp);
|
||||
} = await server.services.identityUa.login(
|
||||
req.body.clientId,
|
||||
req.body.clientSecret,
|
||||
req.realIp,
|
||||
req.body.subOrganizationName
|
||||
);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
|
||||
@@ -7,7 +7,6 @@ export type TIdentityAccessTokenJwtPayload = {
|
||||
clientSecretId: string;
|
||||
identityAccessTokenId: string;
|
||||
authTokenType: string;
|
||||
subOrganizationId?: string;
|
||||
identityAuth: {
|
||||
oidc?: {
|
||||
claims: Record<string, string>;
|
||||
|
||||
@@ -53,7 +53,7 @@ type TIdentityAliCloudAuthServiceFactoryDep = {
|
||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityAliCloudAuthServiceFactory = ReturnType<typeof identityAliCloudAuthServiceFactory>;
|
||||
@@ -67,7 +67,7 @@ export const identityAliCloudAuthServiceFactory = ({
|
||||
permissionService,
|
||||
orgDAL
|
||||
}: TIdentityAliCloudAuthServiceFactoryDep) => {
|
||||
const login = async ({ identityId, ...params }: TLoginAliCloudAuthDTO) => {
|
||||
const login = async ({ identityId, subOrganizationName, ...params }: TLoginAliCloudAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityAliCloudAuth = await identityAliCloudAuthDAL.findOne({ identityId });
|
||||
if (!identityAliCloudAuth) {
|
||||
@@ -80,6 +80,30 @@ export const identityAliCloudAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const requestUrl = new URL("https://sts.aliyuncs.com");
|
||||
@@ -132,7 +156,8 @@ export const identityAliCloudAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityAliCloudAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityAliCloudAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.ALICLOUD_AUTH
|
||||
authMethod: IdentityAuthMethod.ALICLOUD_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ export type TLoginAliCloudAuthDTO = {
|
||||
SignatureVersion: string;
|
||||
SignatureNonce: string;
|
||||
Signature: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TAttachAliCloudAuthDTO = {
|
||||
|
||||
@@ -53,7 +53,7 @@ type TIdentityAwsAuthServiceFactoryDep = {
|
||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityAwsAuthServiceFactory = ReturnType<typeof identityAwsAuthServiceFactory>;
|
||||
@@ -101,7 +101,13 @@ export const identityAwsAuthServiceFactory = ({
|
||||
permissionService,
|
||||
orgDAL
|
||||
}: TIdentityAwsAuthServiceFactoryDep) => {
|
||||
const login = async ({ identityId, iamHttpRequestMethod, iamRequestBody, iamRequestHeaders }: TLoginAwsAuthDTO) => {
|
||||
const login = async ({
|
||||
identityId,
|
||||
iamHttpRequestMethod,
|
||||
iamRequestBody,
|
||||
iamRequestHeaders,
|
||||
subOrganizationName
|
||||
}: TLoginAwsAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityAwsAuth = await identityAwsAuthDAL.findOne({ identityId });
|
||||
if (!identityAwsAuth) {
|
||||
@@ -112,6 +118,32 @@ export const identityAwsAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const headers: TAwsGetCallerIdentityHeaders = JSON.parse(Buffer.from(iamRequestHeaders, "base64").toString());
|
||||
const body: string = Buffer.from(iamRequestBody, "base64").toString();
|
||||
@@ -207,7 +239,8 @@ export const identityAwsAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityAwsAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.AWS_AUTH
|
||||
authMethod: IdentityAuthMethod.AWS_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -5,6 +5,7 @@ export type TLoginAwsAuthDTO = {
|
||||
iamHttpRequestMethod: string;
|
||||
iamRequestBody: string;
|
||||
iamRequestHeaders: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TAttachAwsAuthDTO = {
|
||||
|
||||
@@ -49,7 +49,7 @@ type TIdentityAzureAuthServiceFactoryDep = {
|
||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityAzureAuthServiceFactory = ReturnType<typeof identityAzureAuthServiceFactory>;
|
||||
@@ -63,7 +63,7 @@ export const identityAzureAuthServiceFactory = ({
|
||||
licenseService,
|
||||
orgDAL
|
||||
}: TIdentityAzureAuthServiceFactoryDep) => {
|
||||
const login = async ({ identityId, jwt: azureJwt }: TLoginAzureAuthDTO) => {
|
||||
const login = async ({ identityId, jwt: azureJwt, subOrganizationName }: TLoginAzureAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityAzureAuth = await identityAzureAuthDAL.findOne({ identityId });
|
||||
if (!identityAzureAuth) {
|
||||
@@ -75,6 +75,32 @@ export const identityAzureAuthServiceFactory = ({
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const azureIdentity = await validateAzureIdentity({
|
||||
tenantId: identityAzureAuth.tenantId,
|
||||
@@ -126,7 +152,8 @@ export const identityAzureAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityAzureAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityAzureAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.AZURE_AUTH
|
||||
authMethod: IdentityAuthMethod.AZURE_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { TProjectPermission } from "@app/lib/types";
|
||||
export type TLoginAzureAuthDTO = {
|
||||
identityId: string;
|
||||
jwt: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TAttachAzureAuthDTO = {
|
||||
|
||||
@@ -47,7 +47,7 @@ type TIdentityGcpAuthServiceFactoryDep = {
|
||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityGcpAuthServiceFactory = ReturnType<typeof identityGcpAuthServiceFactory>;
|
||||
@@ -61,7 +61,7 @@ export const identityGcpAuthServiceFactory = ({
|
||||
licenseService,
|
||||
orgDAL
|
||||
}: TIdentityGcpAuthServiceFactoryDep) => {
|
||||
const login = async ({ identityId, jwt: gcpJwt }: TLoginGcpAuthDTO) => {
|
||||
const login = async ({ identityId, jwt: gcpJwt, subOrganizationName }: TLoginGcpAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityGcpAuth = await identityGcpAuthDAL.findOne({ identityId });
|
||||
if (!identityGcpAuth) {
|
||||
@@ -72,6 +72,31 @@ export const identityGcpAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let gcpIdentityDetails: TGcpIdentityDetails;
|
||||
switch (identityGcpAuth.type) {
|
||||
@@ -166,7 +191,8 @@ export const identityGcpAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityGcpAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityGcpAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.GCP_AUTH
|
||||
authMethod: IdentityAuthMethod.GCP_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { TProjectPermission } from "@app/lib/types";
|
||||
export type TLoginGcpAuthDTO = {
|
||||
identityId: string;
|
||||
jwt: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TAttachGcpAuthDTO = {
|
||||
|
||||
@@ -60,7 +60,7 @@ type TIdentityJwtAuthServiceFactoryDep = {
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityJwtAuthServiceFactory = ReturnType<typeof identityJwtAuthServiceFactory>;
|
||||
@@ -75,7 +75,7 @@ export const identityJwtAuthServiceFactory = ({
|
||||
kmsService,
|
||||
orgDAL
|
||||
}: TIdentityJwtAuthServiceFactoryDep) => {
|
||||
const login = async ({ identityId, jwt: jwtValue }: TLoginJwtAuthDTO) => {
|
||||
const login = async ({ identityId, jwt: jwtValue, subOrganizationName }: TLoginJwtAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityJwtAuth = await identityJwtAuthDAL.findOne({ identityId });
|
||||
if (!identityJwtAuth) {
|
||||
@@ -86,6 +86,30 @@ export const identityJwtAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
const { decryptor: orgDataKeyDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.Organization,
|
||||
@@ -246,7 +270,8 @@ export const identityJwtAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityJwtAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityJwtAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.JWT_AUTH
|
||||
authMethod: IdentityAuthMethod.JWT_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -49,4 +49,5 @@ export type TRevokeJwtAuthDTO = {
|
||||
export type TLoginJwtAuthDTO = {
|
||||
identityId: string;
|
||||
jwt: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
@@ -78,7 +78,7 @@ type TIdentityKubernetesAuthServiceFactoryDep = {
|
||||
gatewayV2Service: TGatewayV2ServiceFactory;
|
||||
gatewayDAL: Pick<TGatewayDALFactory, "find">;
|
||||
gatewayV2DAL: Pick<TGatewayV2DALFactory, "find">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityKubernetesAuthServiceFactory = ReturnType<typeof identityKubernetesAuthServiceFactory>;
|
||||
@@ -185,7 +185,7 @@ export const identityKubernetesAuthServiceFactory = ({
|
||||
return callbackResult;
|
||||
};
|
||||
|
||||
const login = async ({ identityId, jwt: serviceAccountJwt }: TLoginKubernetesAuthDTO) => {
|
||||
const login = async ({ identityId, jwt: serviceAccountJwt, subOrganizationName }: TLoginKubernetesAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityKubernetesAuth = await identityKubernetesAuthDAL.findOne({ identityId });
|
||||
if (!identityKubernetesAuth) {
|
||||
@@ -198,6 +198,30 @@ export const identityKubernetesAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
@@ -487,7 +511,8 @@ export const identityKubernetesAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityKubernetesAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityKubernetesAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.KUBERNETES_AUTH
|
||||
authMethod: IdentityAuthMethod.KUBERNETES_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { TProjectPermission } from "@app/lib/types";
|
||||
export type TLoginKubernetesAuthDTO = {
|
||||
identityId: string;
|
||||
jwt: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export enum IdentityKubernetesAuthTokenReviewMode {
|
||||
|
||||
@@ -70,7 +70,7 @@ type TIdentityLdapAuthServiceFactoryDep = {
|
||||
TKeyStoreFactory,
|
||||
"setItemWithExpiry" | "getItem" | "deleteItem" | "getKeysByPattern" | "deleteItems" | "acquireLock"
|
||||
>;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityLdapAuthServiceFactory = ReturnType<typeof identityLdapAuthServiceFactory>;
|
||||
@@ -153,7 +153,7 @@ export const identityLdapAuthServiceFactory = ({
|
||||
return { opts, ldapConfig };
|
||||
};
|
||||
|
||||
const login = async ({ identityId }: TLoginLdapAuthDTO) => {
|
||||
const login = async ({ identityId, subOrganizationName }: TLoginLdapAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityLdapAuth = await identityLdapAuthDAL.findOne({ identityId });
|
||||
|
||||
@@ -167,6 +167,30 @@ export const identityLdapAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const plan = await licenseService.getPlan(identity.orgId);
|
||||
if (!plan.ldap) {
|
||||
throw new BadRequestError({
|
||||
@@ -204,7 +228,8 @@ export const identityLdapAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityLdapAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityLdapAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.LDAP_AUTH
|
||||
authMethod: IdentityAuthMethod.LDAP_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -59,6 +59,7 @@ export type TGetLdapAuthDTO = {
|
||||
|
||||
export type TLoginLdapAuthDTO = {
|
||||
identityId: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TRevokeLdapAuthDTO = {
|
||||
|
||||
@@ -51,7 +51,7 @@ type TIdentityOciAuthServiceFactoryDep = {
|
||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityOciAuthServiceFactory = ReturnType<typeof identityOciAuthServiceFactory>;
|
||||
@@ -65,7 +65,7 @@ export const identityOciAuthServiceFactory = ({
|
||||
permissionService,
|
||||
orgDAL
|
||||
}: TIdentityOciAuthServiceFactoryDep) => {
|
||||
const login = async ({ identityId, headers, userOcid }: TLoginOciAuthDTO) => {
|
||||
const login = async ({ identityId, headers, userOcid, subOrganizationName }: TLoginOciAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityOciAuth = await identityOciAuthDAL.findOne({ identityId });
|
||||
if (!identityOciAuth) {
|
||||
@@ -76,6 +76,30 @@ export const identityOciAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
// Validate OCI host format. Ensures that the host is in "identity.<region>.oraclecloud.com" format.
|
||||
if (!headers.host || !new RE2("^identity\\.([a-z]{2}-[a-z]+-[1-9])\\.oraclecloud\\.com$").test(headers.host)) {
|
||||
@@ -137,7 +161,8 @@ export const identityOciAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityOciAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityOciAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.OCI_AUTH
|
||||
authMethod: IdentityAuthMethod.OCI_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -9,6 +9,7 @@ export type TLoginOciAuthDTO = {
|
||||
"x-date"?: string;
|
||||
date?: string;
|
||||
};
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TAttachOciAuthDTO = {
|
||||
|
||||
@@ -61,7 +61,7 @@ type TIdentityOidcAuthServiceFactoryDep = {
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityOidcAuthServiceFactory = ReturnType<typeof identityOidcAuthServiceFactory>;
|
||||
@@ -76,7 +76,7 @@ export const identityOidcAuthServiceFactory = ({
|
||||
kmsService,
|
||||
orgDAL
|
||||
}: TIdentityOidcAuthServiceFactoryDep) => {
|
||||
const login = async ({ identityId, jwt: oidcJwt }: TLoginOidcAuthDTO) => {
|
||||
const login = async ({ identityId, jwt: oidcJwt, subOrganizationName }: TLoginOidcAuthDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityOidcAuth = await identityOidcAuthDAL.findOne({ identityId });
|
||||
if (!identityOidcAuth) {
|
||||
@@ -87,6 +87,30 @@ export const identityOidcAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.Organization,
|
||||
@@ -299,7 +323,8 @@ export const identityOidcAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityOidcAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityOidcAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.OIDC_AUTH
|
||||
authMethod: IdentityAuthMethod.OIDC_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -38,6 +38,7 @@ export type TGetOidcAuthDTO = {
|
||||
export type TLoginOidcAuthDTO = {
|
||||
identityId: string;
|
||||
jwt: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TRevokeOidcAuthDTO = {
|
||||
|
||||
@@ -46,7 +46,7 @@ type TIdentityTlsCertAuthServiceFactoryDep = {
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
const parseSubjectDetails = (data: string) => {
|
||||
@@ -68,7 +68,11 @@ export const identityTlsCertAuthServiceFactory = ({
|
||||
kmsService,
|
||||
orgDAL
|
||||
}: TIdentityTlsCertAuthServiceFactoryDep): TIdentityTlsCertAuthServiceFactory => {
|
||||
const login: TIdentityTlsCertAuthServiceFactory["login"] = async ({ identityId, clientCertificate }) => {
|
||||
const login: TIdentityTlsCertAuthServiceFactory["login"] = async ({
|
||||
identityId,
|
||||
clientCertificate,
|
||||
subOrganizationName
|
||||
}) => {
|
||||
const appCfg = getConfig();
|
||||
const identityTlsCertAuth = await identityTlsCertAuthDAL.findOne({ identityId });
|
||||
if (!identityTlsCertAuth) {
|
||||
@@ -81,6 +85,30 @@ export const identityTlsCertAuthServiceFactory = ({
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
@@ -157,7 +185,8 @@ export const identityTlsCertAuthServiceFactory = ({
|
||||
accessTokenMaxTTL: identityTlsCertAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityTlsCertAuth.accessTokenNumUsesLimit,
|
||||
authMethod: IdentityAuthMethod.TLS_CERT_AUTH
|
||||
authMethod: IdentityAuthMethod.TLS_CERT_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { TProjectPermission } from "@app/lib/types";
|
||||
export type TLoginTlsCertAuthDTO = {
|
||||
identityId: string;
|
||||
clientCertificate: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TAttachTlsCertAuthDTO = {
|
||||
|
||||
@@ -59,7 +59,7 @@ type TIdentityTokenAuthServiceFactoryDep = {
|
||||
>;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
};
|
||||
|
||||
export type TIdentityTokenAuthServiceFactory = ReturnType<typeof identityTokenAuthServiceFactory>;
|
||||
@@ -424,7 +424,8 @@ export const identityTokenAuthServiceFactory = ({
|
||||
actorAuthMethod,
|
||||
actorOrgId,
|
||||
name,
|
||||
isActorSuperAdmin
|
||||
isActorSuperAdmin,
|
||||
subOrganizationName
|
||||
}: TCreateTokenAuthTokenDTO) => {
|
||||
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
|
||||
|
||||
@@ -503,6 +504,32 @@ export const identityTokenAuthServiceFactory = ({
|
||||
const identity = await identityDAL.findById(identityTokenAuth.identityId);
|
||||
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const identityAccessToken = await identityTokenAuthDAL.transaction(async (tx) => {
|
||||
await membershipIdentityDAL.update(
|
||||
identity.projectId
|
||||
@@ -529,7 +556,8 @@ export const identityTokenAuthServiceFactory = ({
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityTokenAuth.accessTokenNumUsesLimit,
|
||||
name,
|
||||
authMethod: IdentityAuthMethod.TOKEN_AUTH
|
||||
authMethod: IdentityAuthMethod.TOKEN_AUTH,
|
||||
scopeOrgId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -30,6 +30,7 @@ export type TRevokeTokenAuthDTO = {
|
||||
export type TCreateTokenAuthTokenDTO = {
|
||||
identityId: string;
|
||||
name?: string;
|
||||
subOrganizationName?: string;
|
||||
isActorSuperAdmin?: boolean;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
TGetUaClientSecretsDTO,
|
||||
TGetUaDTO,
|
||||
TGetUniversalAuthClientSecretByIdDTO,
|
||||
TLoginUaDTO,
|
||||
TRevokeUaClientSecretDTO,
|
||||
TRevokeUaDTO,
|
||||
TUpdateUaDTO
|
||||
@@ -54,7 +55,7 @@ type TIdentityUaServiceFactoryDep = {
|
||||
membershipIdentityDAL: TMembershipIdentityDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getProjectPermission">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||
orgDAL: Pick<TOrgDALFactory, "findById" | "findOne">;
|
||||
keyStore: Pick<
|
||||
TKeyStoreFactory,
|
||||
"setItemWithExpiry" | "getItem" | "deleteItem" | "getKeysByPattern" | "deleteItems" | "acquireLock"
|
||||
@@ -79,7 +80,7 @@ export const identityUaServiceFactory = ({
|
||||
keyStore,
|
||||
identityDAL
|
||||
}: TIdentityUaServiceFactoryDep) => {
|
||||
const login = async (clientId: string, clientSecret: string, ip: string) => {
|
||||
const login = async ({ clientId, clientSecret, ip, subOrganizationName }: TLoginUaDTO) => {
|
||||
const appCfg = getConfig();
|
||||
const identityUa = await identityUaDAL.findOne({ clientId });
|
||||
if (!identityUa) {
|
||||
@@ -90,6 +91,30 @@ export const identityUaServiceFactory = ({
|
||||
|
||||
const identity = await identityDAL.findById(identityUa.identityId);
|
||||
const org = await orgDAL.findById(identity.orgId);
|
||||
const isSubOrg = !!(org.rootOrgId || org.parentOrgId);
|
||||
|
||||
const rootOrgId = isSubOrg ? org.rootOrgId || org.id : org.id;
|
||||
|
||||
// Resolve sub-organization if specified
|
||||
let scopeOrgId = rootOrgId;
|
||||
if (subOrganizationName) {
|
||||
const subOrg = await orgDAL.findOne({ slug: subOrganizationName });
|
||||
|
||||
if (subOrg) {
|
||||
if (!isSubOrg || (isSubOrg && subOrg.rootOrgId === rootOrgId)) {
|
||||
// Verify identity has membership in the sub-organization
|
||||
const subOrgMembership = await membershipIdentityDAL.findOne({
|
||||
scope: AccessScope.Organization,
|
||||
actorIdentityId: identity.id,
|
||||
scopeOrgId: subOrg.id
|
||||
});
|
||||
|
||||
if (subOrgMembership) {
|
||||
scopeOrgId = subOrg.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
checkIPAgainstBlocklist({
|
||||
@@ -259,6 +284,7 @@ export const identityUaServiceFactory = ({
|
||||
accessTokenNumUsesLimit: identityUa.accessTokenNumUsesLimit,
|
||||
accessTokenPeriod: identityUa.accessTokenPeriod,
|
||||
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH,
|
||||
scopeOrgId,
|
||||
...accessTokenTTLParams
|
||||
},
|
||||
tx
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { TProjectPermission } from "@app/lib/types";
|
||||
|
||||
export type TLoginUaDTO = {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
ip: string;
|
||||
subOrganizationName?: string;
|
||||
};
|
||||
|
||||
export type TAttachUaDTO = {
|
||||
identityId: string;
|
||||
accessTokenTTL: number;
|
||||
|
||||
@@ -640,7 +640,8 @@ export const superAdminServiceFactory = ({
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: tokenAuth.accessTokenNumUsesLimit,
|
||||
name: "Instance Admin Token",
|
||||
authMethod: IdentityAuthMethod.TOKEN_AUTH
|
||||
authMethod: IdentityAuthMethod.TOKEN_AUTH,
|
||||
scopeOrgId: organization.id
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user