mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-17 20:21:18 +00:00
Merge pull request #4701 from Infisical/feat/sub-org
feat: sub organization
This commit is contained in:
@@ -8,6 +8,7 @@ import { TScimTokenJwtPayload } from "@app/ee/services/scim/scim-types";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { crypto } from "@app/lib/crypto";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { slugSchema } from "@app/server/lib/schemas";
|
||||
import { ActorType, AuthMethod, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
|
||||
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
||||
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
||||
@@ -20,6 +21,8 @@ export type TAuthMode =
|
||||
tokenVersionId: string; // the session id of token used
|
||||
user: TUsers;
|
||||
orgId: string;
|
||||
rootOrgId: string;
|
||||
parentOrgId: string;
|
||||
authMethod: AuthMethod;
|
||||
isMfaVerified?: boolean;
|
||||
token: AuthModeJwtTokenPayload;
|
||||
@@ -31,6 +34,8 @@ export type TAuthMode =
|
||||
userId: string;
|
||||
user: TUsers;
|
||||
orgId: string;
|
||||
rootOrgId: string;
|
||||
parentOrgId: string;
|
||||
token: string;
|
||||
}
|
||||
| {
|
||||
@@ -39,6 +44,8 @@ export type TAuthMode =
|
||||
actor: ActorType.SERVICE;
|
||||
serviceTokenId: string;
|
||||
orgId: string;
|
||||
rootOrgId: string;
|
||||
parentOrgId: string;
|
||||
authMethod: null;
|
||||
token: string;
|
||||
}
|
||||
@@ -48,6 +55,8 @@ export type TAuthMode =
|
||||
identityId: string;
|
||||
identityName: string;
|
||||
orgId: string;
|
||||
rootOrgId: string;
|
||||
parentOrgId: string;
|
||||
authMethod: null;
|
||||
isInstanceAdmin?: boolean;
|
||||
token: TIdentityAccessTokenJwtPayload;
|
||||
@@ -57,6 +66,8 @@ export type TAuthMode =
|
||||
actor: ActorType.SCIM_CLIENT;
|
||||
scimTokenId: string;
|
||||
orgId: string;
|
||||
rootOrgId: string;
|
||||
parentOrgId: string;
|
||||
authMethod: null;
|
||||
};
|
||||
|
||||
@@ -136,17 +147,26 @@ export const injectIdentity = fp(
|
||||
|
||||
if (!authMode) return;
|
||||
|
||||
const subOrganizationSelector = req.headers?.["x-infisical-org"] as string | undefined;
|
||||
if (subOrganizationSelector) {
|
||||
await slugSchema().parseAsync(subOrganizationSelector);
|
||||
}
|
||||
|
||||
switch (authMode) {
|
||||
case AuthMode.JWT: {
|
||||
const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(token);
|
||||
const { user, tokenVersionId, orgId, rootOrgId, parentOrgId } =
|
||||
await server.services.authToken.fnValidateJwtIdentity(token, subOrganizationSelector);
|
||||
requestContext.set("orgId", orgId);
|
||||
|
||||
req.auth = {
|
||||
authMode: AuthMode.JWT,
|
||||
user,
|
||||
userId: user.id,
|
||||
tokenVersionId,
|
||||
actor,
|
||||
orgId: orgId as string,
|
||||
orgId,
|
||||
rootOrgId,
|
||||
parentOrgId,
|
||||
authMethod: token.authMethod,
|
||||
isMfaVerified: token.isMfaVerified,
|
||||
token
|
||||
@@ -154,13 +174,19 @@ export const injectIdentity = fp(
|
||||
break;
|
||||
}
|
||||
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
||||
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(token, req.realIp);
|
||||
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(
|
||||
token,
|
||||
subOrganizationSelector,
|
||||
req.realIp
|
||||
);
|
||||
const serverCfg = await getServerCfg();
|
||||
requestContext.set("orgId", identity.orgId);
|
||||
req.auth = {
|
||||
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||
actor,
|
||||
orgId: identity.orgId,
|
||||
rootOrgId: identity.rootOrgId,
|
||||
parentOrgId: identity.parentOrgId,
|
||||
identityId: identity.identityId,
|
||||
identityName: identity.name,
|
||||
authMethod: null,
|
||||
@@ -190,8 +216,14 @@ export const injectIdentity = fp(
|
||||
case AuthMode.SERVICE_TOKEN: {
|
||||
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token);
|
||||
requestContext.set("orgId", serviceToken.orgId);
|
||||
|
||||
if (subOrganizationSelector)
|
||||
throw new BadRequestError({ message: `Service token doesn't support sub organization selector` });
|
||||
|
||||
req.auth = {
|
||||
orgId: serviceToken.orgId,
|
||||
rootOrgId: serviceToken.rootOrgId,
|
||||
parentOrgId: serviceToken.parentOrgId,
|
||||
authMode: AuthMode.SERVICE_TOKEN as const,
|
||||
serviceToken,
|
||||
serviceTokenId: serviceToken.id,
|
||||
@@ -202,22 +234,27 @@ export const injectIdentity = fp(
|
||||
break;
|
||||
}
|
||||
case AuthMode.API_KEY: {
|
||||
const user = await server.services.apiKey.fnValidateApiKey(token as string);
|
||||
req.auth = {
|
||||
authMode: AuthMode.API_KEY as const,
|
||||
userId: user.id,
|
||||
actor,
|
||||
user,
|
||||
orgId: "API_KEY", // We set the orgId to an arbitrary value, since we can't link an API key to a specific org. We have to deprecate API keys soon!
|
||||
authMethod: null,
|
||||
token: token as string
|
||||
};
|
||||
break;
|
||||
throw new BadRequestError({
|
||||
message: "API key authentication is not supported anymore. Please switch to identity authentication."
|
||||
});
|
||||
}
|
||||
case AuthMode.SCIM_TOKEN: {
|
||||
const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token);
|
||||
requestContext.set("orgId", orgId);
|
||||
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId, authMethod: null };
|
||||
|
||||
if (subOrganizationSelector)
|
||||
throw new BadRequestError({ message: `SCIM token doesn't support sub organization selector` });
|
||||
|
||||
req.auth = {
|
||||
authMode: AuthMode.SCIM_TOKEN,
|
||||
actor,
|
||||
scimTokenId,
|
||||
orgId,
|
||||
authMethod: null,
|
||||
// scim cannot be done for sub organization
|
||||
rootOrgId: orgId,
|
||||
parentOrgId: orgId
|
||||
};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -14,7 +14,9 @@ export const injectPermission = fp(async (server) => {
|
||||
type: ActorType.USER,
|
||||
id: req.auth.userId,
|
||||
orgId: req.auth.orgId, // if the req.auth.authMode is AuthMode.API_KEY, the orgId will be "API_KEY"
|
||||
authMethod: req.auth.authMethod // if the req.auth.authMode is AuthMode.API_KEY, the authMethod will be null
|
||||
authMethod: req.auth.authMethod, // if the req.auth.authMode is AuthMode.API_KEY, the authMethod will be null
|
||||
rootOrgId: req.auth.rootOrgId,
|
||||
parentOrgId: req.auth.parentOrgId
|
||||
};
|
||||
|
||||
logger.info(
|
||||
@@ -25,7 +27,9 @@ export const injectPermission = fp(async (server) => {
|
||||
type: ActorType.IDENTITY,
|
||||
id: req.auth.identityId,
|
||||
orgId: req.auth.orgId,
|
||||
authMethod: null
|
||||
authMethod: null,
|
||||
rootOrgId: req.auth.rootOrgId,
|
||||
parentOrgId: req.auth.parentOrgId
|
||||
};
|
||||
|
||||
logger.info(
|
||||
@@ -36,6 +40,8 @@ export const injectPermission = fp(async (server) => {
|
||||
type: ActorType.SERVICE,
|
||||
id: req.auth.serviceTokenId,
|
||||
orgId: req.auth.orgId,
|
||||
rootOrgId: req.auth.rootOrgId,
|
||||
parentOrgId: req.auth.parentOrgId,
|
||||
authMethod: null
|
||||
};
|
||||
|
||||
@@ -47,6 +53,8 @@ export const injectPermission = fp(async (server) => {
|
||||
type: ActorType.SCIM_CLIENT,
|
||||
id: req.auth.scimTokenId,
|
||||
orgId: req.auth.orgId,
|
||||
rootOrgId: req.auth.rootOrgId,
|
||||
parentOrgId: req.auth.parentOrgId,
|
||||
authMethod: null
|
||||
};
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ import { sshHostLoginUserDALFactory } from "@app/ee/services/ssh-host/ssh-login-
|
||||
import { sshHostGroupDALFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-dal";
|
||||
import { sshHostGroupMembershipDALFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-membership-dal";
|
||||
import { sshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
||||
import { subOrgServiceFactory } from "@app/ee/services/sub-org/sub-org-service";
|
||||
import { trustedIpDALFactory } from "@app/ee/services/trusted-ip/trusted-ip-dal";
|
||||
import { trustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
||||
import { keyValueStoreDALFactory } from "@app/keystore/key-value-store-dal";
|
||||
@@ -568,11 +569,10 @@ export const registerRoutes = async (
|
||||
orgDAL,
|
||||
licenseDAL,
|
||||
keyStore,
|
||||
identityOrgMembershipDAL,
|
||||
projectDAL
|
||||
});
|
||||
|
||||
const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL, membershipUserDAL });
|
||||
const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL, membershipUserDAL, orgDAL });
|
||||
|
||||
const membershipUserService = membershipUserServiceFactory({
|
||||
licenseService,
|
||||
@@ -592,6 +592,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const membershipIdentityService = membershipIdentityServiceFactory({
|
||||
identityDAL,
|
||||
membershipIdentityDAL,
|
||||
membershipRoleDAL,
|
||||
orgDAL,
|
||||
@@ -912,6 +913,15 @@ export const registerRoutes = async (
|
||||
userGroupMembershipDAL,
|
||||
additionalPrivilegeDAL
|
||||
});
|
||||
|
||||
const subOrgService = subOrgServiceFactory({
|
||||
licenseService,
|
||||
membershipDAL,
|
||||
membershipRoleDAL,
|
||||
orgDAL,
|
||||
permissionService
|
||||
});
|
||||
|
||||
const signupService = authSignupServiceFactory({
|
||||
tokenService,
|
||||
smtpService,
|
||||
@@ -1594,10 +1604,12 @@ export const registerRoutes = async (
|
||||
permissionService,
|
||||
projectDAL,
|
||||
accessTokenQueue,
|
||||
smtpService
|
||||
smtpService,
|
||||
orgDAL
|
||||
});
|
||||
|
||||
const identityService = identityServiceFactory({
|
||||
additionalPrivilegeDAL,
|
||||
permissionService,
|
||||
identityDAL,
|
||||
identityOrgMembershipDAL,
|
||||
@@ -1628,10 +1640,12 @@ export const registerRoutes = async (
|
||||
identityAccessTokenDAL,
|
||||
accessTokenQueue,
|
||||
identityDAL,
|
||||
membershipIdentityDAL
|
||||
membershipIdentityDAL,
|
||||
orgDAL
|
||||
});
|
||||
|
||||
const identityTokenAuthService = identityTokenAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityTokenAuthDAL,
|
||||
identityAccessTokenDAL,
|
||||
permissionService,
|
||||
@@ -1641,6 +1655,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityUaService = identityUaServiceFactory({
|
||||
identityDAL,
|
||||
permissionService,
|
||||
identityAccessTokenDAL,
|
||||
identityUaClientSecretDAL,
|
||||
@@ -1652,6 +1667,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityKubernetesAuthService = identityKubernetesAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityKubernetesAuthDAL,
|
||||
identityAccessTokenDAL,
|
||||
permissionService,
|
||||
@@ -1665,6 +1681,7 @@ export const registerRoutes = async (
|
||||
membershipIdentityDAL
|
||||
});
|
||||
const identityGcpAuthService = identityGcpAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityGcpAuthDAL,
|
||||
orgDAL,
|
||||
identityAccessTokenDAL,
|
||||
@@ -1674,6 +1691,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityAliCloudAuthService = identityAliCloudAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityAccessTokenDAL,
|
||||
orgDAL,
|
||||
identityAliCloudAuthDAL,
|
||||
@@ -1683,6 +1701,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityTlsCertAuthService = identityTlsCertAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityAccessTokenDAL,
|
||||
identityTlsCertAuthDAL,
|
||||
licenseService,
|
||||
@@ -1692,6 +1711,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityAwsAuthService = identityAwsAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityAccessTokenDAL,
|
||||
orgDAL,
|
||||
identityAwsAuthDAL,
|
||||
@@ -1701,6 +1721,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityAzureAuthService = identityAzureAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityAzureAuthDAL,
|
||||
orgDAL,
|
||||
identityAccessTokenDAL,
|
||||
@@ -1710,6 +1731,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityOciAuthService = identityOciAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityAccessTokenDAL,
|
||||
orgDAL,
|
||||
identityOciAuthDAL,
|
||||
@@ -1733,6 +1755,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityOidcAuthService = identityOidcAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityOidcAuthDAL,
|
||||
orgDAL,
|
||||
identityAccessTokenDAL,
|
||||
@@ -1743,6 +1766,7 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
const identityJwtAuthService = identityJwtAuthServiceFactory({
|
||||
identityDAL,
|
||||
identityJwtAuthDAL,
|
||||
orgDAL,
|
||||
permissionService,
|
||||
@@ -2296,6 +2320,7 @@ export const registerRoutes = async (
|
||||
groupProject: groupProjectService,
|
||||
permission: permissionService,
|
||||
org: orgService,
|
||||
subOrganization: subOrgService,
|
||||
oidc: oidcService,
|
||||
apiKey: apiKeyService,
|
||||
authToken: tokenService,
|
||||
|
||||
@@ -94,6 +94,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
||||
decodedToken.userId,
|
||||
decodedToken.organizationId,
|
||||
decodedToken.authMethod,
|
||||
decodedToken.organizationId,
|
||||
decodedToken.organizationId
|
||||
);
|
||||
if (org && org.userTokenExpiration) {
|
||||
|
||||
@@ -73,12 +73,12 @@ export const registerIdentityAliCloudAuthRouter = async (server: FastifyZodProvi
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityAliCloudAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityAliCloudAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityAliCloudAuth.login(req.body);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_ALICLOUD_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -40,12 +40,12 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider)
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityAwsAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityAwsAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityAwsAuth.login(req.body);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_AWS_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -35,12 +35,12 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityAzureAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityAzureAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityAzureAuth.login(req.body);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_AZURE_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -35,12 +35,12 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider)
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityGcpAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityGcpAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityGcpAuth.login(req.body);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_GCP_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -111,7 +111,7 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider)
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityJwtAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityJwtAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityJwtAuth.login({
|
||||
identityId: req.body.identityId,
|
||||
jwt: req.body.jwt
|
||||
@@ -119,7 +119,7 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider)
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_JWT_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -56,7 +56,7 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityKubernetesAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityKubernetesAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityKubernetesAuth.login({
|
||||
identityId: req.body.identityId,
|
||||
jwt: req.body.jwt
|
||||
@@ -64,7 +64,7 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_KUBERNETES_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -162,13 +162,13 @@ export const registerIdentityLdapAuthRouter = async (server: FastifyZodProvider)
|
||||
|
||||
const { identityId, user } = req.passportMachineIdentity;
|
||||
|
||||
const { accessToken, identityLdapAuth, identityMembershipOrg } = await server.services.identityLdapAuth.login({
|
||||
const { accessToken, identityLdapAuth, identity } = await server.services.identityLdapAuth.login({
|
||||
identityId
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_LDAP_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -52,12 +52,12 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityOciAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityOciAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityOciAuth.login(req.body);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_OCI_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -59,7 +59,7 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider)
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityOidcAuth, accessToken, identityAccessToken, identityMembershipOrg, oidcTokenData } =
|
||||
const { identityOidcAuth, accessToken, identityAccessToken, identity, oidcTokenData } =
|
||||
await server.services.identityOidcAuth.login({
|
||||
identityId: req.body.identityId,
|
||||
jwt: req.body.jwt
|
||||
@@ -67,7 +67,7 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider)
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_OIDC_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { AccessScope, TemporaryPermissionMode } from "@app/db/schemas";
|
||||
import { ApiDocsTags, PROJECT_IDENTITIES } from "@app/lib/api-docs";
|
||||
import { ms } from "@app/lib/ms";
|
||||
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
const sanitizedOrgIdentityMembershipSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
orgId: z.string(),
|
||||
identityId: z.string().uuid(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
||||
export const registerOrgIdentityMembershipRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/identity-memberships/:identityId",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
hide: true,
|
||||
// this is hidden so not updating tags
|
||||
tags: [ApiDocsTags.ProjectIdentities],
|
||||
description: "Create org identity membership",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string().trim()
|
||||
}),
|
||||
body: z.object({
|
||||
roles: z
|
||||
.array(
|
||||
z.union([
|
||||
z.object({
|
||||
role: z.string().describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||
isTemporary: z
|
||||
.literal(false)
|
||||
.default(false)
|
||||
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role)
|
||||
}),
|
||||
z.object({
|
||||
role: z.string().describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||
isTemporary: z.literal(true).describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||
temporaryMode: z
|
||||
.nativeEnum(TemporaryPermissionMode)
|
||||
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||
temporaryRange: z
|
||||
.string()
|
||||
.refine((val) => ms(val) > 0, "Temporary range must be a positive number")
|
||||
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||
temporaryAccessStartTime: z
|
||||
.string()
|
||||
.datetime()
|
||||
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role)
|
||||
})
|
||||
])
|
||||
)
|
||||
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.description)
|
||||
.max(1)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
identityMembership: sanitizedOrgIdentityMembershipSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { membership } = await server.services.membershipIdentity.createMembership({
|
||||
permission: req.permission,
|
||||
scopeData: {
|
||||
scope: AccessScope.Organization,
|
||||
orgId: req.permission.orgId
|
||||
},
|
||||
data: {
|
||||
identityId: req.params.identityId,
|
||||
roles: req.body.roles
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
identityMembership: { ...membership, identityId: req.params.identityId, orgId: req.permission.orgId }
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "DELETE",
|
||||
url: "/identity-memberships/:identityId",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
hide: true,
|
||||
tags: [ApiDocsTags.ProjectIdentities],
|
||||
description: "Delete org identity memberships",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
params: z.object({
|
||||
identityId: z.string().trim().describe(PROJECT_IDENTITIES.DELETE_IDENTITY_MEMBERSHIP.identityId)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
identityMembership: sanitizedOrgIdentityMembershipSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { membership } = await server.services.membershipIdentity.deleteMembership({
|
||||
permission: req.permission,
|
||||
scopeData: {
|
||||
scope: AccessScope.Organization,
|
||||
orgId: req.permission.orgId
|
||||
},
|
||||
selector: {
|
||||
identityId: req.params.identityId
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
identityMembership: { ...membership, identityId: req.params.identityId, orgId: req.permission.orgId }
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -249,7 +249,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
permissions: true,
|
||||
description: true
|
||||
}).optional(),
|
||||
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true }).extend({
|
||||
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true, orgId: true }).extend({
|
||||
authMethods: z.array(z.string()),
|
||||
activeLockoutAuthMethods: z.array(z.string())
|
||||
})
|
||||
@@ -393,7 +393,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
permissions: true,
|
||||
description: true
|
||||
}).optional(),
|
||||
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true }).extend({
|
||||
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true, orgId: true }).extend({
|
||||
authMethods: z.array(z.string())
|
||||
})
|
||||
}).array(),
|
||||
|
||||
@@ -64,7 +64,7 @@ export const registerIdentityTlsCertAuthRouter = async (server: FastifyZodProvid
|
||||
throw new BadRequestError({ message: "Missing TLS certificate in header" });
|
||||
}
|
||||
|
||||
const { identityTlsCertAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityTlsCertAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityTlsCertAuth.login({
|
||||
identityId: req.body.identityId,
|
||||
clientCertificate: clientCertificate as string
|
||||
@@ -72,7 +72,7 @@ export const registerIdentityTlsCertAuthRouter = async (server: FastifyZodProvid
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_TLS_CERT_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -319,7 +319,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityTokenAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
const { identityTokenAuth, accessToken, identityAccessToken, identity } =
|
||||
await server.services.identityTokenAuth.createTokenAuthToken({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
@@ -332,7 +332,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.CREATE_TOKEN_IDENTITY_TOKEN_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -52,14 +52,14 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
accessToken,
|
||||
identityAccessToken,
|
||||
validClientSecretInfo,
|
||||
identityMembershipOrg,
|
||||
identity,
|
||||
accessTokenTTL,
|
||||
accessTokenMaxTTL
|
||||
} = await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg.scopeOrgId,
|
||||
orgId: identity.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -33,6 +33,7 @@ import { registerIdentityKubernetesRouter } from "./identity-kubernetes-auth-rou
|
||||
import { registerIdentityLdapAuthRouter } from "./identity-ldap-auth-router";
|
||||
import { registerIdentityOciAuthRouter } from "./identity-oci-auth-router";
|
||||
import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router";
|
||||
import { registerOrgIdentityMembershipRouter } from "./identity-org-membership-router";
|
||||
import { registerIdentityProjectRouter } from "./identity-project-router";
|
||||
import { registerIdentityRouter } from "./identity-router";
|
||||
import { registerIdentityTlsCertAuthRouter } from "./identity-tls-cert-auth-router";
|
||||
@@ -90,6 +91,7 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
|
||||
);
|
||||
await server.register(registerPasswordRouter, { prefix: "/password" });
|
||||
await server.register(registerOrgRouter, { prefix: "/organization" });
|
||||
await server.register(registerOrgIdentityMembershipRouter, { prefix: "/organization" });
|
||||
await server.register(registerAdminRouter, { prefix: "/admin" });
|
||||
await server.register(registerOrgAdminRouter, { prefix: "/organization-admin" });
|
||||
await server.register(registerUserRouter, { prefix: "/user" });
|
||||
|
||||
@@ -2,6 +2,7 @@ import RE2 from "re2";
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
AccessScope,
|
||||
AuditLogsSchema,
|
||||
GroupsSchema,
|
||||
IncidentContactsSchema,
|
||||
@@ -59,7 +60,14 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
organization: sanitizedOrganizationSchema
|
||||
organization: sanitizedOrganizationSchema.extend({
|
||||
subOrganization: z
|
||||
.object({
|
||||
id: z.string(),
|
||||
name: z.string()
|
||||
})
|
||||
.optional()
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -69,6 +77,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
req.permission.id,
|
||||
req.params.organizationId,
|
||||
req.permission.authMethod,
|
||||
req.permission.rootOrgId,
|
||||
req.permission.orgId
|
||||
);
|
||||
return { organization };
|
||||
@@ -467,4 +476,68 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
return { groups };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/users/available",
|
||||
schema: {
|
||||
response: {
|
||||
200: z.object({
|
||||
users: z
|
||||
.object({
|
||||
id: z.string().uuid(),
|
||||
username: z.string(),
|
||||
email: z.string().nullable().optional(),
|
||||
firstName: z.string().nullable().optional(),
|
||||
lastName: z.string().nullable().optional()
|
||||
})
|
||||
.array()
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
handler: async (req) => {
|
||||
const { users } = await server.services.membershipUser.listAvailableUsers({
|
||||
permission: req.permission,
|
||||
scopeData: {
|
||||
orgId: req.permission.orgId,
|
||||
scope: AccessScope.Organization
|
||||
},
|
||||
data: {}
|
||||
});
|
||||
|
||||
return { users };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/identities/available",
|
||||
schema: {
|
||||
response: {
|
||||
200: z.object({
|
||||
identities: z
|
||||
.object({
|
||||
id: z.string().uuid(),
|
||||
name: z.string(),
|
||||
hasDeleteProtection: z.boolean()
|
||||
})
|
||||
.array()
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
handler: async (req) => {
|
||||
const { identities } = await server.services.membershipIdentity.listAvailableIdentities({
|
||||
permission: req.permission,
|
||||
scopeData: {
|
||||
orgId: req.permission.orgId,
|
||||
scope: AccessScope.Organization
|
||||
},
|
||||
data: {}
|
||||
});
|
||||
|
||||
return { identities };
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
|
||||
permissions: true,
|
||||
description: true
|
||||
}).optional(),
|
||||
identity: IdentitiesSchema.pick({ name: true, id: true }).extend({
|
||||
identity: IdentitiesSchema.pick({ name: true, id: true, orgId: true }).extend({
|
||||
authMethods: z.array(z.string())
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user