mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 21:27:31 +00:00
feat: completed backend changes for tls auth
This commit is contained in:
Vendored
+2
@@ -110,6 +110,7 @@ import { TUserServiceFactory } from "@app/services/user/user-service";
|
|||||||
import { TUserEngagementServiceFactory } from "@app/services/user-engagement/user-engagement-service";
|
import { TUserEngagementServiceFactory } from "@app/services/user-engagement/user-engagement-service";
|
||||||
import { TWebhookServiceFactory } from "@app/services/webhook/webhook-service";
|
import { TWebhookServiceFactory } from "@app/services/webhook/webhook-service";
|
||||||
import { TWorkflowIntegrationServiceFactory } from "@app/services/workflow-integration/workflow-integration-service";
|
import { TWorkflowIntegrationServiceFactory } from "@app/services/workflow-integration/workflow-integration-service";
|
||||||
|
import { TIdentityTlsCertAuthServiceFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-types";
|
||||||
|
|
||||||
declare module "@fastify/request-context" {
|
declare module "@fastify/request-context" {
|
||||||
interface RequestContextData {
|
interface RequestContextData {
|
||||||
@@ -218,6 +219,7 @@ declare module "fastify" {
|
|||||||
identityKubernetesAuth: TIdentityKubernetesAuthServiceFactory;
|
identityKubernetesAuth: TIdentityKubernetesAuthServiceFactory;
|
||||||
identityGcpAuth: TIdentityGcpAuthServiceFactory;
|
identityGcpAuth: TIdentityGcpAuthServiceFactory;
|
||||||
identityAliCloudAuth: TIdentityAliCloudAuthServiceFactory;
|
identityAliCloudAuth: TIdentityAliCloudAuthServiceFactory;
|
||||||
|
identityTlsCertAuth: TIdentityTlsCertAuthServiceFactory;
|
||||||
identityAwsAuth: TIdentityAwsAuthServiceFactory;
|
identityAwsAuth: TIdentityAwsAuthServiceFactory;
|
||||||
identityAzureAuth: TIdentityAzureAuthServiceFactory;
|
identityAzureAuth: TIdentityAzureAuthServiceFactory;
|
||||||
identityOciAuth: TIdentityOciAuthServiceFactory;
|
identityOciAuth: TIdentityOciAuthServiceFactory;
|
||||||
|
|||||||
Vendored
+8
@@ -164,6 +164,9 @@ import {
|
|||||||
TIdentityProjectMemberships,
|
TIdentityProjectMemberships,
|
||||||
TIdentityProjectMembershipsInsert,
|
TIdentityProjectMembershipsInsert,
|
||||||
TIdentityProjectMembershipsUpdate,
|
TIdentityProjectMembershipsUpdate,
|
||||||
|
TIdentityTlsCertAuths,
|
||||||
|
TIdentityTlsCertAuthsInsert,
|
||||||
|
TIdentityTlsCertAuthsUpdate,
|
||||||
TIdentityTokenAuths,
|
TIdentityTokenAuths,
|
||||||
TIdentityTokenAuthsInsert,
|
TIdentityTokenAuthsInsert,
|
||||||
TIdentityTokenAuthsUpdate,
|
TIdentityTokenAuthsUpdate,
|
||||||
@@ -794,6 +797,11 @@ declare module "knex/types/tables" {
|
|||||||
TIdentityAlicloudAuthsInsert,
|
TIdentityAlicloudAuthsInsert,
|
||||||
TIdentityAlicloudAuthsUpdate
|
TIdentityAlicloudAuthsUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.IdentityTlsCertAuth]: KnexOriginal.CompositeTableType<
|
||||||
|
TIdentityTlsCertAuths,
|
||||||
|
TIdentityTlsCertAuthsInsert,
|
||||||
|
TIdentityTlsCertAuthsUpdate
|
||||||
|
>;
|
||||||
[TableName.IdentityAwsAuth]: KnexOriginal.CompositeTableType<
|
[TableName.IdentityAwsAuth]: KnexOriginal.CompositeTableType<
|
||||||
TIdentityAwsAuths,
|
TIdentityAwsAuths,
|
||||||
TIdentityAwsAuthsInsert,
|
TIdentityAwsAuthsInsert,
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.IdentityTlsCertAuth))) {
|
||||||
|
await knex.schema.createTable(TableName.IdentityTlsCertAuth, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable();
|
||||||
|
t.bigInteger("accessTokenMaxTTL").defaultTo(7200).notNullable();
|
||||||
|
t.bigInteger("accessTokenNumUsesLimit").defaultTo(0).notNullable();
|
||||||
|
t.jsonb("accessTokenTrustedIps").notNullable();
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
t.uuid("identityId").notNullable().unique();
|
||||||
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
t.string("allowedCommonNames").nullable();
|
||||||
|
t.binary("encryptedCaCertificate").notNullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IdentityTlsCertAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IdentityTlsCertAuth);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IdentityTlsCertAuth);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { zodBuffer } from "@app/lib/zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const IdentityTlsCertAuthsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
accessTokenTTL: z.coerce.number().default(7200),
|
||||||
|
accessTokenMaxTTL: z.coerce.number().default(7200),
|
||||||
|
accessTokenNumUsesLimit: z.coerce.number().default(0),
|
||||||
|
accessTokenTrustedIps: z.unknown(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
identityId: z.string().uuid(),
|
||||||
|
allowedCommonNames: z.string().nullable().optional(),
|
||||||
|
encryptedCaCertificate: zodBuffer
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TIdentityTlsCertAuths = z.infer<typeof IdentityTlsCertAuthsSchema>;
|
||||||
|
export type TIdentityTlsCertAuthsInsert = Omit<z.input<typeof IdentityTlsCertAuthsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TIdentityTlsCertAuthsUpdate = Partial<Omit<z.input<typeof IdentityTlsCertAuthsSchema>, TImmutableDBKeys>>;
|
||||||
@@ -52,6 +52,7 @@ export * from "./identity-org-memberships";
|
|||||||
export * from "./identity-project-additional-privilege";
|
export * from "./identity-project-additional-privilege";
|
||||||
export * from "./identity-project-membership-role";
|
export * from "./identity-project-membership-role";
|
||||||
export * from "./identity-project-memberships";
|
export * from "./identity-project-memberships";
|
||||||
|
export * from "./identity-tls-cert-auths";
|
||||||
export * from "./identity-token-auths";
|
export * from "./identity-token-auths";
|
||||||
export * from "./identity-ua-client-secrets";
|
export * from "./identity-ua-client-secrets";
|
||||||
export * from "./identity-universal-auths";
|
export * from "./identity-universal-auths";
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ export enum TableName {
|
|||||||
IdentityOidcAuth = "identity_oidc_auths",
|
IdentityOidcAuth = "identity_oidc_auths",
|
||||||
IdentityJwtAuth = "identity_jwt_auths",
|
IdentityJwtAuth = "identity_jwt_auths",
|
||||||
IdentityLdapAuth = "identity_ldap_auths",
|
IdentityLdapAuth = "identity_ldap_auths",
|
||||||
|
IdentityTlsCertAuth = "identity_tls_cert_auths",
|
||||||
IdentityOrgMembership = "identity_org_memberships",
|
IdentityOrgMembership = "identity_org_memberships",
|
||||||
IdentityProjectMembership = "identity_project_memberships",
|
IdentityProjectMembership = "identity_project_memberships",
|
||||||
IdentityProjectMembershipRole = "identity_project_membership_role",
|
IdentityProjectMembershipRole = "identity_project_membership_role",
|
||||||
@@ -251,6 +252,7 @@ export enum IdentityAuthMethod {
|
|||||||
ALICLOUD_AUTH = "alicloud-auth",
|
ALICLOUD_AUTH = "alicloud-auth",
|
||||||
AWS_AUTH = "aws-auth",
|
AWS_AUTH = "aws-auth",
|
||||||
AZURE_AUTH = "azure-auth",
|
AZURE_AUTH = "azure-auth",
|
||||||
|
TLS_CERT_AUTH = "tls-cert-auth",
|
||||||
OCI_AUTH = "oci-auth",
|
OCI_AUTH = "oci-auth",
|
||||||
OIDC_AUTH = "oidc-auth",
|
OIDC_AUTH = "oidc-auth",
|
||||||
JWT_AUTH = "jwt-auth",
|
JWT_AUTH = "jwt-auth",
|
||||||
|
|||||||
@@ -202,6 +202,12 @@ export enum EventType {
|
|||||||
REVOKE_IDENTITY_ALICLOUD_AUTH = "revoke-identity-alicloud-auth",
|
REVOKE_IDENTITY_ALICLOUD_AUTH = "revoke-identity-alicloud-auth",
|
||||||
GET_IDENTITY_ALICLOUD_AUTH = "get-identity-alicloud-auth",
|
GET_IDENTITY_ALICLOUD_AUTH = "get-identity-alicloud-auth",
|
||||||
|
|
||||||
|
LOGIN_IDENTITY_TLS_CERT_AUTH = "login-identity-tls-cert-auth",
|
||||||
|
ADD_IDENTITY_TLS_CERT_AUTH = "add-identity-tls-cert-auth",
|
||||||
|
UPDATE_IDENTITY_TLS_CERT_AUTH = "update-identity-tls-cert-auth",
|
||||||
|
REVOKE_IDENTITY_TLS_CERT_AUTH = "revoke-identity-tls-cert-auth",
|
||||||
|
GET_IDENTITY_TLS_CERT_AUTH = "get-identity-tls-cert-auth",
|
||||||
|
|
||||||
LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth",
|
LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth",
|
||||||
ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth",
|
ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth",
|
||||||
UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth",
|
UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth",
|
||||||
@@ -1141,6 +1147,53 @@ interface GetIdentityAliCloudAuthEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LoginIdentityTlsCertAuthEvent {
|
||||||
|
type: EventType.LOGIN_IDENTITY_TLS_CERT_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
identityTlsCertAuthId: string;
|
||||||
|
identityAccessTokenId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddIdentityTlsCertAuthEvent {
|
||||||
|
type: EventType.ADD_IDENTITY_TLS_CERT_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
allowedCommonNames: string | null | undefined;
|
||||||
|
accessTokenTTL: number;
|
||||||
|
accessTokenMaxTTL: number;
|
||||||
|
accessTokenNumUsesLimit: number;
|
||||||
|
accessTokenTrustedIps: Array<TIdentityTrustedIp>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteIdentityTlsCertAuthEvent {
|
||||||
|
type: EventType.REVOKE_IDENTITY_TLS_CERT_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateIdentityTlsCertAuthEvent {
|
||||||
|
type: EventType.UPDATE_IDENTITY_TLS_CERT_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
allowedCommonNames: string | null | undefined;
|
||||||
|
accessTokenTTL?: number;
|
||||||
|
accessTokenMaxTTL?: number;
|
||||||
|
accessTokenNumUsesLimit?: number;
|
||||||
|
accessTokenTrustedIps?: Array<TIdentityTrustedIp>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetIdentityTlsCertAuthEvent {
|
||||||
|
type: EventType.GET_IDENTITY_TLS_CERT_AUTH;
|
||||||
|
metadata: {
|
||||||
|
identityId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface LoginIdentityOciAuthEvent {
|
interface LoginIdentityOciAuthEvent {
|
||||||
type: EventType.LOGIN_IDENTITY_OCI_AUTH;
|
type: EventType.LOGIN_IDENTITY_OCI_AUTH;
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -3358,6 +3411,11 @@ export type Event =
|
|||||||
| UpdateIdentityAliCloudAuthEvent
|
| UpdateIdentityAliCloudAuthEvent
|
||||||
| GetIdentityAliCloudAuthEvent
|
| GetIdentityAliCloudAuthEvent
|
||||||
| DeleteIdentityAliCloudAuthEvent
|
| DeleteIdentityAliCloudAuthEvent
|
||||||
|
| LoginIdentityTlsCertAuthEvent
|
||||||
|
| AddIdentityTlsCertAuthEvent
|
||||||
|
| UpdateIdentityTlsCertAuthEvent
|
||||||
|
| GetIdentityTlsCertAuthEvent
|
||||||
|
| DeleteIdentityTlsCertAuthEvent
|
||||||
| LoginIdentityOciAuthEvent
|
| LoginIdentityOciAuthEvent
|
||||||
| AddIdentityOciAuthEvent
|
| AddIdentityOciAuthEvent
|
||||||
| UpdateIdentityOciAuthEvent
|
| UpdateIdentityOciAuthEvent
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export enum ApiDocsTags {
|
|||||||
UniversalAuth = "Universal Auth",
|
UniversalAuth = "Universal Auth",
|
||||||
GcpAuth = "GCP Auth",
|
GcpAuth = "GCP Auth",
|
||||||
AliCloudAuth = "Alibaba Cloud Auth",
|
AliCloudAuth = "Alibaba Cloud Auth",
|
||||||
|
TlsCertAuth = "TLS Certificate Auth",
|
||||||
AwsAuth = "AWS Auth",
|
AwsAuth = "AWS Auth",
|
||||||
OciAuth = "OCI Auth",
|
OciAuth = "OCI Auth",
|
||||||
AzureAuth = "Azure Auth",
|
AzureAuth = "Azure Auth",
|
||||||
@@ -283,6 +284,38 @@ export const ALICLOUD_AUTH = {
|
|||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const TLS_CERT_AUTH = {
|
||||||
|
LOGIN: {
|
||||||
|
identityId: "The ID of the identity to login."
|
||||||
|
},
|
||||||
|
ATTACH: {
|
||||||
|
identityId: "The ID of the identity to attach the configuration onto.",
|
||||||
|
allowedCommonNames:
|
||||||
|
"The comma-separated list of trusted common names that are allowed to authenticate with Infisical.",
|
||||||
|
caCertificate: "The PEM-encoded CA certificate to validate client certificates.",
|
||||||
|
accessTokenTTL: "The lifetime for an access token in seconds.",
|
||||||
|
accessTokenMaxTTL: "The maximum lifetime for an access token in seconds.",
|
||||||
|
accessTokenNumUsesLimit: "The maximum number of times that an access token can be used.",
|
||||||
|
accessTokenTrustedIps: "The IPs or CIDR ranges that access tokens can be used from."
|
||||||
|
},
|
||||||
|
UPDATE: {
|
||||||
|
identityId: "The ID of the identity to update the auth method for.",
|
||||||
|
allowedCommonNames:
|
||||||
|
"The comma-separated list of trusted common names that are allowed to authenticate with Infisical.",
|
||||||
|
caCertificate: "The PEM-encoded CA certificate to validate client certificates.",
|
||||||
|
accessTokenTTL: "The new lifetime for an access token in seconds.",
|
||||||
|
accessTokenMaxTTL: "The new maximum lifetime for an access token in seconds.",
|
||||||
|
accessTokenNumUsesLimit: "The new maximum number of times that an access token can be used.",
|
||||||
|
accessTokenTrustedIps: "The new IPs or CIDR ranges that access tokens can be used from."
|
||||||
|
},
|
||||||
|
RETRIEVE: {
|
||||||
|
identityId: "The ID of the identity to retrieve the auth method for."
|
||||||
|
},
|
||||||
|
REVOKE: {
|
||||||
|
identityId: "The ID of the identity to revoke the auth method for."
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const AWS_AUTH = {
|
export const AWS_AUTH = {
|
||||||
LOGIN: {
|
LOGIN: {
|
||||||
identityId: "The ID of the identity to login.",
|
identityId: "The ID of the identity to login.",
|
||||||
|
|||||||
@@ -301,6 +301,8 @@ import { registerSecretScannerGhApp } from "../plugins/secret-scanner";
|
|||||||
import { registerV1Routes } from "./v1";
|
import { registerV1Routes } from "./v1";
|
||||||
import { registerV2Routes } from "./v2";
|
import { registerV2Routes } from "./v2";
|
||||||
import { registerV3Routes } from "./v3";
|
import { registerV3Routes } from "./v3";
|
||||||
|
import { identityTlsCertAuthDALFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-dal";
|
||||||
|
import { identityTlsCertAuthServiceFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-service";
|
||||||
|
|
||||||
const histogram = monitorEventLoopDelay({ resolution: 20 });
|
const histogram = monitorEventLoopDelay({ resolution: 20 });
|
||||||
histogram.enable();
|
histogram.enable();
|
||||||
@@ -386,6 +388,7 @@ export const registerRoutes = async (
|
|||||||
const identityKubernetesAuthDAL = identityKubernetesAuthDALFactory(db);
|
const identityKubernetesAuthDAL = identityKubernetesAuthDALFactory(db);
|
||||||
const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db);
|
const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db);
|
||||||
const identityAliCloudAuthDAL = identityAliCloudAuthDALFactory(db);
|
const identityAliCloudAuthDAL = identityAliCloudAuthDALFactory(db);
|
||||||
|
const identityTlsCertAuthDAL = identityTlsCertAuthDALFactory(db);
|
||||||
const identityAwsAuthDAL = identityAwsAuthDALFactory(db);
|
const identityAwsAuthDAL = identityAwsAuthDALFactory(db);
|
||||||
const identityGcpAuthDAL = identityGcpAuthDALFactory(db);
|
const identityGcpAuthDAL = identityGcpAuthDALFactory(db);
|
||||||
const identityOciAuthDAL = identityOciAuthDALFactory(db);
|
const identityOciAuthDAL = identityOciAuthDALFactory(db);
|
||||||
@@ -1493,6 +1496,15 @@ export const registerRoutes = async (
|
|||||||
permissionService
|
permissionService
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const identityTlsCertAuthService = identityTlsCertAuthServiceFactory({
|
||||||
|
identityAccessTokenDAL,
|
||||||
|
identityTlsCertAuthDAL,
|
||||||
|
identityOrgMembershipDAL,
|
||||||
|
licenseService,
|
||||||
|
permissionService,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
const identityAwsAuthService = identityAwsAuthServiceFactory({
|
const identityAwsAuthService = identityAwsAuthServiceFactory({
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityAwsAuthDAL,
|
identityAwsAuthDAL,
|
||||||
@@ -1947,6 +1959,7 @@ export const registerRoutes = async (
|
|||||||
identityAwsAuth: identityAwsAuthService,
|
identityAwsAuth: identityAwsAuthService,
|
||||||
identityAzureAuth: identityAzureAuthService,
|
identityAzureAuth: identityAzureAuthService,
|
||||||
identityOciAuth: identityOciAuthService,
|
identityOciAuth: identityOciAuthService,
|
||||||
|
identityTlsCertAuth: identityTlsCertAuthService,
|
||||||
identityOidcAuth: identityOidcAuthService,
|
identityOidcAuth: identityOidcAuthService,
|
||||||
identityJwtAuth: identityJwtAuthService,
|
identityJwtAuth: identityJwtAuthService,
|
||||||
identityLdapAuth: identityLdapAuthService,
|
identityLdapAuth: identityLdapAuthService,
|
||||||
|
|||||||
@@ -0,0 +1,345 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
// import { TLSSocket } from "tls";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { ApiDocsTags, TLS_CERT_AUTH } from "@app/lib/api-docs";
|
||||||
|
import { IdentityTlsCertAuthsSchema } from "@app/db/schemas";
|
||||||
|
import { isSuperAdmin } from "@app/services/super-admin/super-admin-fns";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
|
||||||
|
|
||||||
|
const validateCommonNames = z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.trim()
|
||||||
|
.transform((el) =>
|
||||||
|
el
|
||||||
|
.split(",")
|
||||||
|
.map((i) => i.trim())
|
||||||
|
.join(",")
|
||||||
|
);
|
||||||
|
|
||||||
|
export const registerIdentityTlsCertAuthRouter = async (server: FastifyZodProvider) => {
|
||||||
|
// server.route({
|
||||||
|
// method: "GET",
|
||||||
|
// url: "/",
|
||||||
|
// config: {
|
||||||
|
// rateLimit: readLimit
|
||||||
|
// },
|
||||||
|
// schema: {
|
||||||
|
// params: z.object({}),
|
||||||
|
// response: {
|
||||||
|
// 200: z.object({})
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
// handler: async (req) => {
|
||||||
|
// const { socket } = req;
|
||||||
|
// if (socket instanceof TLSSocket && socket.encrypted) {
|
||||||
|
// // Inside this block, TypeScript now knows `socket` is a TlsSocket
|
||||||
|
// const certificate = socket.getPeerCertificate();
|
||||||
|
//
|
||||||
|
// if (Object.keys(certificate).length === 0) {
|
||||||
|
// return reply.send({ message: "Client did not provide a certificate." });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return reply.send({
|
||||||
|
// message: "Certificate received!",
|
||||||
|
// subject: certificate.subject,
|
||||||
|
// issuer: certificate.issuer,
|
||||||
|
// fingerprint: certificate.fingerprint
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// // This will handle plain HTTP requests gracefully
|
||||||
|
// return reply
|
||||||
|
// .status(400)
|
||||||
|
// .send({ error: "This endpoint requires an HTTPS connection with a client certificate." });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/identities/:identityId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.TlsCertAuth],
|
||||||
|
description: "Attach TLS Certificate Auth configuration onto identity",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
identityId: z.string().trim().describe(TLS_CERT_AUTH.ATTACH.identityId)
|
||||||
|
}),
|
||||||
|
body: z
|
||||||
|
.object({
|
||||||
|
allowedCommonNames: validateCommonNames.describe(TLS_CERT_AUTH.ATTACH.allowedCommonNames),
|
||||||
|
caCertificate: z.string().min(1).describe(TLS_CERT_AUTH.ATTACH.caCertificate),
|
||||||
|
accessTokenTrustedIps: z
|
||||||
|
.object({
|
||||||
|
ipAddress: z.string().trim()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.min(1)
|
||||||
|
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }])
|
||||||
|
.describe(TLS_CERT_AUTH.ATTACH.accessTokenTrustedIps),
|
||||||
|
accessTokenTTL: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.min(0)
|
||||||
|
.max(315360000)
|
||||||
|
.default(2592000)
|
||||||
|
.describe(TLS_CERT_AUTH.ATTACH.accessTokenTTL),
|
||||||
|
accessTokenMaxTTL: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.min(1)
|
||||||
|
.max(315360000)
|
||||||
|
.default(2592000)
|
||||||
|
.describe(TLS_CERT_AUTH.ATTACH.accessTokenMaxTTL),
|
||||||
|
accessTokenNumUsesLimit: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.min(0)
|
||||||
|
.default(0)
|
||||||
|
.describe(TLS_CERT_AUTH.ATTACH.accessTokenNumUsesLimit)
|
||||||
|
})
|
||||||
|
.refine(
|
||||||
|
(val) => val.accessTokenTTL <= val.accessTokenMaxTTL,
|
||||||
|
"Access Token TTL cannot be greater than Access Token Max TTL."
|
||||||
|
),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
identityTlsCloudAuth: IdentityTlsCertAuthsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const identityTlsCertAuth = await server.services.identityTlsCertAuth.attachTlsCertAuth({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
...req.body,
|
||||||
|
identityId: req.params.identityId,
|
||||||
|
isActorSuperAdmin: isSuperAdmin(req.auth)
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.ADD_IDENTITY_TLS_CERT_AUTH,
|
||||||
|
metadata: {
|
||||||
|
identityId: identityTlsCertAuth.identityId,
|
||||||
|
allowedCommonNames: identityTlsCertAuth.allowedCommonNames,
|
||||||
|
accessTokenTTL: identityTlsCertAuth.accessTokenTTL,
|
||||||
|
accessTokenMaxTTL: identityTlsCertAuth.accessTokenMaxTTL,
|
||||||
|
accessTokenTrustedIps: identityTlsCertAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
|
accessTokenNumUsesLimit: identityTlsCertAuth.accessTokenNumUsesLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { identityTlsCertAuth };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/identities/:identityId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.TlsCertAuth],
|
||||||
|
description: "Update Tls Certificate Auth configuration on identity",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
identityId: z.string().describe(TLS_CERT_AUTH.UPDATE.identityId)
|
||||||
|
}),
|
||||||
|
body: z
|
||||||
|
.object({
|
||||||
|
allowedCommonNames: validateCommonNames.describe(TLS_CERT_AUTH.UPDATE.allowedCommonNames),
|
||||||
|
accessTokenTrustedIps: z
|
||||||
|
.object({
|
||||||
|
ipAddress: z.string().trim()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.min(1)
|
||||||
|
.optional()
|
||||||
|
.describe(TLS_CERT_AUTH.UPDATE.accessTokenTrustedIps),
|
||||||
|
accessTokenTTL: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.min(0)
|
||||||
|
.max(315360000)
|
||||||
|
.optional()
|
||||||
|
.describe(TLS_CERT_AUTH.UPDATE.accessTokenTTL),
|
||||||
|
accessTokenNumUsesLimit: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.min(0)
|
||||||
|
.optional()
|
||||||
|
.describe(TLS_CERT_AUTH.UPDATE.accessTokenNumUsesLimit),
|
||||||
|
accessTokenMaxTTL: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.max(315360000)
|
||||||
|
.min(0)
|
||||||
|
.optional()
|
||||||
|
.describe(TLS_CERT_AUTH.UPDATE.accessTokenMaxTTL)
|
||||||
|
})
|
||||||
|
.refine(
|
||||||
|
(val) => (val.accessTokenMaxTTL && val.accessTokenTTL ? val.accessTokenTTL <= val.accessTokenMaxTTL : true),
|
||||||
|
"Access Token TTL cannot be greater than Access Token Max TTL."
|
||||||
|
),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
identityTlsCloudAuth: IdentityTlsCertAuthsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const identityTlsCertAuth = await server.services.identityTlsCertAuth.updateTlsCertAuth({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
...req.body,
|
||||||
|
identityId: req.params.identityId
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_IDENTITY_TLS_CERT_AUTH,
|
||||||
|
metadata: {
|
||||||
|
identityId: identityTlsCertAuth.identityId,
|
||||||
|
allowedCommonNames: identityTlsCertAuth.allowedCommonNames,
|
||||||
|
accessTokenTTL: identityTlsCertAuth.accessTokenTTL,
|
||||||
|
accessTokenMaxTTL: identityTlsCertAuth.accessTokenMaxTTL,
|
||||||
|
accessTokenTrustedIps: identityTlsCertAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
|
accessTokenNumUsesLimit: identityTlsCertAuth.accessTokenNumUsesLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { identityTlsCertAuth };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/identities/:identityId",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.TlsCertAuth],
|
||||||
|
description: "Retrieve Tls Certificate Auth configuration on identity",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
identityId: z.string().describe(TLS_CERT_AUTH.RETRIEVE.identityId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
identityTlsCloudAuth: IdentityTlsCertAuthsSchema.extend({
|
||||||
|
caCertificate: z.string()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const identityTlsCertAuth = await server.services.identityTlsCertAuth.getTlsCertAuth({
|
||||||
|
identityId: req.params.identityId,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.GET_IDENTITY_TLS_CERT_AUTH,
|
||||||
|
metadata: {
|
||||||
|
identityId: identityTlsCertAuth.identityId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { identityTlsCertAuth };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/identities/:identityId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.TlsCertAuth],
|
||||||
|
description: "Delete Tls Certificate Auth configuration on identity",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
identityId: z.string().describe(TLS_CERT_AUTH.REVOKE.identityId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
identityTlsCloudAuth: IdentityTlsCertAuthsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const identityTlsCertAuth = await server.services.identityTlsCertAuth.revokeTlsCertAuth({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
identityId: req.params.identityId
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.REVOKE_IDENTITY_TLS_CERT_AUTH,
|
||||||
|
metadata: {
|
||||||
|
identityId: identityTlsCertAuth.identityId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { identityTlsCertAuth };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -53,6 +53,7 @@ import { registerUserEngagementRouter } from "./user-engagement-router";
|
|||||||
import { registerUserRouter } from "./user-router";
|
import { registerUserRouter } from "./user-router";
|
||||||
import { registerWebhookRouter } from "./webhook-router";
|
import { registerWebhookRouter } from "./webhook-router";
|
||||||
import { registerWorkflowIntegrationRouter } from "./workflow-integration-router";
|
import { registerWorkflowIntegrationRouter } from "./workflow-integration-router";
|
||||||
|
import { registerIdentityTlsCertAuthRouter } from "./identity-tls-cert-auth-router";
|
||||||
|
|
||||||
export const registerV1Routes = async (server: FastifyZodProvider) => {
|
export const registerV1Routes = async (server: FastifyZodProvider) => {
|
||||||
await server.register(registerSsoRouter, { prefix: "/sso" });
|
await server.register(registerSsoRouter, { prefix: "/sso" });
|
||||||
@@ -66,6 +67,7 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
|
|||||||
await authRouter.register(registerIdentityAccessTokenRouter);
|
await authRouter.register(registerIdentityAccessTokenRouter);
|
||||||
await authRouter.register(registerIdentityAliCloudAuthRouter);
|
await authRouter.register(registerIdentityAliCloudAuthRouter);
|
||||||
await authRouter.register(registerIdentityAwsAuthRouter);
|
await authRouter.register(registerIdentityAwsAuthRouter);
|
||||||
|
await authRouter.register(registerIdentityTlsCertAuthRouter, { prefix: "/tls-cert-auth" });
|
||||||
await authRouter.register(registerIdentityAzureAuthRouter);
|
await authRouter.register(registerIdentityAzureAuthRouter);
|
||||||
await authRouter.register(registerIdentityOciAuthRouter);
|
await authRouter.register(registerIdentityOciAuthRouter);
|
||||||
await authRouter.register(registerIdentityOidcAuthRouter);
|
await authRouter.register(registerIdentityOidcAuthRouter);
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ export const identityAccessTokenDALFactory = (db: TDbClient) => {
|
|||||||
.leftJoin(TableName.IdentityOidcAuth, `${TableName.Identity}.id`, `${TableName.IdentityOidcAuth}.identityId`)
|
.leftJoin(TableName.IdentityOidcAuth, `${TableName.Identity}.id`, `${TableName.IdentityOidcAuth}.identityId`)
|
||||||
.leftJoin(TableName.IdentityTokenAuth, `${TableName.Identity}.id`, `${TableName.IdentityTokenAuth}.identityId`)
|
.leftJoin(TableName.IdentityTokenAuth, `${TableName.Identity}.id`, `${TableName.IdentityTokenAuth}.identityId`)
|
||||||
.leftJoin(TableName.IdentityJwtAuth, `${TableName.Identity}.id`, `${TableName.IdentityJwtAuth}.identityId`)
|
.leftJoin(TableName.IdentityJwtAuth, `${TableName.Identity}.id`, `${TableName.IdentityJwtAuth}.identityId`)
|
||||||
|
.leftJoin(
|
||||||
|
TableName.IdentityTlsCertAuth,
|
||||||
|
`${TableName.Identity}.id`,
|
||||||
|
`${TableName.IdentityTlsCertAuth}.identityId`
|
||||||
|
)
|
||||||
.select(selectAllTableCols(TableName.IdentityAccessToken))
|
.select(selectAllTableCols(TableName.IdentityAccessToken))
|
||||||
.select(
|
.select(
|
||||||
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityUniversalAuth).as("accessTokenTrustedIpsUa"),
|
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityUniversalAuth).as("accessTokenTrustedIpsUa"),
|
||||||
@@ -61,6 +66,7 @@ export const identityAccessTokenDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityTokenAuth).as("accessTokenTrustedIpsToken"),
|
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityTokenAuth).as("accessTokenTrustedIpsToken"),
|
||||||
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityJwtAuth).as("accessTokenTrustedIpsJwt"),
|
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityJwtAuth).as("accessTokenTrustedIpsJwt"),
|
||||||
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityLdapAuth).as("accessTokenTrustedIpsLdap"),
|
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityLdapAuth).as("accessTokenTrustedIpsLdap"),
|
||||||
|
db.ref("accessTokenTrustedIps").withSchema(TableName.IdentityTlsCertAuth).as("accessTokenTrustedIpsTlsCert"),
|
||||||
db.ref("name").withSchema(TableName.Identity)
|
db.ref("name").withSchema(TableName.Identity)
|
||||||
)
|
)
|
||||||
.first();
|
.first();
|
||||||
@@ -79,7 +85,8 @@ export const identityAccessTokenDALFactory = (db: TDbClient) => {
|
|||||||
trustedIpsOidcAuth: doc.accessTokenTrustedIpsOidc,
|
trustedIpsOidcAuth: doc.accessTokenTrustedIpsOidc,
|
||||||
trustedIpsAccessTokenAuth: doc.accessTokenTrustedIpsToken,
|
trustedIpsAccessTokenAuth: doc.accessTokenTrustedIpsToken,
|
||||||
trustedIpsAccessJwtAuth: doc.accessTokenTrustedIpsJwt,
|
trustedIpsAccessJwtAuth: doc.accessTokenTrustedIpsJwt,
|
||||||
trustedIpsAccessLdapAuth: doc.accessTokenTrustedIpsLdap
|
trustedIpsAccessLdapAuth: doc.accessTokenTrustedIpsLdap,
|
||||||
|
trustedIpsAccessTlsCertAuth: doc.accessTokenTrustedIpsTlsCert
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "IdAccessTokenFindOne" });
|
throw new DatabaseError({ error, name: "IdAccessTokenFindOne" });
|
||||||
|
|||||||
@@ -201,7 +201,8 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
[IdentityAuthMethod.OIDC_AUTH]: identityAccessToken.trustedIpsOidcAuth,
|
[IdentityAuthMethod.OIDC_AUTH]: identityAccessToken.trustedIpsOidcAuth,
|
||||||
[IdentityAuthMethod.TOKEN_AUTH]: identityAccessToken.trustedIpsAccessTokenAuth,
|
[IdentityAuthMethod.TOKEN_AUTH]: identityAccessToken.trustedIpsAccessTokenAuth,
|
||||||
[IdentityAuthMethod.JWT_AUTH]: identityAccessToken.trustedIpsAccessJwtAuth,
|
[IdentityAuthMethod.JWT_AUTH]: identityAccessToken.trustedIpsAccessJwtAuth,
|
||||||
[IdentityAuthMethod.LDAP_AUTH]: identityAccessToken.trustedIpsAccessLdapAuth
|
[IdentityAuthMethod.LDAP_AUTH]: identityAccessToken.trustedIpsAccessLdapAuth,
|
||||||
|
[IdentityAuthMethod.TLS_CERT_AUTH]: identityAccessToken.trustedIpsAccessTlsCertAuth
|
||||||
};
|
};
|
||||||
|
|
||||||
const trustedIps = trustedIpsMap[identityAccessToken.authMethod as IdentityAuthMethod];
|
const trustedIps = trustedIpsMap[identityAccessToken.authMethod as IdentityAuthMethod];
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TIdentityTlsCertAuthDALFactory = TOrmify<TableName.IdentityTlsCertAuth>;
|
||||||
|
|
||||||
|
export const identityTlsCertAuthDALFactory = (db: TDbClient) => {
|
||||||
|
const orm = ormify(db, TableName.IdentityTlsCertAuth);
|
||||||
|
return orm;
|
||||||
|
};
|
||||||
@@ -0,0 +1,417 @@
|
|||||||
|
import crypto from "node:crypto";
|
||||||
|
|
||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
|
||||||
|
import { IdentityAuthMethod } from "@app/db/schemas";
|
||||||
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
|
import {
|
||||||
|
constructPermissionErrorMessage,
|
||||||
|
validatePrivilegeChangeOperation
|
||||||
|
} from "@app/ee/services/permission/permission-fns";
|
||||||
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
||||||
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
|
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 { TKmsServiceFactory } from "../kms/kms-service";
|
||||||
|
import { KmsDataKey } from "../kms/kms-types";
|
||||||
|
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
|
||||||
|
import { TIdentityTlsCertAuthDALFactory } from "./identity-tls-cert-auth-dal";
|
||||||
|
import { TIdentityTlsCertAuthServiceFactory } from "./identity-tls-cert-auth-types";
|
||||||
|
|
||||||
|
type TIdentityTlsCertAuthServiceFactoryDep = {
|
||||||
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
|
identityTlsCertAuthDAL: Pick<
|
||||||
|
TIdentityTlsCertAuthDALFactory,
|
||||||
|
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
||||||
|
>;
|
||||||
|
identityOrgMembershipDAL: Pick<TIdentityOrgDALFactory, "findOne">;
|
||||||
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseSubjectDetails = (data: string) => {
|
||||||
|
const values: Record<string, string> = {};
|
||||||
|
data.split("\n").forEach((el) => {
|
||||||
|
const [key, value] = el.split("=");
|
||||||
|
values[key.trim()] = value.trim();
|
||||||
|
});
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const identityTlsCertAuthServiceFactory = ({
|
||||||
|
identityAccessTokenDAL,
|
||||||
|
identityTlsCertAuthDAL,
|
||||||
|
identityOrgMembershipDAL,
|
||||||
|
licenseService,
|
||||||
|
permissionService,
|
||||||
|
kmsService
|
||||||
|
}: TIdentityTlsCertAuthServiceFactoryDep): TIdentityTlsCertAuthServiceFactory => {
|
||||||
|
const login: TIdentityTlsCertAuthServiceFactory["login"] = async ({ identityId, clientCertificate }) => {
|
||||||
|
const identityTlsCertAuth = await identityTlsCertAuthDAL.findOne({ identityId });
|
||||||
|
if (!identityTlsCertAuth) {
|
||||||
|
throw new NotFoundError({
|
||||||
|
message: "TLS Certificate auth method not found for identity, did you configure TLS Certificate auth?"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({
|
||||||
|
identityId: identityTlsCertAuth.identityId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!identityMembershipOrg) {
|
||||||
|
throw new NotFoundError({
|
||||||
|
message: `Identity organization membership for identity with ID '${identityTlsCertAuth.identityId}' not found`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.Organization,
|
||||||
|
orgId: identityMembershipOrg.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
const caCertificate = decryptor({
|
||||||
|
cipherTextBlob: identityTlsCertAuth.encryptedCaCertificate
|
||||||
|
}).toString();
|
||||||
|
|
||||||
|
const clientCertificateX509 = new crypto.X509Certificate(Buffer.from(clientCertificate));
|
||||||
|
const caCertificateX509 = new crypto.X509Certificate(caCertificate);
|
||||||
|
|
||||||
|
const isValidCertificate = clientCertificateX509.verify(caCertificateX509.publicKey);
|
||||||
|
if (!isValidCertificate)
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Access denied: Certificate not issued by the provided CA."
|
||||||
|
});
|
||||||
|
|
||||||
|
if (new Date(clientCertificateX509.validTo) < new Date()) {
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Access denied: Certificate has expired."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new Date(clientCertificateX509.validFrom) > new Date()) {
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Access denied: Certificate not yet valid."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const subjectDetails = parseSubjectDetails(clientCertificateX509.subject);
|
||||||
|
if (identityTlsCertAuth.allowedCommonNames) {
|
||||||
|
const isValidCommonName = identityTlsCertAuth.allowedCommonNames.split(",").includes(subjectDetails.CN);
|
||||||
|
if (!isValidCommonName) {
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Access denied: TLS Certificate Auth common name not allowed."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the token
|
||||||
|
const identityAccessToken = await identityTlsCertAuthDAL.transaction(async (tx) => {
|
||||||
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
|
{
|
||||||
|
identityId: identityTlsCertAuth.identityId,
|
||||||
|
isAccessTokenRevoked: false,
|
||||||
|
accessTokenTTL: identityTlsCertAuth.accessTokenTTL,
|
||||||
|
accessTokenMaxTTL: identityTlsCertAuth.accessTokenMaxTTL,
|
||||||
|
accessTokenNumUses: 0,
|
||||||
|
accessTokenNumUsesLimit: identityTlsCertAuth.accessTokenNumUsesLimit,
|
||||||
|
authMethod: IdentityAuthMethod.TLS_CERT_AUTH
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
return newToken;
|
||||||
|
});
|
||||||
|
|
||||||
|
const appCfg = getConfig();
|
||||||
|
const accessToken = jwt.sign(
|
||||||
|
{
|
||||||
|
identityId: identityTlsCertAuth.identityId,
|
||||||
|
identityAccessTokenId: identityAccessToken.id,
|
||||||
|
authTokenType: AuthTokenType.IDENTITY_ACCESS_TOKEN
|
||||||
|
} as TIdentityAccessTokenJwtPayload,
|
||||||
|
appCfg.AUTH_SECRET,
|
||||||
|
Number(identityAccessToken.accessTokenTTL) === 0
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
expiresIn: Number(identityAccessToken.accessTokenTTL)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
identityTlsCertAuth,
|
||||||
|
accessToken,
|
||||||
|
identityAccessToken,
|
||||||
|
identityMembershipOrg
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const attachTlsCertAuth: TIdentityTlsCertAuthServiceFactory["attachTlsCertAuth"] = async ({
|
||||||
|
identityId,
|
||||||
|
accessTokenTTL,
|
||||||
|
accessTokenMaxTTL,
|
||||||
|
accessTokenNumUsesLimit,
|
||||||
|
accessTokenTrustedIps,
|
||||||
|
actorId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
isActorSuperAdmin,
|
||||||
|
caCertificate,
|
||||||
|
allowedCommonNames
|
||||||
|
}) => {
|
||||||
|
await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin);
|
||||||
|
|
||||||
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||||
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
|
||||||
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Failed to add TLS Certificate Auth to already configured identity"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessTokenMaxTTL > 0 && accessTokenTTL > accessTokenMaxTTL) {
|
||||||
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
identityMembershipOrg.orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
|
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
|
||||||
|
const reformattedAccessTokenTrustedIps = accessTokenTrustedIps.map((accessTokenTrustedIp) => {
|
||||||
|
if (
|
||||||
|
!plan.ipAllowlisting &&
|
||||||
|
accessTokenTrustedIp.ipAddress !== "0.0.0.0/0" &&
|
||||||
|
accessTokenTrustedIp.ipAddress !== "::/0"
|
||||||
|
)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message:
|
||||||
|
"Failed to add IP access range to access token due to plan restriction. Upgrade plan to add IP access range."
|
||||||
|
});
|
||||||
|
if (!isValidIpOrCidr(accessTokenTrustedIp.ipAddress))
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||||
|
});
|
||||||
|
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
||||||
|
});
|
||||||
|
|
||||||
|
const { encryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.Organization,
|
||||||
|
orgId: identityMembershipOrg.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
const identityTlsCertAuth = await identityTlsCertAuthDAL.transaction(async (tx) => {
|
||||||
|
const doc = await identityTlsCertAuthDAL.create(
|
||||||
|
{
|
||||||
|
identityId: identityMembershipOrg.identityId,
|
||||||
|
accessTokenMaxTTL,
|
||||||
|
allowedCommonNames,
|
||||||
|
accessTokenTTL,
|
||||||
|
encryptedCaCertificate: encryptor({ plainText: Buffer.from(caCertificate) }).cipherTextBlob,
|
||||||
|
accessTokenNumUsesLimit,
|
||||||
|
accessTokenTrustedIps: JSON.stringify(reformattedAccessTokenTrustedIps)
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
return doc;
|
||||||
|
});
|
||||||
|
return { ...identityTlsCertAuth, orgId: identityMembershipOrg.orgId };
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTlsCertAuth: TIdentityTlsCertAuthServiceFactory["updateTlsCertAuth"] = async ({
|
||||||
|
identityId,
|
||||||
|
caCertificate,
|
||||||
|
allowedCommonNames,
|
||||||
|
accessTokenTTL,
|
||||||
|
accessTokenMaxTTL,
|
||||||
|
accessTokenNumUsesLimit,
|
||||||
|
accessTokenTrustedIps,
|
||||||
|
actorId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actor,
|
||||||
|
actorOrgId
|
||||||
|
}) => {
|
||||||
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||||
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
|
||||||
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
||||||
|
throw new NotFoundError({
|
||||||
|
message: "The identity does not have TLS Certificate Auth attached"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityTlsCertAuth = await identityTlsCertAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
|
if (
|
||||||
|
(accessTokenMaxTTL || identityTlsCertAuth.accessTokenMaxTTL) > 0 &&
|
||||||
|
(accessTokenTTL || identityTlsCertAuth.accessTokenTTL) >
|
||||||
|
(accessTokenMaxTTL || identityTlsCertAuth.accessTokenMaxTTL)
|
||||||
|
) {
|
||||||
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
identityMembershipOrg.orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
|
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
|
||||||
|
const reformattedAccessTokenTrustedIps = accessTokenTrustedIps?.map((accessTokenTrustedIp) => {
|
||||||
|
if (
|
||||||
|
!plan.ipAllowlisting &&
|
||||||
|
accessTokenTrustedIp.ipAddress !== "0.0.0.0/0" &&
|
||||||
|
accessTokenTrustedIp.ipAddress !== "::/0"
|
||||||
|
)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message:
|
||||||
|
"Failed to add IP access range to access token due to plan restriction. Upgrade plan to add IP access range."
|
||||||
|
});
|
||||||
|
if (!isValidIpOrCidr(accessTokenTrustedIp.ipAddress))
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||||
|
});
|
||||||
|
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
||||||
|
});
|
||||||
|
const { encryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.Organization,
|
||||||
|
orgId: identityMembershipOrg.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedTlsCertAuth = await identityTlsCertAuthDAL.updateById(identityTlsCertAuth.id, {
|
||||||
|
allowedCommonNames,
|
||||||
|
encryptedCaCertificate: caCertificate
|
||||||
|
? encryptor({ plainText: Buffer.from(caCertificate) }).cipherTextBlob
|
||||||
|
: undefined,
|
||||||
|
accessTokenMaxTTL,
|
||||||
|
accessTokenTTL,
|
||||||
|
accessTokenNumUsesLimit,
|
||||||
|
accessTokenTrustedIps: reformattedAccessTokenTrustedIps
|
||||||
|
? JSON.stringify(reformattedAccessTokenTrustedIps)
|
||||||
|
: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
return { ...updatedTlsCertAuth, orgId: identityMembershipOrg.orgId };
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTlsCertAuth: TIdentityTlsCertAuthServiceFactory["getTlsCertAuth"] = async ({
|
||||||
|
identityId,
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}) => {
|
||||||
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||||
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
|
||||||
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "The identity does not have TLS Certificate Auth attached"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const identityAuth = await identityTlsCertAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
identityMembershipOrg.orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.Organization,
|
||||||
|
orgId: identityMembershipOrg.orgId
|
||||||
|
});
|
||||||
|
let caCertificate = "";
|
||||||
|
if (identityAuth.encryptedCaCertificate) {
|
||||||
|
caCertificate = decryptor({ cipherTextBlob: identityAuth.encryptedCaCertificate }).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...identityAuth, caCertificate, orgId: identityMembershipOrg.orgId };
|
||||||
|
};
|
||||||
|
|
||||||
|
const revokeTlsCertAuth: TIdentityTlsCertAuthServiceFactory["revokeTlsCertAuth"] = async ({
|
||||||
|
identityId,
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}) => {
|
||||||
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||||
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "The identity does not have TLS Certificate auth"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const { permission, membership } = await permissionService.getOrgPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
identityMembershipOrg.orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
|
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
||||||
|
ActorType.IDENTITY,
|
||||||
|
identityMembershipOrg.identityId,
|
||||||
|
identityMembershipOrg.orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
|
||||||
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
|
membership.shouldUseNewPrivilegeSystem,
|
||||||
|
OrgPermissionIdentityActions.RevokeAuth,
|
||||||
|
OrgPermissionSubjects.Identity,
|
||||||
|
permission,
|
||||||
|
rolePermission
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!permissionBoundary.isValid)
|
||||||
|
throw new PermissionBoundaryError({
|
||||||
|
message: constructPermissionErrorMessage(
|
||||||
|
"Failed to revoke TLS Certificate auth of identity with more privileged role",
|
||||||
|
membership.shouldUseNewPrivilegeSystem,
|
||||||
|
OrgPermissionIdentityActions.RevokeAuth,
|
||||||
|
OrgPermissionSubjects.Identity
|
||||||
|
),
|
||||||
|
details: { missingPermissions: permissionBoundary.missingPermissions }
|
||||||
|
});
|
||||||
|
|
||||||
|
const revokedIdentityTlsCertAuth = await identityTlsCertAuthDAL.transaction(async (tx) => {
|
||||||
|
const deletedTlsCertAuth = await identityTlsCertAuthDAL.delete({ identityId }, tx);
|
||||||
|
await identityAccessTokenDAL.delete({ identityId, authMethod: IdentityAuthMethod.TLS_CERT_AUTH }, tx);
|
||||||
|
|
||||||
|
return { ...deletedTlsCertAuth?.[0], orgId: identityMembershipOrg.orgId };
|
||||||
|
});
|
||||||
|
return revokedIdentityTlsCertAuth;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
login,
|
||||||
|
attachTlsCertAuth,
|
||||||
|
updateTlsCertAuth,
|
||||||
|
getTlsCertAuth,
|
||||||
|
revokeTlsCertAuth
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { TIdentityAccessTokens, TIdentityOrgMemberships, TIdentityTlsCertAuths } from "@app/db/schemas";
|
||||||
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|
||||||
|
export type TLoginTlsCertAuthDTO = {
|
||||||
|
identityId: string;
|
||||||
|
clientCertificate: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TAttachTlsCertAuthDTO = {
|
||||||
|
identityId: string;
|
||||||
|
caCertificate: string;
|
||||||
|
allowedCommonNames?: string;
|
||||||
|
accessTokenTTL: number;
|
||||||
|
accessTokenMaxTTL: number;
|
||||||
|
accessTokenNumUsesLimit: number;
|
||||||
|
accessTokenTrustedIps: { ipAddress: string }[];
|
||||||
|
isActorSuperAdmin?: boolean;
|
||||||
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export type TUpdateTlsCertAuthDTO = {
|
||||||
|
identityId: string;
|
||||||
|
caCertificate?: string;
|
||||||
|
allowedCommonNames?: string;
|
||||||
|
accessTokenTTL?: number;
|
||||||
|
accessTokenMaxTTL?: number;
|
||||||
|
accessTokenNumUsesLimit?: number;
|
||||||
|
accessTokenTrustedIps?: { ipAddress: string }[];
|
||||||
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export type TGetTlsCertAuthDTO = {
|
||||||
|
identityId: string;
|
||||||
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export type TRevokeTlsCertAuthDTO = {
|
||||||
|
identityId: string;
|
||||||
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export type TIdentityTlsCertAuthServiceFactory = {
|
||||||
|
login: (dto: TLoginTlsCertAuthDTO) => Promise<{
|
||||||
|
identityTlsCertAuth: TIdentityTlsCertAuths;
|
||||||
|
accessToken: string;
|
||||||
|
identityAccessToken: TIdentityAccessTokens;
|
||||||
|
identityMembershipOrg: TIdentityOrgMemberships;
|
||||||
|
}>;
|
||||||
|
attachTlsCertAuth: (dto: TAttachTlsCertAuthDTO) => Promise<TIdentityTlsCertAuths>;
|
||||||
|
updateTlsCertAuth: (dto: TUpdateTlsCertAuthDTO) => Promise<TIdentityTlsCertAuths>;
|
||||||
|
revokeTlsCertAuth: (dto: TRevokeTlsCertAuthDTO) => Promise<TIdentityTlsCertAuths>;
|
||||||
|
getTlsCertAuth: (dto: TGetTlsCertAuthDTO) => Promise<TIdentityTlsCertAuths & { caCertificate: string }>;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user