diff --git a/backend/src/ee/routes/v1/ldap-router.ts b/backend/src/ee/routes/v1/ldap-router.ts index 57c5736df..7c520e2ab 100644 --- a/backend/src/ee/routes/v1/ldap-router.ts +++ b/backend/src/ee/routes/v1/ldap-router.ts @@ -17,6 +17,7 @@ import { z } from "zod"; import { LdapGroupMapsSchema } from "@app/db/schemas"; import { TLDAPConfig } from "@app/ee/services/ldap-config/ldap-config-types"; import { isValidLdapFilter, searchGroups } from "@app/ee/services/ldap-config/ldap-fns"; +import { ApiDocsTags, LdapSso } from "@app/lib/api-docs"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError } from "@app/lib/errors"; import { logger } from "@app/lib/logger"; @@ -132,10 +133,18 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => { config: { rateLimit: readLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.LdapSso], + description: "Get LDAP config", + security: [ + { + bearerAuth: [] + } + ], querystring: z.object({ - organizationId: z.string().trim() + organizationId: z.string().trim().describe(LdapSso.GET_CONFIG.organizationId) }), response: { 200: z.object({ @@ -172,23 +181,32 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => { config: { rateLimit: writeLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.LdapSso], + description: "Create LDAP config", + security: [ + { + bearerAuth: [] + } + ], body: z.object({ - organizationId: z.string().trim(), - isActive: z.boolean(), - url: z.string().trim(), - bindDN: z.string().trim(), - bindPass: z.string().trim(), - uniqueUserAttribute: z.string().trim().default("uidNumber"), - searchBase: z.string().trim(), - searchFilter: z.string().trim().default("(uid={{username}})"), - groupSearchBase: z.string().trim(), + organizationId: z.string().trim().describe(LdapSso.CREATE_CONFIG.organizationId), + isActive: z.boolean().describe(LdapSso.CREATE_CONFIG.isActive), + url: z.string().trim().describe(LdapSso.CREATE_CONFIG.url), + bindDN: z.string().trim().describe(LdapSso.CREATE_CONFIG.bindDN), + bindPass: z.string().trim().describe(LdapSso.CREATE_CONFIG.bindPass), + uniqueUserAttribute: z.string().trim().default("uidNumber").describe(LdapSso.CREATE_CONFIG.uniqueUserAttribute), + searchBase: z.string().trim().describe(LdapSso.CREATE_CONFIG.searchBase), + searchFilter: z.string().trim().default("(uid={{username}})").describe(LdapSso.CREATE_CONFIG.searchFilter), + groupSearchBase: z.string().trim().describe(LdapSso.CREATE_CONFIG.groupSearchBase), groupSearchFilter: z .string() .trim() - .default("(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))"), - caCert: z.string().trim().default("") + .default("(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))") + .describe(LdapSso.CREATE_CONFIG.groupSearchFilter), + caCert: z.string().trim().default("").describe(LdapSso.CREATE_CONFIG.caCert) }), response: { 200: SanitizedLdapConfigSchema @@ -214,23 +232,31 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => { config: { rateLimit: writeLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.LdapSso], + description: "Update LDAP config", + security: [ + { + bearerAuth: [] + } + ], body: z .object({ - isActive: z.boolean(), - url: z.string().trim(), - bindDN: z.string().trim(), - bindPass: z.string().trim(), - uniqueUserAttribute: z.string().trim(), - searchBase: z.string().trim(), - searchFilter: z.string().trim(), - groupSearchBase: z.string().trim(), - groupSearchFilter: z.string().trim(), - caCert: z.string().trim() + isActive: z.boolean().describe(LdapSso.UPDATE_CONFIG.isActive), + url: z.string().trim().describe(LdapSso.UPDATE_CONFIG.url), + bindDN: z.string().trim().describe(LdapSso.UPDATE_CONFIG.bindDN), + bindPass: z.string().trim().describe(LdapSso.UPDATE_CONFIG.bindPass), + uniqueUserAttribute: z.string().trim().describe(LdapSso.UPDATE_CONFIG.uniqueUserAttribute), + searchBase: z.string().trim().describe(LdapSso.UPDATE_CONFIG.searchBase), + searchFilter: z.string().trim().describe(LdapSso.UPDATE_CONFIG.searchFilter), + groupSearchBase: z.string().trim().describe(LdapSso.UPDATE_CONFIG.groupSearchBase), + groupSearchFilter: z.string().trim().describe(LdapSso.UPDATE_CONFIG.groupSearchFilter), + caCert: z.string().trim().describe(LdapSso.UPDATE_CONFIG.caCert) }) .partial() - .merge(z.object({ organizationId: z.string() })), + .merge(z.object({ organizationId: z.string().trim().describe(LdapSso.UPDATE_CONFIG.organizationId) })), response: { 200: SanitizedLdapConfigSchema } diff --git a/backend/src/ee/routes/v1/oidc-router.ts b/backend/src/ee/routes/v1/oidc-router.ts index 1bfc4d696..59c05272d 100644 --- a/backend/src/ee/routes/v1/oidc-router.ts +++ b/backend/src/ee/routes/v1/oidc-router.ts @@ -13,6 +13,7 @@ import { z } from "zod"; import { OidcConfigsSchema } from "@app/db/schemas"; import { OIDCConfigurationType, OIDCJWTSignatureAlgorithm } from "@app/ee/services/oidc/oidc-config-types"; +import { ApiDocsTags, OidcSSo } from "@app/lib/api-docs"; import { getConfig } from "@app/lib/config/env"; import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -153,10 +154,18 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => { config: { rateLimit: readLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.OidcSso], + description: "Get OIDC config", + security: [ + { + bearerAuth: [] + } + ], querystring: z.object({ - orgSlug: z.string().trim() + organizationId: z.string().trim().describe(OidcSSo.GET_CONFIG.organizationId) }), response: { 200: SanitizedOidcConfigSchema.pick({ @@ -180,9 +189,8 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const { orgSlug } = req.query; const oidc = await server.services.oidc.getOidc({ - orgSlug, + organizationId: req.query.organizationId, type: "external", actor: req.permission.type, actorId: req.permission.id, @@ -200,8 +208,16 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => { config: { rateLimit: writeLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.OidcSso], + description: "Update OIDC config", + security: [ + { + bearerAuth: [] + } + ], body: z .object({ allowedEmailDomains: z @@ -216,22 +232,26 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => { .split(",") .map((id) => id.trim()) .join(", "); - }), - discoveryURL: z.string().trim(), - configurationType: z.nativeEnum(OIDCConfigurationType), - issuer: z.string().trim(), - authorizationEndpoint: z.string().trim(), - jwksUri: z.string().trim(), - tokenEndpoint: z.string().trim(), - userinfoEndpoint: z.string().trim(), - clientId: z.string().trim(), - clientSecret: z.string().trim(), - isActive: z.boolean(), - manageGroupMemberships: z.boolean().optional(), - jwtSignatureAlgorithm: z.nativeEnum(OIDCJWTSignatureAlgorithm).optional() + }) + .describe(OidcSSo.UPDATE_CONFIG.allowedEmailDomains), + discoveryURL: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.discoveryURL), + configurationType: z.nativeEnum(OIDCConfigurationType).describe(OidcSSo.UPDATE_CONFIG.configurationType), + issuer: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.issuer), + authorizationEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.authorizationEndpoint), + jwksUri: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.jwksUri), + tokenEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.tokenEndpoint), + userinfoEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.userinfoEndpoint), + clientId: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.clientId), + clientSecret: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.clientSecret), + isActive: z.boolean().describe(OidcSSo.UPDATE_CONFIG.isActive), + manageGroupMemberships: z.boolean().optional().describe(OidcSSo.UPDATE_CONFIG.manageGroupMemberships), + jwtSignatureAlgorithm: z + .nativeEnum(OIDCJWTSignatureAlgorithm) + .optional() + .describe(OidcSSo.UPDATE_CONFIG.jwtSignatureAlgorithm) }) .partial() - .merge(z.object({ orgSlug: z.string() })), + .merge(z.object({ organizationId: z.string().describe(OidcSSo.UPDATE_CONFIG.organizationId) })), response: { 200: SanitizedOidcConfigSchema.pick({ id: true, @@ -267,8 +287,16 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => { config: { rateLimit: writeLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.OidcSso], + description: "Create OIDC config", + security: [ + { + bearerAuth: [] + } + ], body: z .object({ allowedEmailDomains: z @@ -283,23 +311,34 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => { .split(",") .map((id) => id.trim()) .join(", "); - }), - configurationType: z.nativeEnum(OIDCConfigurationType), - issuer: z.string().trim().optional().default(""), - discoveryURL: z.string().trim().optional().default(""), - authorizationEndpoint: z.string().trim().optional().default(""), - jwksUri: z.string().trim().optional().default(""), - tokenEndpoint: z.string().trim().optional().default(""), - userinfoEndpoint: z.string().trim().optional().default(""), - clientId: z.string().trim(), - clientSecret: z.string().trim(), - isActive: z.boolean(), - orgSlug: z.string().trim(), - manageGroupMemberships: z.boolean().optional().default(false), + }) + .describe(OidcSSo.CREATE_CONFIG.allowedEmailDomains), + configurationType: z.nativeEnum(OIDCConfigurationType).describe(OidcSSo.CREATE_CONFIG.configurationType), + issuer: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.issuer), + discoveryURL: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.discoveryURL), + authorizationEndpoint: z + .string() + .trim() + .optional() + .default("") + .describe(OidcSSo.CREATE_CONFIG.authorizationEndpoint), + jwksUri: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.jwksUri), + tokenEndpoint: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.tokenEndpoint), + userinfoEndpoint: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.userinfoEndpoint), + clientId: z.string().trim().describe(OidcSSo.CREATE_CONFIG.clientId), + clientSecret: z.string().trim().describe(OidcSSo.CREATE_CONFIG.clientSecret), + isActive: z.boolean().describe(OidcSSo.CREATE_CONFIG.isActive), + organizationId: z.string().trim().describe(OidcSSo.CREATE_CONFIG.organizationId), + manageGroupMemberships: z + .boolean() + .optional() + .default(false) + .describe(OidcSSo.CREATE_CONFIG.manageGroupMemberships), jwtSignatureAlgorithm: z .nativeEnum(OIDCJWTSignatureAlgorithm) .optional() .default(OIDCJWTSignatureAlgorithm.RS256) + .describe(OidcSSo.CREATE_CONFIG.jwtSignatureAlgorithm) }) .superRefine((data, ctx) => { if (data.configurationType === OIDCConfigurationType.CUSTOM) { diff --git a/backend/src/ee/routes/v1/saml-router.ts b/backend/src/ee/routes/v1/saml-router.ts index c8395d608..f8e371d01 100644 --- a/backend/src/ee/routes/v1/saml-router.ts +++ b/backend/src/ee/routes/v1/saml-router.ts @@ -13,6 +13,7 @@ import { FastifyRequest } from "fastify"; import { z } from "zod"; import { SamlProviders, TGetSamlCfgDTO } from "@app/ee/services/saml-config/saml-config-types"; +import { ApiDocsTags, SamlSso } from "@app/lib/api-docs"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError } from "@app/lib/errors"; import { logger } from "@app/lib/logger"; @@ -149,8 +150,8 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { firstName, lastName: lastName as string, relayState: (req.body as { RelayState?: string }).RelayState, - authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider as string, - orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId as string, + authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider, + orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId, metadata: userMetadata }); cb(null, { isUserCompleted, providerAuthToken }); @@ -262,25 +263,31 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { config: { rateLimit: readLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SamlSso], + description: "Get SAML config", + security: [ + { + bearerAuth: [] + } + ], querystring: z.object({ - organizationId: z.string().trim() + organizationId: z.string().trim().describe(SamlSso.GET_CONFIG.organizationId) }), response: { - 200: z - .object({ - id: z.string(), - organization: z.string(), - orgId: z.string(), - authProvider: z.string(), - isActive: z.boolean(), - entryPoint: z.string(), - issuer: z.string(), - cert: z.string(), - lastUsed: z.date().nullable().optional() - }) - .optional() + 200: z.object({ + id: z.string(), + organization: z.string(), + orgId: z.string(), + authProvider: z.string(), + isActive: z.boolean(), + entryPoint: z.string(), + issuer: z.string(), + cert: z.string(), + lastUsed: z.date().nullable().optional() + }) } }, handler: async (req) => { @@ -302,15 +309,23 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { config: { rateLimit: writeLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SamlSso], + description: "Create SAML config", + security: [ + { + bearerAuth: [] + } + ], body: z.object({ - organizationId: z.string(), - authProvider: z.nativeEnum(SamlProviders), - isActive: z.boolean(), - entryPoint: z.string(), - issuer: z.string(), - cert: z.string() + organizationId: z.string().trim().describe(SamlSso.CREATE_CONFIG.organizationId), + authProvider: z.nativeEnum(SamlProviders).describe(SamlSso.CREATE_CONFIG.authProvider), + isActive: z.boolean().describe(SamlSso.CREATE_CONFIG.isActive), + entryPoint: z.string().trim().describe(SamlSso.CREATE_CONFIG.entryPoint), + issuer: z.string().trim().describe(SamlSso.CREATE_CONFIG.issuer), + cert: z.string().trim().describe(SamlSso.CREATE_CONFIG.cert) }), response: { 200: SanitizedSamlConfigSchema @@ -341,18 +356,26 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { config: { rateLimit: writeLimit }, - onRequest: verifyAuth([AuthMode.JWT]), + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SamlSso], + description: "Update SAML config", + security: [ + { + bearerAuth: [] + } + ], body: z .object({ - authProvider: z.nativeEnum(SamlProviders), - isActive: z.boolean(), - entryPoint: z.string(), - issuer: z.string(), - cert: z.string() + authProvider: z.nativeEnum(SamlProviders).describe(SamlSso.UPDATE_CONFIG.authProvider), + isActive: z.boolean().describe(SamlSso.UPDATE_CONFIG.isActive), + entryPoint: z.string().trim().describe(SamlSso.UPDATE_CONFIG.entryPoint), + issuer: z.string().trim().describe(SamlSso.UPDATE_CONFIG.issuer), + cert: z.string().trim().describe(SamlSso.UPDATE_CONFIG.cert) }) .partial() - .merge(z.object({ organizationId: z.string() })), + .merge(z.object({ organizationId: z.string().trim().describe(SamlSso.UPDATE_CONFIG.organizationId) })), response: { 200: SanitizedSamlConfigSchema } diff --git a/backend/src/ee/services/oidc/oidc-config-service.ts b/backend/src/ee/services/oidc/oidc-config-service.ts index a5088bde5..1a3374035 100644 --- a/backend/src/ee/services/oidc/oidc-config-service.ts +++ b/backend/src/ee/services/oidc/oidc-config-service.ts @@ -107,34 +107,26 @@ export const oidcConfigServiceFactory = ({ kmsService }: TOidcConfigServiceFactoryDep) => { const getOidc = async (dto: TGetOidcCfgDTO) => { - const org = await orgDAL.findOne({ slug: dto.orgSlug }); - if (!org) { + const oidcCfg = await oidcConfigDAL.findOne({ + orgId: dto.organizationId + }); + if (!oidcCfg) { throw new NotFoundError({ - message: `Organization with slug '${dto.orgSlug}' not found`, - name: "OrgNotFound" + message: `OIDC configuration for organization with ID '${dto.organizationId}' not found` }); } + if (dto.type === "external") { const { permission } = await permissionService.getOrgPermission( dto.actor, dto.actorId, - org.id, + dto.organizationId, dto.actorAuthMethod, dto.actorOrgId ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso); } - const oidcCfg = await oidcConfigDAL.findOne({ - orgId: org.id - }); - - if (!oidcCfg) { - throw new NotFoundError({ - message: `OIDC configuration for organization with slug '${dto.orgSlug}' not found` - }); - } - const { decryptor } = await kmsService.createCipherPairWithDataKey({ type: KmsDataKey.Organization, orgId: oidcCfg.orgId @@ -465,7 +457,7 @@ export const oidcConfigServiceFactory = ({ }; const updateOidcCfg = async ({ - orgSlug, + organizationId, allowedEmailDomains, configurationType, discoveryURL, @@ -484,13 +476,11 @@ export const oidcConfigServiceFactory = ({ manageGroupMemberships, jwtSignatureAlgorithm }: TUpdateOidcCfgDTO) => { - const org = await orgDAL.findOne({ - slug: orgSlug - }); + const org = await orgDAL.findOne({ id: organizationId }); if (!org) { throw new NotFoundError({ - message: `Organization with slug '${orgSlug}' not found` + message: `Organization with ID '${organizationId}' not found` }); } @@ -555,7 +545,7 @@ export const oidcConfigServiceFactory = ({ }; const createOidcCfg = async ({ - orgSlug, + organizationId, allowedEmailDomains, configurationType, discoveryURL, @@ -574,12 +564,10 @@ export const oidcConfigServiceFactory = ({ manageGroupMemberships, jwtSignatureAlgorithm }: TCreateOidcCfgDTO) => { - const org = await orgDAL.findOne({ - slug: orgSlug - }); + const org = await orgDAL.findOne({ id: organizationId }); if (!org) { throw new NotFoundError({ - message: `Organization with slug '${orgSlug}' not found` + message: `Organization with ID '${organizationId}' not found` }); } @@ -639,7 +627,7 @@ export const oidcConfigServiceFactory = ({ const oidcCfg = await getOidc({ type: "internal", - orgSlug + organizationId: org.id }); if (!oidcCfg || !oidcCfg.isActive) { diff --git a/backend/src/ee/services/oidc/oidc-config-types.ts b/backend/src/ee/services/oidc/oidc-config-types.ts index c56427e63..f38f2172f 100644 --- a/backend/src/ee/services/oidc/oidc-config-types.ts +++ b/backend/src/ee/services/oidc/oidc-config-types.ts @@ -26,11 +26,11 @@ export type TOidcLoginDTO = { export type TGetOidcCfgDTO = | ({ type: "external"; - orgSlug: string; + organizationId: string; } & TGenericPermission) | { type: "internal"; - orgSlug: string; + organizationId: string; }; export type TCreateOidcCfgDTO = { @@ -45,7 +45,7 @@ export type TCreateOidcCfgDTO = { clientId: string; clientSecret: string; isActive: boolean; - orgSlug: string; + organizationId: string; manageGroupMemberships: boolean; jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm; } & TGenericPermission; @@ -62,7 +62,7 @@ export type TUpdateOidcCfgDTO = Partial<{ clientId: string; clientSecret: string; isActive: boolean; - orgSlug: string; + organizationId: string; manageGroupMemberships: boolean; jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm; }> & diff --git a/backend/src/ee/services/saml-config/saml-config-service.ts b/backend/src/ee/services/saml-config/saml-config-service.ts index c81fd518b..5430b0afc 100644 --- a/backend/src/ee/services/saml-config/saml-config-service.ts +++ b/backend/src/ee/services/saml-config/saml-config-service.ts @@ -148,10 +148,18 @@ export const samlConfigServiceFactory = ({ let samlConfig: TSamlConfigs | undefined; if (dto.type === "org") { samlConfig = await samlConfigDAL.findOne({ orgId: dto.orgId }); - if (!samlConfig) return; + if (!samlConfig) { + throw new NotFoundError({ + message: `SAML configuration for organization with ID '${dto.orgId}' not found` + }); + } } else if (dto.type === "orgSlug") { const org = await orgDAL.findOne({ slug: dto.orgSlug }); - if (!org) return; + if (!org) { + throw new NotFoundError({ + message: `Organization with slug '${dto.orgSlug}' not found` + }); + } samlConfig = await samlConfigDAL.findOne({ orgId: org.id }); } else if (dto.type === "ssoId") { // TODO: diff --git a/backend/src/ee/services/saml-config/saml-config-types.ts b/backend/src/ee/services/saml-config/saml-config-types.ts index a9bd8f485..f4ede04fa 100644 --- a/backend/src/ee/services/saml-config/saml-config-types.ts +++ b/backend/src/ee/services/saml-config/saml-config-types.ts @@ -61,20 +61,17 @@ export type TSamlLoginDTO = { export type TSamlConfigServiceFactory = { createSamlCfg: (arg: TCreateSamlCfgDTO) => Promise; updateSamlCfg: (arg: TUpdateSamlCfgDTO) => Promise; - getSaml: (arg: TGetSamlCfgDTO) => Promise< - | { - id: string; - organization: string; - orgId: string; - authProvider: string; - isActive: boolean; - entryPoint: string; - issuer: string; - cert: string; - lastUsed: Date | null | undefined; - } - | undefined - >; + getSaml: (arg: TGetSamlCfgDTO) => Promise<{ + id: string; + organization: string; + orgId: string; + authProvider: string; + isActive: boolean; + entryPoint: string; + issuer: string; + cert: string; + lastUsed: Date | null | undefined; + }>; samlLogin: (arg: TSamlLoginDTO) => Promise<{ isUserCompleted: boolean; providerAuthToken: string; diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index b973ff5fd..de5060f6f 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -66,7 +66,10 @@ export enum ApiDocsTags { KmsKeys = "KMS Keys", KmsEncryption = "KMS Encryption", KmsSigning = "KMS Signing", - SecretScanning = "Secret Scanning" + SecretScanning = "Secret Scanning", + OidcSso = "OIDC SSO", + SamlSso = "SAML SSO", + LdapSso = "LDAP SSO" } export const GROUPS = { @@ -2670,3 +2673,113 @@ export const SecretScanningConfigs = { content: "The contents of the Secret Scanning Configuration file." } }; + +export const OidcSSo = { + GET_CONFIG: { + organizationId: "The ID of the organization to get the OIDC config for." + }, + UPDATE_CONFIG: { + organizationId: "The ID of the organization to update the OIDC config for.", + allowedEmailDomains: + "A list of allowed email domains that users can use to authenticate with. This field is comma separated. Example: 'example.com,acme.com'", + discoveryURL: "The URL of the OIDC discovery endpoint.", + configurationType: "The configuration type to use for the OIDC configuration.", + issuer: + "The issuer for the OIDC configuration. This is only supported when the OIDC configuration type is set to 'custom'.", + authorizationEndpoint: + "The endpoint to use for OIDC authorization. This is only supported when the OIDC configuration type is set to 'custom'.", + jwksUri: "The URL of the OIDC JWKS endpoint.", + tokenEndpoint: "The token endpoint to use for OIDC token exchange.", + userinfoEndpoint: "The userinfo endpoint to get user information from the OIDC provider.", + clientId: "The client ID to use for OIDC authentication.", + clientSecret: "The client secret to use for OIDC authentication.", + isActive: "Whether to enable or disable this OIDC configuration.", + manageGroupMemberships: + "Whether to manage group memberships for the OIDC configuration. If enabled, users will automatically be assigned groups when they sign in, based on which groups they are a member of in the OIDC provider.", + jwtSignatureAlgorithm: "The algorithm to use for JWT signature verification." + }, + CREATE_CONFIG: { + organizationId: "The ID of the organization to create the OIDC config for.", + allowedEmailDomains: + "A list of allowed email domains that users can use to authenticate with. This field is comma separated.", + discoveryURL: "The URL of the OIDC discovery endpoint.", + configurationType: "The configuration type to use for the OIDC configuration.", + issuer: + "The issuer for the OIDC configuration. This is only supported when the OIDC configuration type is set to 'custom'.", + authorizationEndpoint: + "The authorization endpoint to use for OIDC authorization. This is only supported when the OIDC configuration type is set to 'custom'.", + jwksUri: "The URL of the OIDC JWKS endpoint.", + tokenEndpoint: "The token endpoint to use for OIDC token exchange.", + userinfoEndpoint: "The userinfo endpoint to get user information from the OIDC provider.", + clientId: "The client ID to use for OIDC authentication.", + clientSecret: "The client secret to use for OIDC authentication.", + isActive: "Whether to enable or disable this OIDC configuration.", + manageGroupMemberships: + "Whether to manage group memberships for the OIDC configuration. If enabled, users will automatically be assigned groups when they sign in, based on which groups they are a member of in the OIDC provider.", + jwtSignatureAlgorithm: "The algorithm to use for JWT signature verification." + } +}; + +export const SamlSso = { + GET_CONFIG: { + organizationId: "The ID of the organization to get the SAML config for." + }, + UPDATE_CONFIG: { + organizationId: "The ID of the organization to update the SAML config for.", + authProvider: "Authentication provider to use for SAML authentication.", + isActive: "Whether to enable or disable this SAML configuration.", + entryPoint: + "The entry point for the SAML authentication. This is the URL that the user will be redirected to after they have authenticated with the SAML provider.", + issuer: "The SAML provider issuer URL or entity ID.", + cert: "The certificate to use for SAML authentication." + }, + CREATE_CONFIG: { + organizationId: "The ID of the organization to create the SAML config for.", + authProvider: "Authentication provider to use for SAML authentication.", + isActive: "Whether to enable or disable this SAML configuration.", + entryPoint: + "The entry point for the SAML authentication. This is the URL that the user will be redirected to after they have authenticated with the SAML provider.", + issuer: "The SAML provider issuer URL or entity ID.", + cert: "The certificate to use for SAML authentication." + } +}; + +export const LdapSso = { + GET_CONFIG: { + organizationId: "The ID of the organization to get the LDAP config for." + }, + CREATE_CONFIG: { + organizationId: "The ID of the organization to create the LDAP config for.", + isActive: "Whether to enable or disable this LDAP configuration.", + url: "The LDAP server to connect to such as `ldap://ldap.your-org.com`, `ldaps://ldap.myorg.com:636` (for connection over SSL/TLS), etc.", + bindDN: + "The distinguished name of the object to bind when performing the user search such as `cn=infisical,ou=Users,dc=acme,dc=com`", + bindPass: "The password to use along with Bind DN when performing the user search.", + searchBase: "The base DN to use for the user search such as `ou=Users,dc=acme,dc=com`", + uniqueUserAttribute: + "The attribute to use as the unique identifier of LDAP users such as `sAMAccountName`, `cn`, `uid`, `objectGUID`. If left blank, defaults to uidNumber", + searchFilter: + "The template used to construct the LDAP user search filter such as `(uid={{username}})` uses literal `{{username}}` to have the given username used in the search. The default is `(uid={{username}})` which is compatible with several common directory schemas.", + groupSearchBase: "LDAP search base to use for group membership search such as `ou=Groups,dc=acme,dc=com`", + groupSearchFilter: + "The template used when constructing the group membership query such as `(&(objectClass=posixGroup)(memberUid={{.Username}}))`. The template can access the following context variables: `[UserDN, UserName]`. The default is `(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))` which is compatible with several common directory schemas.", + caCert: "The CA certificate to use when verifying the LDAP server certificate." + }, + UPDATE_CONFIG: { + organizationId: "The ID of the organization to update the LDAP config for.", + isActive: "Whether to enable or disable this LDAP configuration.", + url: "The LDAP server to connect to such as `ldap://ldap.your-org.com`, `ldaps://ldap.myorg.com:636` (for connection over SSL/TLS), etc.", + bindDN: + "The distinguished name of object to bind when performing the user search such as `cn=infisical,ou=Users,dc=acme,dc=com`", + bindPass: "The password to use along with Bind DN when performing the user search.", + uniqueUserAttribute: + "The attribute to use as the unique identifier of LDAP users such as `sAMAccountName`, `cn`, `uid`, `objectGUID`. If left blank, defaults to uidNumber", + searchFilter: + "The template used to construct the LDAP user search filter such as `(uid={{username}})` uses literal `{{username}}` to have the given username used in the search. The default is `(uid={{username}})` which is compatible with several common directory schemas.", + searchBase: "The base DN to use for the user search such as `ou=Users,dc=acme,dc=com`", + groupSearchBase: "LDAP search base to use for group membership search such as `ou=Groups,dc=acme,dc=com`", + groupSearchFilter: + "The template used when constructing the group membership query such as `(&(objectClass=posixGroup)(memberUid={{.Username}}))`. The template can access the following context variables: `[UserDN, UserName]`. The default is `(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))` which is compatible with several common directory schemas.", + caCert: "The CA certificate to use when verifying the LDAP server certificate." + } +}; diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 4704449fc..8500e6518 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -1911,6 +1911,7 @@ export const registerRoutes = async ( await hsmService.startService(); await telemetryQueue.startTelemetryCheck(); + await telemetryQueue.startAggregatedEventsJob(); await dailyResourceCleanUp.startCleanUp(); await dailyExpiringPkiItemAlert.startSendingAlerts(); await pkiSubscriberQueue.startDailyAutoRenewalJob(); diff --git a/backend/src/server/routes/v1/secret-sync-routers/secret-sync-endpoints.ts b/backend/src/server/routes/v1/secret-sync-routers/secret-sync-endpoints.ts index 6ab9b5939..9db3a2013 100644 --- a/backend/src/server/routes/v1/secret-sync-routers/secret-sync-endpoints.ts +++ b/backend/src/server/routes/v1/secret-sync-routers/secret-sync-endpoints.ts @@ -382,7 +382,8 @@ export const registerSyncSecretsEndpoints = { // clear previous aggregated events job await queueService.stopRepeatableJob( QueueName.TelemetryAggregatedEvents, @@ -80,11 +89,6 @@ export const telemetryQueueServiceFactory = ({ ); if (postHog) { - await queueService.queue(QueueName.TelemetryInstanceStats, QueueJobs.TelemetryInstanceStats, undefined, { - jobId: QueueName.TelemetryInstanceStats, - repeat: { pattern: "0 0 * * *", utc: true } - }); - // Start aggregated events job (runs every five minutes) await queueService.queue(QueueName.TelemetryAggregatedEvents, QueueJobs.TelemetryAggregatedEvents, undefined, { jobId: QueueName.TelemetryAggregatedEvents, @@ -102,6 +106,7 @@ export const telemetryQueueServiceFactory = ({ }); return { - startTelemetryCheck + startTelemetryCheck, + startAggregatedEventsJob }; }; diff --git a/backend/src/services/telemetry/telemetry-service.ts b/backend/src/services/telemetry/telemetry-service.ts index eaab5bec6..6dbd12ff5 100644 --- a/backend/src/services/telemetry/telemetry-service.ts +++ b/backend/src/services/telemetry/telemetry-service.ts @@ -14,7 +14,7 @@ export const TELEMETRY_SECRET_PROCESSED_KEY = "telemetry-secret-processed"; export const TELEMETRY_SECRET_OPERATIONS_KEY = "telemetry-secret-operations"; export const POSTHOG_AGGREGATED_EVENTS = [PostHogEventTypes.SecretPulled]; -const TELEMETRY_AGGREGATED_KEY_EXP = 900; // 15mins +const TELEMETRY_AGGREGATED_KEY_EXP = 600; // 10mins // Bucket configuration const TELEMETRY_BUCKET_COUNT = 30; @@ -102,13 +102,6 @@ To opt into telemetry, you can set "TELEMETRY_ENABLED=true" within the environme const instanceType = licenseService.getInstanceType(); // capture posthog only when its cloud or signup event happens in self-hosted if (instanceType === InstanceType.Cloud || event.event === PostHogEventTypes.UserSignedUp) { - if (event.organizationId) { - try { - postHog.groupIdentify({ groupType: "organization", groupKey: event.organizationId }); - } catch (error) { - logger.error(error, "Failed to identify PostHog organization"); - } - } if (POSTHOG_AGGREGATED_EVENTS.includes(event.event)) { const eventKey = createTelemetryEventKey(event.event, event.distinctId); await keyStore.setItemWithExpiry( @@ -122,6 +115,13 @@ To opt into telemetry, you can set "TELEMETRY_ENABLED=true" within the environme }) ); } else { + if (event.organizationId) { + try { + postHog.groupIdentify({ groupType: "organization", groupKey: event.organizationId }); + } catch (error) { + logger.error(error, "Failed to identify PostHog organization"); + } + } postHog.capture({ event: event.event, distinctId: event.distinctId, diff --git a/cli/detect/cmd/scm/scm.go b/cli/detect/cmd/scm/scm.go index 66868aadc..dddeffdf5 100644 --- a/cli/detect/cmd/scm/scm.go +++ b/cli/detect/cmd/scm/scm.go @@ -35,6 +35,7 @@ const ( GitHubPlatform GitLabPlatform AzureDevOpsPlatform + BitBucketPlatform // TODO: Add others. ) @@ -45,6 +46,7 @@ func (p Platform) String() string { "github", "gitlab", "azuredevops", + "bitbucket", }[p] } @@ -60,6 +62,8 @@ func PlatformFromString(s string) (Platform, error) { return GitLabPlatform, nil case "azuredevops": return AzureDevOpsPlatform, nil + case "bitbucket": + return BitBucketPlatform, nil default: return UnknownPlatform, fmt.Errorf("invalid scm platform value: %s", s) } diff --git a/cli/detect/git.go b/cli/detect/git.go index ddde0757d..83ed8a853 100644 --- a/cli/detect/git.go +++ b/cli/detect/git.go @@ -208,6 +208,8 @@ func platformFromHost(u *url.URL) scm.Platform { return scm.GitLabPlatform case "dev.azure.com", "visualstudio.com": return scm.AzureDevOpsPlatform + case "bitbucket.org": + return scm.BitBucketPlatform default: return scm.UnknownPlatform } diff --git a/cli/detect/utils.go b/cli/detect/utils.go index 255d01fbe..84b1017fc 100644 --- a/cli/detect/utils.go +++ b/cli/detect/utils.go @@ -112,6 +112,15 @@ func createScmLink(scmPlatform scm.Platform, remoteUrl string, finding report.Fi // This is a bit dirty, but Azure DevOps does not highlight the line when the lineStartColumn and lineEndColumn are not provided link += "&lineStartColumn=1&lineEndColumn=10000000&type=2&lineStyle=plain&_a=files" return link + case scm.BitBucketPlatform: + link := fmt.Sprintf("%s/src/%s/%s", remoteUrl, finding.Commit, filePath) + if finding.StartLine != 0 { + link += fmt.Sprintf("#lines-%d", finding.StartLine) + } + if finding.EndLine != finding.StartLine { + link += fmt.Sprintf(":%d", finding.EndLine) + } + return link default: // This should never happen. return "" diff --git a/cli/packages/cmd/scan.go b/cli/packages/cmd/scan.go index 42ff0f1e1..4a721d2c5 100644 --- a/cli/packages/cmd/scan.go +++ b/cli/packages/cmd/scan.go @@ -337,9 +337,7 @@ var scanCmd = &cobra.Command{ if gitCmd, err = sources.NewGitLogCmd(source, logOpts); err != nil { logging.Fatal().Err(err).Msg("could not create Git cmd") } - if scmPlatform, err = scm.PlatformFromString("github"); err != nil { - logging.Fatal().Err(err).Send() - } + scmPlatform = scm.UnknownPlatform remote = detect.NewRemoteInfo(scmPlatform, source) if findings, err = detector.DetectGit(gitCmd, remote); err != nil { diff --git a/docs/api-reference/endpoints/organizations/ldap-sso/create-ldap-config.mdx b/docs/api-reference/endpoints/organizations/ldap-sso/create-ldap-config.mdx new file mode 100644 index 000000000..3edabd366 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/ldap-sso/create-ldap-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Create LDAP SSO Config" +openapi: "POST /api/v1/ldap/config" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/organizations/ldap-sso/get-ldap-config.mdx b/docs/api-reference/endpoints/organizations/ldap-sso/get-ldap-config.mdx new file mode 100644 index 000000000..a41669384 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/ldap-sso/get-ldap-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Get LDAP SSO Config" +openapi: "GET /api/v1/ldap/config" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/organizations/ldap-sso/update-ldap-config.mdx b/docs/api-reference/endpoints/organizations/ldap-sso/update-ldap-config.mdx new file mode 100644 index 000000000..ab613728a --- /dev/null +++ b/docs/api-reference/endpoints/organizations/ldap-sso/update-ldap-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Update LDAP SSO Config" +openapi: "PATCH /api/v1/ldap/config" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/organizations/oidc-sso/create-oidc-config.mdx b/docs/api-reference/endpoints/organizations/oidc-sso/create-oidc-config.mdx new file mode 100644 index 000000000..6a86d970c --- /dev/null +++ b/docs/api-reference/endpoints/organizations/oidc-sso/create-oidc-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Create OIDC Config" +openapi: "POST /api/v1/sso/oidc/config" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/organizations/oidc-sso/get-oidc-config.mdx b/docs/api-reference/endpoints/organizations/oidc-sso/get-oidc-config.mdx new file mode 100644 index 000000000..af62c7d0a --- /dev/null +++ b/docs/api-reference/endpoints/organizations/oidc-sso/get-oidc-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Get OIDC Config" +openapi: "GET /api/v1/sso/oidc/config" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/organizations/oidc-sso/update-oidc-config.mdx b/docs/api-reference/endpoints/organizations/oidc-sso/update-oidc-config.mdx new file mode 100644 index 000000000..fdafeaf99 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/oidc-sso/update-oidc-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Update OIDC Config" +openapi: "PATCH /api/v1/sso/oidc/config" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/organizations/saml-sso/create-saml-config.mdx b/docs/api-reference/endpoints/organizations/saml-sso/create-saml-config.mdx new file mode 100644 index 000000000..0a01fb742 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/saml-sso/create-saml-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Create SAML SSO Config" +openapi: "POST /api/v1/sso/config" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/organizations/saml-sso/get-saml-config.mdx b/docs/api-reference/endpoints/organizations/saml-sso/get-saml-config.mdx new file mode 100644 index 000000000..71c00fb24 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/saml-sso/get-saml-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Get SAML SSO Config" +openapi: "GET /api/v1/sso/config" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/organizations/saml-sso/update-saml-config.mdx b/docs/api-reference/endpoints/organizations/saml-sso/update-saml-config.mdx new file mode 100644 index 000000000..57067dbd1 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/saml-sso/update-saml-config.mdx @@ -0,0 +1,4 @@ +--- +title: "Update SAML SSO Config" +openapi: "PATCH /api/v1/sso/config" +--- \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index 3b337fdc6..94046ad02 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -853,6 +853,30 @@ { "group": "Organizations", "pages": [ + { + "group": "OIDC SSO", + "pages": [ + "api-reference/endpoints/organizations/oidc-sso/get-oidc-config", + "api-reference/endpoints/organizations/oidc-sso/update-oidc-config", + "api-reference/endpoints/organizations/oidc-sso/create-oidc-config" + ] + }, + { + "group": "LDAP SSO", + "pages": [ + "api-reference/endpoints/organizations/ldap-sso/get-ldap-config", + "api-reference/endpoints/organizations/ldap-sso/update-ldap-config", + "api-reference/endpoints/organizations/ldap-sso/create-ldap-config" + ] + }, + { + "group": "SAML SSO", + "pages": [ + "api-reference/endpoints/organizations/saml-sso/get-saml-config", + "api-reference/endpoints/organizations/saml-sso/update-saml-config", + "api-reference/endpoints/organizations/saml-sso/create-saml-config" + ] + }, "api-reference/endpoints/organizations/memberships", "api-reference/endpoints/organizations/update-membership", "api-reference/endpoints/organizations/delete-membership", diff --git a/frontend/src/components/v2/ContentLoader/ContentLoader.tsx b/frontend/src/components/v2/ContentLoader/ContentLoader.tsx index 3254dd9ff..f60668aec 100644 --- a/frontend/src/components/v2/ContentLoader/ContentLoader.tsx +++ b/frontend/src/components/v2/ContentLoader/ContentLoader.tsx @@ -33,7 +33,7 @@ export const ContentLoader = ({ text, frequency = 2000, className }: Props) => { className )} > - + {text && isTextArray && ( {children} - - {content} - - + + + {content} + + + ) : ( // eslint-disable-next-line react/jsx-no-useless-fragment diff --git a/frontend/src/hooks/api/oidcConfig/mutations.tsx b/frontend/src/hooks/api/oidcConfig/mutations.tsx index 4cf4ede93..2150a17bc 100644 --- a/frontend/src/hooks/api/oidcConfig/mutations.tsx +++ b/frontend/src/hooks/api/oidcConfig/mutations.tsx @@ -21,7 +21,7 @@ export const useUpdateOIDCConfig = () => { clientId, clientSecret, isActive, - orgSlug, + organizationId, manageGroupMemberships, jwtSignatureAlgorithm }: { @@ -36,7 +36,7 @@ export const useUpdateOIDCConfig = () => { clientSecret?: string; isActive?: boolean; configurationType?: string; - orgSlug: string; + organizationId: string; manageGroupMemberships?: boolean; jwtSignatureAlgorithm?: OIDCJWTSignatureAlgorithm; }) => { @@ -50,7 +50,7 @@ export const useUpdateOIDCConfig = () => { tokenEndpoint, userinfoEndpoint, clientId, - orgSlug, + organizationId, clientSecret, isActive, manageGroupMemberships, @@ -60,7 +60,7 @@ export const useUpdateOIDCConfig = () => { return data; }, onSuccess(_, dto) { - queryClient.invalidateQueries({ queryKey: oidcConfigKeys.getOIDCConfig(dto.orgSlug) }); + queryClient.invalidateQueries({ queryKey: oidcConfigKeys.getOIDCConfig(dto.organizationId) }); queryClient.invalidateQueries({ queryKey: organizationKeys.getUserOrganizations }); } }); @@ -81,7 +81,7 @@ export const useCreateOIDCConfig = () => { clientId, clientSecret, isActive, - orgSlug, + organizationId, manageGroupMemberships, jwtSignatureAlgorithm }: { @@ -95,7 +95,7 @@ export const useCreateOIDCConfig = () => { clientId: string; clientSecret: string; isActive: boolean; - orgSlug: string; + organizationId: string; allowedEmailDomains?: string; manageGroupMemberships?: boolean; jwtSignatureAlgorithm?: OIDCJWTSignatureAlgorithm; @@ -112,7 +112,7 @@ export const useCreateOIDCConfig = () => { clientId, clientSecret, isActive, - orgSlug, + organizationId, manageGroupMemberships, jwtSignatureAlgorithm }); @@ -120,7 +120,7 @@ export const useCreateOIDCConfig = () => { return data; }, onSuccess(_, dto) { - queryClient.invalidateQueries({ queryKey: oidcConfigKeys.getOIDCConfig(dto.orgSlug) }); + queryClient.invalidateQueries({ queryKey: oidcConfigKeys.getOIDCConfig(dto.organizationId) }); } }); }; diff --git a/frontend/src/hooks/api/oidcConfig/queries.tsx b/frontend/src/hooks/api/oidcConfig/queries.tsx index 38c939520..b9ee943f7 100644 --- a/frontend/src/hooks/api/oidcConfig/queries.tsx +++ b/frontend/src/hooks/api/oidcConfig/queries.tsx @@ -5,18 +5,18 @@ import { apiRequest } from "@app/config/request"; import { OIDCConfigData } from "./types"; export const oidcConfigKeys = { - getOIDCConfig: (orgSlug: string) => [{ orgSlug }, "organization-oidc"] as const, + getOIDCConfig: (orgId: string) => [{ orgId }, "organization-oidc"] as const, getOIDCManageGroupMembershipsEnabled: (orgId: string) => ["oidc-manage-group-memberships", orgId] as const }; -export const useGetOIDCConfig = (orgSlug: string) => { +export const useGetOIDCConfig = (orgId: string) => { return useQuery({ - queryKey: oidcConfigKeys.getOIDCConfig(orgSlug), + queryKey: oidcConfigKeys.getOIDCConfig(orgId), queryFn: async () => { try { const { data } = await apiRequest.get( - `/api/v1/sso/oidc/config?orgSlug=${orgSlug}` + `/api/v1/sso/oidc/config?organizationId=${orgId}` ); return data; diff --git a/frontend/src/layouts/ProjectLayout/components/ProjectSelect/ProjectSelect.tsx b/frontend/src/layouts/ProjectLayout/components/ProjectSelect/ProjectSelect.tsx index 1efcf3939..d4c7a3f56 100644 --- a/frontend/src/layouts/ProjectLayout/components/ProjectSelect/ProjectSelect.tsx +++ b/frontend/src/layouts/ProjectLayout/components/ProjectSelect/ProjectSelect.tsx @@ -113,7 +113,7 @@ export const ProjectSelect = () => {
- +
{currentWorkspace?.name}
@@ -176,7 +176,7 @@ export const ProjectSelect = () => { >
- +
{workspace.name}
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index c2c54be08..e99210352 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -63,7 +63,7 @@ const router = createRouter({ context: { serverConfig: null, queryClient }, defaultPendingComponent: () => (
- +
), defaultNotFoundComponent: NotFoundPage, diff --git a/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OIDCModal.tsx b/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OIDCModal.tsx index 52df20285..03f946ace 100644 --- a/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OIDCModal.tsx +++ b/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OIDCModal.tsx @@ -105,7 +105,7 @@ export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle, hideDele const { mutateAsync: updateMutateAsync, isPending: updateIsLoading } = useUpdateOIDCConfig(); const [isDeletePopupOpen, setIsDeletePopupOpen] = useToggle(false); - const { data } = useGetOIDCConfig(currentOrg?.slug ?? ""); + const { data } = useGetOIDCConfig(currentOrg?.id ?? ""); const { control, handleSubmit, reset, setValue, watch } = useForm({ resolver: zodResolver(schema), @@ -134,7 +134,7 @@ export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle, hideDele clientId: "", clientSecret: "", isActive: false, - orgSlug: currentOrg.slug + organizationId: currentOrg.id }); createNotification({ @@ -196,7 +196,7 @@ export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle, hideDele clientId, clientSecret, isActive: true, - orgSlug: currentOrg.slug, + organizationId: currentOrg.id, jwtSignatureAlgorithm }); } else { @@ -212,7 +212,7 @@ export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle, hideDele clientId, clientSecret, isActive: true, - orgSlug: currentOrg.slug, + organizationId: currentOrg.id, jwtSignatureAlgorithm }); } diff --git a/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OrgOIDCSection.tsx b/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OrgOIDCSection.tsx index 8d5021d53..3956ba894 100644 --- a/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OrgOIDCSection.tsx +++ b/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OrgOIDCSection.tsx @@ -21,7 +21,7 @@ export const OrgOIDCSection = (): JSX.Element => { const { currentOrg } = useOrganization(); const { subscription } = useSubscription(); - const { data, isPending } = useGetOIDCConfig(currentOrg?.slug ?? ""); + const { data, isPending } = useGetOIDCConfig(currentOrg?.id ?? ""); const { mutateAsync } = useUpdateOIDCConfig(); const { mutateAsync: updateOrg } = useUpdateOrg(); @@ -41,7 +41,7 @@ export const OrgOIDCSection = (): JSX.Element => { } await mutateAsync({ - orgSlug: currentOrg?.slug, + organizationId: currentOrg?.id, isActive: value }); @@ -114,7 +114,7 @@ export const OrgOIDCSection = (): JSX.Element => { } await mutateAsync({ - orgSlug: currentOrg?.slug, + organizationId: currentOrg?.id, manageGroupMemberships: value }); diff --git a/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OrgSsoTab.tsx b/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OrgSsoTab.tsx index ca27b7517..9b11c1302 100644 --- a/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OrgSsoTab.tsx +++ b/frontend/src/pages/organization/SsoPage/components/OrgSsoTab/OrgSsoTab.tsx @@ -38,7 +38,7 @@ export const OrgSsoTab = withPermission( const { subscription } = useSubscription(); const { data: oidcConfig, isPending: isLoadingOidcConfig } = useGetOIDCConfig( - currentOrg?.slug ?? "" + currentOrg?.id ?? "" ); const { data: samlConfig, isPending: isLoadingSamlConfig } = useGetSSOConfig( currentOrg?.id ?? "" diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx index 255196f86..f58edbd33 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx @@ -891,7 +891,7 @@ export const OverviewPage = () => { if (isProjectV3 && visibleEnvs.length > 0 && isOverviewLoading) { return (
- +
); } diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretDropzone/SecretDropzone.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretDropzone/SecretDropzone.tsx index 56d075445..017604fc4 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretDropzone/SecretDropzone.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretDropzone/SecretDropzone.tsx @@ -253,7 +253,7 @@ export const SecretDropzone = ({ > {isLoading ? (
- +
) : (