Merge pull request #3259 from Infisical/feat/automated-instance-bootstrapping

feat: automated bootstrapping
This commit is contained in:
Sheen
2025-03-19 21:40:55 +08:00
committed by GitHub
49 changed files with 1199 additions and 114 deletions
@@ -0,0 +1,19 @@
import { Knex } from "knex";
import { TableName } from "../schemas/models";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasColumn(TableName.SuperAdmin, "adminIdentityIds"))) {
await knex.schema.alterTable(TableName.SuperAdmin, (t) => {
t.specificType("adminIdentityIds", "text[]");
});
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasColumn(TableName.SuperAdmin, "adminIdentityIds")) {
await knex.schema.alterTable(TableName.SuperAdmin, (t) => {
t.dropColumn("adminIdentityIds");
});
}
}
+2 -1
View File
@@ -25,7 +25,8 @@ export const SuperAdminSchema = z.object({
encryptedSlackClientId: zodBuffer.nullable().optional(),
encryptedSlackClientSecret: zodBuffer.nullable().optional(),
authConsentContent: z.string().nullable().optional(),
pageFrameContent: z.string().nullable().optional()
pageFrameContent: z.string().nullable().optional(),
adminIdentityIds: z.string().array().nullable().optional()
});
export type TSuperAdmin = z.infer<typeof SuperAdminSchema>;
@@ -9,6 +9,7 @@ import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
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";
export type TAuthMode =
| {
@@ -44,6 +45,7 @@ export type TAuthMode =
identityName: string;
orgId: string;
authMethod: null;
isInstanceAdmin?: boolean;
}
| {
authMode: AuthMode.SCIM_TOKEN;
@@ -130,13 +132,15 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
}
case AuthMode.IDENTITY_ACCESS_TOKEN: {
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(token, req.realIp);
const serverCfg = await getServerCfg();
req.auth = {
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
actor,
orgId: identity.orgId,
identityId: identity.identityId,
identityName: identity.name,
authMethod: null
authMethod: null,
isInstanceAdmin: serverCfg?.adminIdentityIds?.includes(identity.identityId)
};
if (token?.identityAuth?.oidc) {
requestContext.set("identityAuthInfo", {
@@ -1,16 +1,18 @@
import { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from "fastify";
import { ForbiddenRequestError } from "@app/lib/errors";
import { ActorType } from "@app/services/auth/auth-type";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
export const verifySuperAdmin = <T extends FastifyRequest>(
req: T,
_res: FastifyReply,
done: HookHandlerDoneFunction
) => {
if (req.auth.actor !== ActorType.USER || !req.auth.user.superAdmin)
throw new ForbiddenRequestError({
message: "Requires elevated super admin privileges"
});
done();
if (isSuperAdmin(req.auth)) {
return done();
}
throw new ForbiddenRequestError({
message: "Requires elevated super admin privileges"
});
};
+3
View File
@@ -637,6 +637,9 @@ export const registerRoutes = async (
userDAL,
identityDAL,
userAliasDAL,
identityTokenAuthDAL,
identityAccessTokenDAL,
identityOrgMembershipDAL,
authService: loginService,
serverCfgDAL: superAdminDAL,
kmsRootConfigDAL,
+150 -9
View File
@@ -98,7 +98,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT, AuthMode.API_KEY])(req, res, () => {
verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
@@ -139,7 +139,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT])(req, res, () => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
@@ -171,12 +171,16 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
identities: IdentitiesSchema.pick({
name: true,
id: true
}).array()
})
.extend({
isInstanceAdmin: z.boolean()
})
.array()
})
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT])(req, res, () => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
@@ -206,7 +210,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT])(req, res, () => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
@@ -240,7 +244,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT])(req, res, () => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
@@ -265,7 +269,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
})
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT])(req, res, () => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
@@ -293,7 +297,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT])(req, res, () => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
@@ -316,7 +320,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
})
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT])(req, res, () => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
@@ -394,4 +398,141 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
};
}
});
server.route({
method: "DELETE",
url: "/identity-management/identities/:identityId/super-admin-access",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
identityId: z.string()
}),
response: {
200: z.object({
identity: IdentitiesSchema.pick({
name: true,
id: true
})
})
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
handler: async (req) => {
const identity = await server.services.superAdmin.deleteIdentitySuperAdminAccess(
req.params.identityId,
req.permission.id
);
return {
identity
};
}
});
server.route({
method: "DELETE",
url: "/user-management/users/:userId/admin-access",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
userId: z.string()
}),
response: {
200: z.object({
user: UsersSchema.pick({
username: true,
firstName: true,
lastName: true,
email: true,
id: true
})
})
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
handler: async (req) => {
const user = await server.services.superAdmin.deleteUserSuperAdminAccess(req.params.userId);
return {
user
};
}
});
server.route({
method: "POST",
url: "/bootstrap",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
email: z.string().email().trim().min(1),
password: z.string().trim().min(1),
organization: z.string().trim().min(1)
}),
response: {
200: z.object({
message: z.string(),
user: UsersSchema.pick({
username: true,
firstName: true,
lastName: true,
email: true,
id: true,
superAdmin: true
}),
organization: OrganizationsSchema.pick({
id: true,
name: true,
slug: true
}),
identity: IdentitiesSchema.pick({
id: true,
name: true
}).extend({
credentials: z.object({
token: z.string()
}) // would just be Token AUTH for now
})
})
}
},
handler: async (req) => {
const { user, organization, machineIdentity } = await server.services.superAdmin.bootstrapInstance({
...req.body,
organizationName: req.body.organization
});
await server.services.telemetry.sendPostHogEvents({
event: PostHogEventTypes.AdminInit,
distinctId: user.user.username ?? "",
properties: {
username: user.user.username,
email: user.user.email ?? "",
lastName: user.user.lastName || "",
firstName: user.user.firstName || ""
}
});
return {
message: "Successfully bootstrapped instance",
user: user.user,
organization,
identity: machineIdentity
};
}
});
};
@@ -11,6 +11,7 @@ import {
validateAccountIds,
validatePrincipalArns
} from "@app/services/identity-aws-auth/identity-aws-auth-validators";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) => {
server.route({
@@ -130,7 +131,8 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider)
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -8,8 +8,7 @@ import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
import { validateAzureAuthField } from "@app/services/identity-azure-auth/identity-azure-auth-validators";
import {} from "../sanitizedSchemas";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider) => {
server.route({
@@ -127,7 +126,8 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -8,6 +8,7 @@ import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
import { validateGcpAuthField } from "@app/services/identity-gcp-auth/identity-gcp-auth-validators";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider) => {
server.route({
@@ -121,7 +122,8 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider)
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -12,6 +12,7 @@ import {
validateJwtAuthAudiencesField,
validateJwtBoundClaimsField
} from "@app/services/identity-jwt-auth/identity-jwt-auth-validators";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
const IdentityJwtAuthResponseSchema = IdentityJwtAuthsSchema.omit({
encryptedJwksCaCert: true,
@@ -169,7 +170,8 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider)
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -7,6 +7,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
const IdentityKubernetesAuthResponseSchema = IdentityKubernetesAuthsSchema.pick({
id: true,
@@ -147,7 +148,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -11,6 +11,7 @@ import {
validateOidcAuthAudiencesField,
validateOidcBoundClaimsField
} from "@app/services/identity-oidc-auth/identity-oidc-auth-validators";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
const IdentityOidcAuthResponseSchema = IdentityOidcAuthsSchema.pick({
id: true,
@@ -148,7 +149,8 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider)
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -7,6 +7,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
import { SanitizedProjectSchema } from "../sanitizedSchemas";
@@ -118,6 +119,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth),
...req.body
});
@@ -166,7 +168,8 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.identityId
id: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -7,6 +7,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider) => {
server.route({
@@ -74,7 +75,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -157,7 +159,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -257,7 +260,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
@@ -312,6 +316,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth),
...req.body
});
@@ -370,6 +375,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth),
...req.query
});
@@ -421,6 +427,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
tokenId: req.params.tokenId,
isActorSuperAdmin: isSuperAdmin(req.auth),
...req.body
});
@@ -470,7 +477,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
tokenId: req.params.tokenId
tokenId: req.params.tokenId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
return {
@@ -7,6 +7,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
export const sanitizedClientSecretSchema = IdentityUaClientSecretsSchema.pick({
id: true,
@@ -142,8 +143,10 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
isActorSuperAdmin: isSuperAdmin(req.auth)
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: identityUniversalAuth.orgId,
@@ -16,6 +16,7 @@ import { ActorType, AuthTokenType } from "../auth/auth-type";
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityAwsAuthDALFactory } from "./identity-aws-auth-dal";
import { extractPrincipalArn } from "./identity-aws-auth-fns";
import {
@@ -149,8 +150,11 @@ export const identityAwsAuthServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TAttachAwsAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -16,6 +16,7 @@ export type TAttachAwsAuthDTO = {
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateAwsAuthDTO = {
@@ -14,6 +14,7 @@ import { ActorType, AuthTokenType } from "../auth/auth-type";
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityAzureAuthDALFactory } from "./identity-azure-auth-dal";
import { validateAzureIdentity } from "./identity-azure-auth-fns";
import {
@@ -122,8 +123,11 @@ export const identityAzureAuthServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TAttachAzureAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -14,6 +14,7 @@ export type TAttachAzureAuthDTO = {
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateAzureAuthDTO = {
@@ -14,6 +14,7 @@ import { ActorType, AuthTokenType } from "../auth/auth-type";
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityGcpAuthDALFactory } from "./identity-gcp-auth-dal";
import { validateIamIdentity, validateIdTokenIdentity } from "./identity-gcp-auth-fns";
import {
@@ -162,8 +163,11 @@ export const identityGcpAuthServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TAttachGcpAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -15,6 +15,7 @@ export type TAttachGcpAuthDTO = {
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateGcpAuthDTO = {
@@ -19,6 +19,7 @@ import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identit
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { TKmsServiceFactory } from "../kms/kms-service";
import { KmsDataKey } from "../kms/kms-types";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityJwtAuthDALFactory } from "./identity-jwt-auth-dal";
import { doesFieldValueMatchJwtPolicy } from "./identity-jwt-auth-fns";
import {
@@ -250,8 +251,11 @@ export const identityJwtAuthServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TAttachJwtAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) {
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -19,6 +19,7 @@ export type TAttachJwtAuthDTO = {
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateJwtAuthDTO = {
@@ -18,6 +18,7 @@ import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identit
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { TKmsServiceFactory } from "../kms/kms-service";
import { KmsDataKey } from "../kms/kms-types";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityKubernetesAuthDALFactory } from "./identity-kubernetes-auth-dal";
import { extractK8sUsername } from "./identity-kubernetes-auth-fns";
import {
@@ -227,8 +228,11 @@ export const identityKubernetesAuthServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TAttachKubernetesAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -17,6 +17,7 @@ export type TAttachKubernetesAuthDTO = {
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateKubernetesAuthDTO = {
@@ -20,6 +20,7 @@ import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identit
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { TKmsServiceFactory } from "../kms/kms-service";
import { KmsDataKey } from "../kms/kms-types";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityOidcAuthDALFactory } from "./identity-oidc-auth-dal";
import { doesAudValueMatchOidcPolicy, doesFieldValueMatchOidcPolicy } from "./identity-oidc-auth-fns";
import {
@@ -222,8 +223,10 @@ export const identityOidcAuthServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TAttachOidcAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) {
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -13,6 +13,7 @@ export type TAttachOidcAuthDTO = {
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateOidcAuthDTO = {
@@ -14,6 +14,7 @@ import { ActorType, AuthTokenType } from "../auth/auth-type";
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityTokenAuthDALFactory } from "./identity-token-auth-dal";
import {
TAttachTokenAuthDTO,
@@ -59,8 +60,11 @@ export const identityTokenAuthServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TAttachTokenAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -126,8 +130,11 @@ export const identityTokenAuthServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TUpdateTokenAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -218,8 +225,11 @@ export const identityTokenAuthServiceFactory = ({
actorId,
actor,
actorAuthMethod,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TRevokeTokenAuthDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -271,8 +281,11 @@ export const identityTokenAuthServiceFactory = ({
actor,
actorAuthMethod,
actorOrgId,
name
name,
isActorSuperAdmin
}: TCreateTokenAuthTokenDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -350,8 +363,11 @@ export const identityTokenAuthServiceFactory = ({
actorId,
actor,
actorAuthMethod,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TGetTokenAuthTokensDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -386,7 +402,8 @@ export const identityTokenAuthServiceFactory = ({
actorId,
actor,
actorAuthMethod,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TUpdateTokenAuthTokenDTO) => {
const foundToken = await identityAccessTokenDAL.findOne({
[`${TableName.IdentityAccessToken}.id` as "id"]: tokenId,
@@ -398,6 +415,8 @@ export const identityTokenAuthServiceFactory = ({
if (!identityMembershipOrg) {
throw new NotFoundError({ message: `Failed to find identity with ID ${foundToken.identityId}` });
}
await validateIdentityUpdateForSuperAdminPrivileges(foundToken.identityId, isActorSuperAdmin);
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
throw new BadRequestError({
message: "The identity does not have Token Auth"
@@ -446,18 +465,22 @@ export const identityTokenAuthServiceFactory = ({
actorId,
actor,
actorAuthMethod,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TRevokeTokenAuthTokenDTO) => {
const identityAccessToken = await identityAccessTokenDAL.findOne({
[`${TableName.IdentityAccessToken}.id` as "id"]: tokenId,
[`${TableName.IdentityAccessToken}.isAccessTokenRevoked` as "isAccessTokenRevoked"]: false,
[`${TableName.IdentityAccessToken}.authMethod` as "authMethod"]: IdentityAuthMethod.TOKEN_AUTH
});
if (!identityAccessToken)
throw new NotFoundError({
message: `Token with ID ${tokenId} not found or already revoked`
});
await validateIdentityUpdateForSuperAdminPrivileges(identityAccessToken.identityId, isActorSuperAdmin);
const identityOrgMembership = await identityOrgMembershipDAL.findOne({
identityId: identityAccessToken.identityId
});
@@ -6,6 +6,7 @@ export type TAttachTokenAuthDTO = {
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateTokenAuthDTO = {
@@ -14,6 +15,7 @@ export type TUpdateTokenAuthDTO = {
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;
accessTokenTrustedIps?: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TGetTokenAuthDTO = {
@@ -22,24 +24,29 @@ export type TGetTokenAuthDTO = {
export type TRevokeTokenAuthDTO = {
identityId: string;
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TCreateTokenAuthTokenDTO = {
identityId: string;
name?: string;
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TGetTokenAuthTokensDTO = {
identityId: string;
offset: number;
limit: number;
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateTokenAuthTokenDTO = {
tokenId: string;
name?: string;
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TRevokeTokenAuthTokenDTO = {
tokenId: string;
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
@@ -17,6 +17,7 @@ import { ActorType, AuthTokenType } from "../auth/auth-type";
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityUaClientSecretDALFactory } from "./identity-ua-client-secret-dal";
import { TIdentityUaDALFactory } from "./identity-ua-dal";
import {
@@ -150,8 +151,11 @@ export const identityUaServiceFactory = ({
actorId,
actorAuthMethod,
actor,
actorOrgId
actorOrgId,
isActorSuperAdmin
}: TAttachUaDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
@@ -7,6 +7,7 @@ export type TAttachUaDTO = {
accessTokenNumUsesLimit: number;
clientSecretTrustedIps: { ipAddress: string }[];
accessTokenTrustedIps: { ipAddress: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">;
export type TUpdateUaDTO = {
@@ -9,6 +9,7 @@ import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/
import { TIdentityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
import { ActorType } from "../auth/auth-type";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityDALFactory } from "./identity-dal";
import { TIdentityMetadataDALFactory } from "./identity-metadata-dal";
import { TIdentityOrgDALFactory } from "./identity-org-dal";
@@ -112,8 +113,11 @@ export const identityServiceFactory = ({
actorId,
actorAuthMethod,
actorOrgId,
metadata
metadata,
isActorSuperAdmin
}: TUpdateIdentityDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(id, isActorSuperAdmin);
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${id}` });
@@ -209,7 +213,16 @@ export const identityServiceFactory = ({
return identity;
};
const deleteIdentity = async ({ actorId, actor, actorOrgId, actorAuthMethod, id }: TDeleteIdentityDTO) => {
const deleteIdentity = async ({
actorId,
actor,
actorOrgId,
actorAuthMethod,
id,
isActorSuperAdmin
}: TDeleteIdentityDTO) => {
await validateIdentityUpdateForSuperAdminPrivileges(id, isActorSuperAdmin);
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${id}` });
@@ -12,10 +12,12 @@ export type TUpdateIdentityDTO = {
role?: string;
name?: string;
metadata?: { key: string; value: string }[];
isActorSuperAdmin?: boolean;
} & Omit<TOrgPermission, "orgId">;
export type TDeleteIdentityDTO = {
id: string;
isActorSuperAdmin?: boolean;
} & Omit<TOrgPermission, "orgId">;
export type TGetIdentityByIdDTO = {
@@ -0,0 +1,30 @@
import { ForbiddenRequestError } from "@app/lib/errors";
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
import { ActorType } from "../auth/auth-type";
import { getServerCfg } from "./super-admin-service";
export const isSuperAdmin = (auth: TAuthMode) => {
if (auth.actor === ActorType.USER && auth.user.superAdmin) {
return true;
}
if (auth.actor === ActorType.IDENTITY && auth.isInstanceAdmin) {
return true;
}
return false;
};
export const validateIdentityUpdateForSuperAdminPrivileges = async (
identityId: string,
isActorSuperAdmin?: boolean
) => {
const serverCfg = await getServerCfg();
if (serverCfg.adminIdentityIds?.includes(identityId) && !isActorSuperAdmin) {
throw new ForbiddenRequestError({
message:
"You are attempting to modify an instance admin identity. This requires elevated instance admin privileges"
});
}
};
@@ -1,16 +1,21 @@
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { TSuperAdmin, TSuperAdminUpdate } from "@app/db/schemas";
import { IdentityAuthMethod, OrgMembershipRole, TSuperAdmin, TSuperAdminUpdate } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
import { getConfig } from "@app/lib/config/env";
import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { getUserPrivateKey } from "@app/lib/crypto/srp";
import { generateUserSrpKeys, getUserPrivateKey } from "@app/lib/crypto/srp";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { TIdentityDALFactory } from "@app/services/identity/identity-dal";
import { TAuthLoginFactory } from "../auth/auth-login-service";
import { AuthMethod } from "../auth/auth-type";
import { AuthMethod, AuthTokenType } from "../auth/auth-type";
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
import { TIdentityTokenAuthDALFactory } from "../identity-token-auth/identity-token-auth-dal";
import { KMS_ROOT_CONFIG_UUID } from "../kms/kms-fns";
import { TKmsRootConfigDALFactory } from "../kms/kms-root-config-dal";
import { TKmsServiceFactory } from "../kms/kms-service";
@@ -20,10 +25,19 @@ import { TUserDALFactory } from "../user/user-dal";
import { TUserAliasDALFactory } from "../user-alias/user-alias-dal";
import { UserAliasType } from "../user-alias/user-alias-types";
import { TSuperAdminDALFactory } from "./super-admin-dal";
import { LoginMethod, TAdminGetIdentitiesDTO, TAdminGetUsersDTO, TAdminSignUpDTO } from "./super-admin-types";
import {
LoginMethod,
TAdminBootstrapInstanceDTO,
TAdminGetIdentitiesDTO,
TAdminGetUsersDTO,
TAdminSignUpDTO
} from "./super-admin-types";
type TSuperAdminServiceFactoryDep = {
identityDAL: Pick<TIdentityDALFactory, "getIdentitiesByFilter">;
identityDAL: TIdentityDALFactory;
identityTokenAuthDAL: TIdentityTokenAuthDALFactory;
identityAccessTokenDAL: TIdentityAccessTokenDALFactory;
identityOrgMembershipDAL: TIdentityOrgDALFactory;
serverCfgDAL: TSuperAdminDALFactory;
userDAL: TUserDALFactory;
userAliasDAL: Pick<TUserAliasDALFactory, "findOne">;
@@ -60,7 +74,10 @@ export const superAdminServiceFactory = ({
keyStore,
kmsRootConfigDAL,
kmsService,
licenseService
licenseService,
identityAccessTokenDAL,
identityTokenAuthDAL,
identityOrgMembershipDAL
}: TSuperAdminServiceFactoryDep) => {
const initServerCfg = async () => {
// TODO(akhilmhdh): bad pattern time less change this later to me itself
@@ -274,6 +291,137 @@ export const superAdminServiceFactory = ({
return { token, user: userInfo, organization };
};
const bootstrapInstance = async ({ email, password, organizationName }: TAdminBootstrapInstanceDTO) => {
const appCfg = getConfig();
const serverCfg = await serverCfgDAL.findById(ADMIN_CONFIG_DB_UUID);
if (serverCfg?.initialized) {
throw new BadRequestError({ message: "Instance has already been set up" });
}
const existingUser = await userDAL.findOne({ email });
if (existingUser) throw new BadRequestError({ name: "Instance initialization", message: "User already exists" });
const userInfo = await userDAL.transaction(async (tx) => {
const newUser = await userDAL.create(
{
firstName: "Admin",
lastName: "User",
username: email,
email,
superAdmin: true,
isGhost: false,
isAccepted: true,
authMethods: [AuthMethod.EMAIL],
isEmailVerified: true
},
tx
);
const { tag, encoding, ciphertext, iv } = infisicalSymmetricEncypt(password);
const encKeys = await generateUserSrpKeys(email, password);
const userEnc = await userDAL.createUserEncryption(
{
userId: newUser.id,
encryptionVersion: 2,
protectedKey: encKeys.protectedKey,
protectedKeyIV: encKeys.protectedKeyIV,
protectedKeyTag: encKeys.protectedKeyTag,
publicKey: encKeys.publicKey,
encryptedPrivateKey: encKeys.encryptedPrivateKey,
iv: encKeys.encryptedPrivateKeyIV,
tag: encKeys.encryptedPrivateKeyTag,
salt: encKeys.salt,
verifier: encKeys.verifier,
serverEncryptedPrivateKeyEncoding: encoding,
serverEncryptedPrivateKeyTag: tag,
serverEncryptedPrivateKeyIV: iv,
serverEncryptedPrivateKey: ciphertext
},
tx
);
return { user: newUser, enc: userEnc };
});
const initialOrganizationName = organizationName ?? "Admin Org";
const organization = await orgService.createOrganization({
userId: userInfo.user.id,
userEmail: userInfo.user.email,
orgName: initialOrganizationName
});
const { identity, credentials } = await identityDAL.transaction(async (tx) => {
const newIdentity = await identityDAL.create({ name: "Instance Admin Identity" }, tx);
await identityOrgMembershipDAL.create(
{
identityId: newIdentity.id,
orgId: organization.id,
role: OrgMembershipRole.Admin
},
tx
);
const tokenAuth = await identityTokenAuthDAL.create(
{
identityId: newIdentity.id,
accessTokenMaxTTL: 0,
accessTokenTTL: 0,
accessTokenNumUsesLimit: 0,
accessTokenTrustedIps: JSON.stringify([
{
type: "ipv4",
prefix: 0,
ipAddress: "0.0.0.0"
},
{
type: "ipv6",
prefix: 0,
ipAddress: "::"
}
])
},
tx
);
const newToken = await identityAccessTokenDAL.create(
{
identityId: newIdentity.id,
isAccessTokenRevoked: false,
accessTokenTTL: tokenAuth.accessTokenTTL,
accessTokenMaxTTL: tokenAuth.accessTokenMaxTTL,
accessTokenNumUses: 0,
accessTokenNumUsesLimit: tokenAuth.accessTokenNumUsesLimit,
name: "Instance Admin Token",
authMethod: IdentityAuthMethod.TOKEN_AUTH
},
tx
);
const generatedAccessToken = jwt.sign(
{
identityId: newIdentity.id,
identityAccessTokenId: newToken.id,
authTokenType: AuthTokenType.IDENTITY_ACCESS_TOKEN
} as TIdentityAccessTokenJwtPayload,
appCfg.AUTH_SECRET
);
return { identity: newIdentity, auth: tokenAuth, credentials: { token: generatedAccessToken } };
});
await updateServerCfg({ initialized: true, adminIdentityIds: [identity.id] }, userInfo.user.id);
return {
user: userInfo,
organization,
machineIdentity: {
...identity,
credentials
}
};
};
const getUsers = ({ offset, limit, searchTerm, adminsOnly }: TAdminGetUsersDTO) => {
return userDAL.getUsersByFilter({
limit,
@@ -289,13 +437,46 @@ export const superAdminServiceFactory = ({
return user;
};
const getIdentities = ({ offset, limit, searchTerm }: TAdminGetIdentitiesDTO) => {
return identityDAL.getIdentitiesByFilter({
const deleteIdentitySuperAdminAccess = async (identityId: string, actorId: string) => {
const identity = await identityDAL.findById(identityId);
if (!identity) {
throw new NotFoundError({ name: "Identity", message: "Identity not found" });
}
const currentAdminIdentityIds = (await getServerCfg()).adminIdentityIds ?? [];
if (!currentAdminIdentityIds?.includes(identityId)) {
throw new BadRequestError({ name: "Identity", message: "Identity does not have super admin access" });
}
await updateServerCfg({ adminIdentityIds: currentAdminIdentityIds.filter((id) => id !== identityId) }, actorId);
return identity;
};
const deleteUserSuperAdminAccess = async (userId: string) => {
const user = await userDAL.findById(userId);
if (!user) {
throw new NotFoundError({ name: "User", message: "User not found" });
}
const updatedUser = userDAL.updateById(userId, { superAdmin: false });
return updatedUser;
};
const getIdentities = async ({ offset, limit, searchTerm }: TAdminGetIdentitiesDTO) => {
const identities = await identityDAL.getIdentitiesByFilter({
limit,
offset,
searchTerm,
sortBy: "name"
});
const serverCfg = await getServerCfg();
return identities.map((identity) => ({
...identity,
isInstanceAdmin: Boolean(serverCfg?.adminIdentityIds?.includes(identity.id))
}));
};
const grantServerAdminAccessToUser = async (userId: string) => {
@@ -393,12 +574,15 @@ export const superAdminServiceFactory = ({
initServerCfg,
updateServerCfg,
adminSignUp,
bootstrapInstance,
getUsers,
deleteUser,
getIdentities,
getAdminSlackConfig,
updateRootEncryptionStrategy,
getConfiguredEncryptionStrategies,
grantServerAdminAccessToUser
grantServerAdminAccessToUser,
deleteIdentitySuperAdminAccess,
deleteUserSuperAdminAccess
};
};
@@ -16,6 +16,12 @@ export type TAdminSignUpDTO = {
userAgent: string;
};
export type TAdminBootstrapInstanceDTO = {
email: string;
password: string;
organizationName: string;
};
export type TAdminGetUsersDTO = {
offset: number;
limit: number;