mirror of
https://github.com/Infisical/infisical.git
synced 2025-07-22 13:29:55 +00:00
Compare commits
6 Commits
daniel/fix
...
daniel/sso
Author | SHA1 | Date | |
---|---|---|---|
f903e5b3d4 | |||
c6f8915d3f | |||
65b1354ef1 | |||
cda8579ca4 | |||
13d2cbd8b0 | |||
abfc5736fd |
@ -17,6 +17,7 @@ import { z } from "zod";
|
|||||||
import { LdapGroupMapsSchema } from "@app/db/schemas";
|
import { LdapGroupMapsSchema } from "@app/db/schemas";
|
||||||
import { TLDAPConfig } from "@app/ee/services/ldap-config/ldap-config-types";
|
import { TLDAPConfig } from "@app/ee/services/ldap-config/ldap-config-types";
|
||||||
import { isValidLdapFilter, searchGroups } from "@app/ee/services/ldap-config/ldap-fns";
|
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 { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
@ -132,10 +133,18 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.LdapSso],
|
||||||
|
description: "Get LDAP config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
organizationId: z.string().trim()
|
organizationId: z.string().trim().describe(LdapSso.GET_CONFIG.organizationId)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@ -172,23 +181,32 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.LdapSso],
|
||||||
|
description: "Create LDAP config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
body: z.object({
|
body: z.object({
|
||||||
organizationId: z.string().trim(),
|
organizationId: z.string().trim().describe(LdapSso.CREATE_CONFIG.organizationId),
|
||||||
isActive: z.boolean(),
|
isActive: z.boolean().describe(LdapSso.CREATE_CONFIG.isActive),
|
||||||
url: z.string().trim(),
|
url: z.string().trim().describe(LdapSso.CREATE_CONFIG.url),
|
||||||
bindDN: z.string().trim(),
|
bindDN: z.string().trim().describe(LdapSso.CREATE_CONFIG.bindDN),
|
||||||
bindPass: z.string().trim(),
|
bindPass: z.string().trim().describe(LdapSso.CREATE_CONFIG.bindPass),
|
||||||
uniqueUserAttribute: z.string().trim().default("uidNumber"),
|
uniqueUserAttribute: z.string().trim().default("uidNumber").describe(LdapSso.CREATE_CONFIG.uniqueUserAttribute),
|
||||||
searchBase: z.string().trim(),
|
searchBase: z.string().trim().describe(LdapSso.CREATE_CONFIG.searchBase),
|
||||||
searchFilter: z.string().trim().default("(uid={{username}})"),
|
searchFilter: z.string().trim().default("(uid={{username}})").describe(LdapSso.CREATE_CONFIG.searchFilter),
|
||||||
groupSearchBase: z.string().trim(),
|
groupSearchBase: z.string().trim().describe(LdapSso.CREATE_CONFIG.groupSearchBase),
|
||||||
groupSearchFilter: z
|
groupSearchFilter: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.default("(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))"),
|
.default("(|(memberUid={{.Username}})(member={{.UserDN}})(uniqueMember={{.UserDN}}))")
|
||||||
caCert: z.string().trim().default("")
|
.describe(LdapSso.CREATE_CONFIG.groupSearchFilter),
|
||||||
|
caCert: z.string().trim().default("").describe(LdapSso.CREATE_CONFIG.caCert)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: SanitizedLdapConfigSchema
|
200: SanitizedLdapConfigSchema
|
||||||
@ -214,23 +232,31 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.LdapSso],
|
||||||
|
description: "Update LDAP config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
body: z
|
body: z
|
||||||
.object({
|
.object({
|
||||||
isActive: z.boolean(),
|
isActive: z.boolean().describe(LdapSso.UPDATE_CONFIG.isActive),
|
||||||
url: z.string().trim(),
|
url: z.string().trim().describe(LdapSso.UPDATE_CONFIG.url),
|
||||||
bindDN: z.string().trim(),
|
bindDN: z.string().trim().describe(LdapSso.UPDATE_CONFIG.bindDN),
|
||||||
bindPass: z.string().trim(),
|
bindPass: z.string().trim().describe(LdapSso.UPDATE_CONFIG.bindPass),
|
||||||
uniqueUserAttribute: z.string().trim(),
|
uniqueUserAttribute: z.string().trim().describe(LdapSso.UPDATE_CONFIG.uniqueUserAttribute),
|
||||||
searchBase: z.string().trim(),
|
searchBase: z.string().trim().describe(LdapSso.UPDATE_CONFIG.searchBase),
|
||||||
searchFilter: z.string().trim(),
|
searchFilter: z.string().trim().describe(LdapSso.UPDATE_CONFIG.searchFilter),
|
||||||
groupSearchBase: z.string().trim(),
|
groupSearchBase: z.string().trim().describe(LdapSso.UPDATE_CONFIG.groupSearchBase),
|
||||||
groupSearchFilter: z.string().trim(),
|
groupSearchFilter: z.string().trim().describe(LdapSso.UPDATE_CONFIG.groupSearchFilter),
|
||||||
caCert: z.string().trim()
|
caCert: z.string().trim().describe(LdapSso.UPDATE_CONFIG.caCert)
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.merge(z.object({ organizationId: z.string() })),
|
.merge(z.object({ organizationId: z.string().trim().describe(LdapSso.UPDATE_CONFIG.organizationId) })),
|
||||||
response: {
|
response: {
|
||||||
200: SanitizedLdapConfigSchema
|
200: SanitizedLdapConfigSchema
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { OidcConfigsSchema } from "@app/db/schemas";
|
import { OidcConfigsSchema } from "@app/db/schemas";
|
||||||
import { OIDCConfigurationType, OIDCJWTSignatureAlgorithm } from "@app/ee/services/oidc/oidc-config-types";
|
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 { getConfig } from "@app/lib/config/env";
|
||||||
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@ -153,10 +154,18 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.OidcSso],
|
||||||
|
description: "Get OIDC config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
orgSlug: z.string().trim()
|
organizationId: z.string().trim().describe(OidcSSo.GET_CONFIG.organizationId)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: SanitizedOidcConfigSchema.pick({
|
200: SanitizedOidcConfigSchema.pick({
|
||||||
@ -180,9 +189,8 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { orgSlug } = req.query;
|
|
||||||
const oidc = await server.services.oidc.getOidc({
|
const oidc = await server.services.oidc.getOidc({
|
||||||
orgSlug,
|
organizationId: req.query.organizationId,
|
||||||
type: "external",
|
type: "external",
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@ -200,8 +208,16 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.OidcSso],
|
||||||
|
description: "Update OIDC config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
body: z
|
body: z
|
||||||
.object({
|
.object({
|
||||||
allowedEmailDomains: z
|
allowedEmailDomains: z
|
||||||
@ -216,22 +232,26 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
.split(",")
|
.split(",")
|
||||||
.map((id) => id.trim())
|
.map((id) => id.trim())
|
||||||
.join(", ");
|
.join(", ");
|
||||||
}),
|
})
|
||||||
discoveryURL: z.string().trim(),
|
.describe(OidcSSo.UPDATE_CONFIG.allowedEmailDomains),
|
||||||
configurationType: z.nativeEnum(OIDCConfigurationType),
|
discoveryURL: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.discoveryURL),
|
||||||
issuer: z.string().trim(),
|
configurationType: z.nativeEnum(OIDCConfigurationType).describe(OidcSSo.UPDATE_CONFIG.configurationType),
|
||||||
authorizationEndpoint: z.string().trim(),
|
issuer: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.issuer),
|
||||||
jwksUri: z.string().trim(),
|
authorizationEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.authorizationEndpoint),
|
||||||
tokenEndpoint: z.string().trim(),
|
jwksUri: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.jwksUri),
|
||||||
userinfoEndpoint: z.string().trim(),
|
tokenEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.tokenEndpoint),
|
||||||
clientId: z.string().trim(),
|
userinfoEndpoint: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.userinfoEndpoint),
|
||||||
clientSecret: z.string().trim(),
|
clientId: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.clientId),
|
||||||
isActive: z.boolean(),
|
clientSecret: z.string().trim().describe(OidcSSo.UPDATE_CONFIG.clientSecret),
|
||||||
manageGroupMemberships: z.boolean().optional(),
|
isActive: z.boolean().describe(OidcSSo.UPDATE_CONFIG.isActive),
|
||||||
jwtSignatureAlgorithm: z.nativeEnum(OIDCJWTSignatureAlgorithm).optional()
|
manageGroupMemberships: z.boolean().optional().describe(OidcSSo.UPDATE_CONFIG.manageGroupMemberships),
|
||||||
|
jwtSignatureAlgorithm: z
|
||||||
|
.nativeEnum(OIDCJWTSignatureAlgorithm)
|
||||||
|
.optional()
|
||||||
|
.describe(OidcSSo.UPDATE_CONFIG.jwtSignatureAlgorithm)
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.merge(z.object({ orgSlug: z.string() })),
|
.merge(z.object({ organizationId: z.string().describe(OidcSSo.UPDATE_CONFIG.organizationId) })),
|
||||||
response: {
|
response: {
|
||||||
200: SanitizedOidcConfigSchema.pick({
|
200: SanitizedOidcConfigSchema.pick({
|
||||||
id: true,
|
id: true,
|
||||||
@ -267,8 +287,16 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.OidcSso],
|
||||||
|
description: "Create OIDC config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
body: z
|
body: z
|
||||||
.object({
|
.object({
|
||||||
allowedEmailDomains: z
|
allowedEmailDomains: z
|
||||||
@ -283,23 +311,34 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
.split(",")
|
.split(",")
|
||||||
.map((id) => id.trim())
|
.map((id) => id.trim())
|
||||||
.join(", ");
|
.join(", ");
|
||||||
}),
|
})
|
||||||
configurationType: z.nativeEnum(OIDCConfigurationType),
|
.describe(OidcSSo.CREATE_CONFIG.allowedEmailDomains),
|
||||||
issuer: z.string().trim().optional().default(""),
|
configurationType: z.nativeEnum(OIDCConfigurationType).describe(OidcSSo.CREATE_CONFIG.configurationType),
|
||||||
discoveryURL: z.string().trim().optional().default(""),
|
issuer: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.issuer),
|
||||||
authorizationEndpoint: z.string().trim().optional().default(""),
|
discoveryURL: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.discoveryURL),
|
||||||
jwksUri: z.string().trim().optional().default(""),
|
authorizationEndpoint: z
|
||||||
tokenEndpoint: z.string().trim().optional().default(""),
|
.string()
|
||||||
userinfoEndpoint: z.string().trim().optional().default(""),
|
.trim()
|
||||||
clientId: z.string().trim(),
|
.optional()
|
||||||
clientSecret: z.string().trim(),
|
.default("")
|
||||||
isActive: z.boolean(),
|
.describe(OidcSSo.CREATE_CONFIG.authorizationEndpoint),
|
||||||
orgSlug: z.string().trim(),
|
jwksUri: z.string().trim().optional().default("").describe(OidcSSo.CREATE_CONFIG.jwksUri),
|
||||||
manageGroupMemberships: z.boolean().optional().default(false),
|
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
|
jwtSignatureAlgorithm: z
|
||||||
.nativeEnum(OIDCJWTSignatureAlgorithm)
|
.nativeEnum(OIDCJWTSignatureAlgorithm)
|
||||||
.optional()
|
.optional()
|
||||||
.default(OIDCJWTSignatureAlgorithm.RS256)
|
.default(OIDCJWTSignatureAlgorithm.RS256)
|
||||||
|
.describe(OidcSSo.CREATE_CONFIG.jwtSignatureAlgorithm)
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
if (data.configurationType === OIDCConfigurationType.CUSTOM) {
|
if (data.configurationType === OIDCConfigurationType.CUSTOM) {
|
||||||
|
@ -13,6 +13,7 @@ import { FastifyRequest } from "fastify";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SamlProviders, TGetSamlCfgDTO } from "@app/ee/services/saml-config/saml-config-types";
|
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 { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
@ -149,8 +150,8 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
|||||||
firstName,
|
firstName,
|
||||||
lastName: lastName as string,
|
lastName: lastName as string,
|
||||||
relayState: (req.body as { RelayState?: string }).RelayState,
|
relayState: (req.body as { RelayState?: string }).RelayState,
|
||||||
authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider as string,
|
authProvider: (req as unknown as FastifyRequest).ssoConfig?.authProvider,
|
||||||
orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId as string,
|
orgId: (req as unknown as FastifyRequest).ssoConfig?.orgId,
|
||||||
metadata: userMetadata
|
metadata: userMetadata
|
||||||
});
|
});
|
||||||
cb(null, { isUserCompleted, providerAuthToken });
|
cb(null, { isUserCompleted, providerAuthToken });
|
||||||
@ -262,25 +263,31 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SamlSso],
|
||||||
|
description: "Get SAML config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
organizationId: z.string().trim()
|
organizationId: z.string().trim().describe(SamlSso.GET_CONFIG.organizationId)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z
|
200: z.object({
|
||||||
.object({
|
id: z.string(),
|
||||||
id: z.string(),
|
organization: z.string(),
|
||||||
organization: z.string(),
|
orgId: z.string(),
|
||||||
orgId: z.string(),
|
authProvider: z.string(),
|
||||||
authProvider: z.string(),
|
isActive: z.boolean(),
|
||||||
isActive: z.boolean(),
|
entryPoint: z.string(),
|
||||||
entryPoint: z.string(),
|
issuer: z.string(),
|
||||||
issuer: z.string(),
|
cert: z.string(),
|
||||||
cert: z.string(),
|
lastUsed: z.date().nullable().optional()
|
||||||
lastUsed: z.date().nullable().optional()
|
})
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
@ -302,15 +309,23 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SamlSso],
|
||||||
|
description: "Create SAML config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
body: z.object({
|
body: z.object({
|
||||||
organizationId: z.string(),
|
organizationId: z.string().trim().describe(SamlSso.CREATE_CONFIG.organizationId),
|
||||||
authProvider: z.nativeEnum(SamlProviders),
|
authProvider: z.nativeEnum(SamlProviders).describe(SamlSso.CREATE_CONFIG.authProvider),
|
||||||
isActive: z.boolean(),
|
isActive: z.boolean().describe(SamlSso.CREATE_CONFIG.isActive),
|
||||||
entryPoint: z.string(),
|
entryPoint: z.string().trim().describe(SamlSso.CREATE_CONFIG.entryPoint),
|
||||||
issuer: z.string(),
|
issuer: z.string().trim().describe(SamlSso.CREATE_CONFIG.issuer),
|
||||||
cert: z.string()
|
cert: z.string().trim().describe(SamlSso.CREATE_CONFIG.cert)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: SanitizedSamlConfigSchema
|
200: SanitizedSamlConfigSchema
|
||||||
@ -341,18 +356,26 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
|||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SamlSso],
|
||||||
|
description: "Update SAML config",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
body: z
|
body: z
|
||||||
.object({
|
.object({
|
||||||
authProvider: z.nativeEnum(SamlProviders),
|
authProvider: z.nativeEnum(SamlProviders).describe(SamlSso.UPDATE_CONFIG.authProvider),
|
||||||
isActive: z.boolean(),
|
isActive: z.boolean().describe(SamlSso.UPDATE_CONFIG.isActive),
|
||||||
entryPoint: z.string(),
|
entryPoint: z.string().trim().describe(SamlSso.UPDATE_CONFIG.entryPoint),
|
||||||
issuer: z.string(),
|
issuer: z.string().trim().describe(SamlSso.UPDATE_CONFIG.issuer),
|
||||||
cert: z.string()
|
cert: z.string().trim().describe(SamlSso.UPDATE_CONFIG.cert)
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.merge(z.object({ organizationId: z.string() })),
|
.merge(z.object({ organizationId: z.string().trim().describe(SamlSso.UPDATE_CONFIG.organizationId) })),
|
||||||
response: {
|
response: {
|
||||||
200: SanitizedSamlConfigSchema
|
200: SanitizedSamlConfigSchema
|
||||||
}
|
}
|
||||||
|
@ -107,34 +107,26 @@ export const oidcConfigServiceFactory = ({
|
|||||||
kmsService
|
kmsService
|
||||||
}: TOidcConfigServiceFactoryDep) => {
|
}: TOidcConfigServiceFactoryDep) => {
|
||||||
const getOidc = async (dto: TGetOidcCfgDTO) => {
|
const getOidc = async (dto: TGetOidcCfgDTO) => {
|
||||||
const org = await orgDAL.findOne({ slug: dto.orgSlug });
|
const oidcCfg = await oidcConfigDAL.findOne({
|
||||||
if (!org) {
|
orgId: dto.organizationId
|
||||||
|
});
|
||||||
|
if (!oidcCfg) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with slug '${dto.orgSlug}' not found`,
|
message: `OIDC configuration for organization with ID '${dto.organizationId}' not found`
|
||||||
name: "OrgNotFound"
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dto.type === "external") {
|
if (dto.type === "external") {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
dto.actor,
|
dto.actor,
|
||||||
dto.actorId,
|
dto.actorId,
|
||||||
org.id,
|
dto.organizationId,
|
||||||
dto.actorAuthMethod,
|
dto.actorAuthMethod,
|
||||||
dto.actorOrgId
|
dto.actorOrgId
|
||||||
);
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
|
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({
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.Organization,
|
type: KmsDataKey.Organization,
|
||||||
orgId: oidcCfg.orgId
|
orgId: oidcCfg.orgId
|
||||||
@ -465,7 +457,7 @@ export const oidcConfigServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateOidcCfg = async ({
|
const updateOidcCfg = async ({
|
||||||
orgSlug,
|
organizationId,
|
||||||
allowedEmailDomains,
|
allowedEmailDomains,
|
||||||
configurationType,
|
configurationType,
|
||||||
discoveryURL,
|
discoveryURL,
|
||||||
@ -484,13 +476,11 @@ export const oidcConfigServiceFactory = ({
|
|||||||
manageGroupMemberships,
|
manageGroupMemberships,
|
||||||
jwtSignatureAlgorithm
|
jwtSignatureAlgorithm
|
||||||
}: TUpdateOidcCfgDTO) => {
|
}: TUpdateOidcCfgDTO) => {
|
||||||
const org = await orgDAL.findOne({
|
const org = await orgDAL.findOne({ id: organizationId });
|
||||||
slug: orgSlug
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!org) {
|
if (!org) {
|
||||||
throw new NotFoundError({
|
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 ({
|
const createOidcCfg = async ({
|
||||||
orgSlug,
|
organizationId,
|
||||||
allowedEmailDomains,
|
allowedEmailDomains,
|
||||||
configurationType,
|
configurationType,
|
||||||
discoveryURL,
|
discoveryURL,
|
||||||
@ -574,12 +564,10 @@ export const oidcConfigServiceFactory = ({
|
|||||||
manageGroupMemberships,
|
manageGroupMemberships,
|
||||||
jwtSignatureAlgorithm
|
jwtSignatureAlgorithm
|
||||||
}: TCreateOidcCfgDTO) => {
|
}: TCreateOidcCfgDTO) => {
|
||||||
const org = await orgDAL.findOne({
|
const org = await orgDAL.findOne({ id: organizationId });
|
||||||
slug: orgSlug
|
|
||||||
});
|
|
||||||
if (!org) {
|
if (!org) {
|
||||||
throw new NotFoundError({
|
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({
|
const oidcCfg = await getOidc({
|
||||||
type: "internal",
|
type: "internal",
|
||||||
orgSlug
|
organizationId: org.id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!oidcCfg || !oidcCfg.isActive) {
|
if (!oidcCfg || !oidcCfg.isActive) {
|
||||||
|
@ -26,11 +26,11 @@ export type TOidcLoginDTO = {
|
|||||||
export type TGetOidcCfgDTO =
|
export type TGetOidcCfgDTO =
|
||||||
| ({
|
| ({
|
||||||
type: "external";
|
type: "external";
|
||||||
orgSlug: string;
|
organizationId: string;
|
||||||
} & TGenericPermission)
|
} & TGenericPermission)
|
||||||
| {
|
| {
|
||||||
type: "internal";
|
type: "internal";
|
||||||
orgSlug: string;
|
organizationId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCreateOidcCfgDTO = {
|
export type TCreateOidcCfgDTO = {
|
||||||
@ -45,7 +45,7 @@ export type TCreateOidcCfgDTO = {
|
|||||||
clientId: string;
|
clientId: string;
|
||||||
clientSecret: string;
|
clientSecret: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
orgSlug: string;
|
organizationId: string;
|
||||||
manageGroupMemberships: boolean;
|
manageGroupMemberships: boolean;
|
||||||
jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm;
|
jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm;
|
||||||
} & TGenericPermission;
|
} & TGenericPermission;
|
||||||
@ -62,7 +62,7 @@ export type TUpdateOidcCfgDTO = Partial<{
|
|||||||
clientId: string;
|
clientId: string;
|
||||||
clientSecret: string;
|
clientSecret: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
orgSlug: string;
|
organizationId: string;
|
||||||
manageGroupMemberships: boolean;
|
manageGroupMemberships: boolean;
|
||||||
jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm;
|
jwtSignatureAlgorithm: OIDCJWTSignatureAlgorithm;
|
||||||
}> &
|
}> &
|
||||||
|
@ -148,10 +148,18 @@ export const samlConfigServiceFactory = ({
|
|||||||
let samlConfig: TSamlConfigs | undefined;
|
let samlConfig: TSamlConfigs | undefined;
|
||||||
if (dto.type === "org") {
|
if (dto.type === "org") {
|
||||||
samlConfig = await samlConfigDAL.findOne({ orgId: dto.orgId });
|
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") {
|
} else if (dto.type === "orgSlug") {
|
||||||
const org = await orgDAL.findOne({ slug: dto.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 });
|
samlConfig = await samlConfigDAL.findOne({ orgId: org.id });
|
||||||
} else if (dto.type === "ssoId") {
|
} else if (dto.type === "ssoId") {
|
||||||
// TODO:
|
// TODO:
|
||||||
|
@ -61,20 +61,17 @@ export type TSamlLoginDTO = {
|
|||||||
export type TSamlConfigServiceFactory = {
|
export type TSamlConfigServiceFactory = {
|
||||||
createSamlCfg: (arg: TCreateSamlCfgDTO) => Promise<TSamlConfigs>;
|
createSamlCfg: (arg: TCreateSamlCfgDTO) => Promise<TSamlConfigs>;
|
||||||
updateSamlCfg: (arg: TUpdateSamlCfgDTO) => Promise<TSamlConfigs>;
|
updateSamlCfg: (arg: TUpdateSamlCfgDTO) => Promise<TSamlConfigs>;
|
||||||
getSaml: (arg: TGetSamlCfgDTO) => Promise<
|
getSaml: (arg: TGetSamlCfgDTO) => Promise<{
|
||||||
| {
|
id: string;
|
||||||
id: string;
|
organization: string;
|
||||||
organization: string;
|
orgId: string;
|
||||||
orgId: string;
|
authProvider: string;
|
||||||
authProvider: string;
|
isActive: boolean;
|
||||||
isActive: boolean;
|
entryPoint: string;
|
||||||
entryPoint: string;
|
issuer: string;
|
||||||
issuer: string;
|
cert: string;
|
||||||
cert: string;
|
lastUsed: Date | null | undefined;
|
||||||
lastUsed: Date | null | undefined;
|
}>;
|
||||||
}
|
|
||||||
| undefined
|
|
||||||
>;
|
|
||||||
samlLogin: (arg: TSamlLoginDTO) => Promise<{
|
samlLogin: (arg: TSamlLoginDTO) => Promise<{
|
||||||
isUserCompleted: boolean;
|
isUserCompleted: boolean;
|
||||||
providerAuthToken: string;
|
providerAuthToken: string;
|
||||||
|
@ -66,7 +66,10 @@ export enum ApiDocsTags {
|
|||||||
KmsKeys = "KMS Keys",
|
KmsKeys = "KMS Keys",
|
||||||
KmsEncryption = "KMS Encryption",
|
KmsEncryption = "KMS Encryption",
|
||||||
KmsSigning = "KMS Signing",
|
KmsSigning = "KMS Signing",
|
||||||
SecretScanning = "Secret Scanning"
|
SecretScanning = "Secret Scanning",
|
||||||
|
OidcSso = "OIDC SSO",
|
||||||
|
SamlSso = "SAML SSO",
|
||||||
|
LdapSso = "LDAP SSO"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GROUPS = {
|
export const GROUPS = {
|
||||||
@ -2650,3 +2653,113 @@ export const SecretScanningConfigs = {
|
|||||||
content: "The contents of the Secret Scanning Configuration file."
|
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."
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Create LDAP SSO Config"
|
||||||
|
openapi: "POST /api/v1/ldap/config"
|
||||||
|
---
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Get LDAP SSO Config"
|
||||||
|
openapi: "GET /api/v1/ldap/config"
|
||||||
|
---
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Update LDAP SSO Config"
|
||||||
|
openapi: "PATCH /api/v1/ldap/config"
|
||||||
|
---
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Create OIDC Config"
|
||||||
|
openapi: "POST /api/v1/sso/oidc/config"
|
||||||
|
---
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Get OIDC Config"
|
||||||
|
openapi: "GET /api/v1/sso/oidc/config"
|
||||||
|
---
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Update OIDC Config"
|
||||||
|
openapi: "PATCH /api/v1/sso/oidc/config"
|
||||||
|
---
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Create SAML SSO Config"
|
||||||
|
openapi: "POST /api/v1/sso/config"
|
||||||
|
---
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Get SAML SSO Config"
|
||||||
|
openapi: "GET /api/v1/sso/config"
|
||||||
|
---
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: "Update SAML SSO Config"
|
||||||
|
openapi: "PATCH /api/v1/sso/config"
|
||||||
|
---
|
@ -849,6 +849,30 @@
|
|||||||
{
|
{
|
||||||
"group": "Organizations",
|
"group": "Organizations",
|
||||||
"pages": [
|
"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/memberships",
|
||||||
"api-reference/endpoints/organizations/update-membership",
|
"api-reference/endpoints/organizations/update-membership",
|
||||||
"api-reference/endpoints/organizations/delete-membership",
|
"api-reference/endpoints/organizations/delete-membership",
|
||||||
|
@ -21,7 +21,7 @@ export const useUpdateOIDCConfig = () => {
|
|||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
isActive,
|
isActive,
|
||||||
orgSlug,
|
organizationId,
|
||||||
manageGroupMemberships,
|
manageGroupMemberships,
|
||||||
jwtSignatureAlgorithm
|
jwtSignatureAlgorithm
|
||||||
}: {
|
}: {
|
||||||
@ -36,7 +36,7 @@ export const useUpdateOIDCConfig = () => {
|
|||||||
clientSecret?: string;
|
clientSecret?: string;
|
||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
configurationType?: string;
|
configurationType?: string;
|
||||||
orgSlug: string;
|
organizationId: string;
|
||||||
manageGroupMemberships?: boolean;
|
manageGroupMemberships?: boolean;
|
||||||
jwtSignatureAlgorithm?: OIDCJWTSignatureAlgorithm;
|
jwtSignatureAlgorithm?: OIDCJWTSignatureAlgorithm;
|
||||||
}) => {
|
}) => {
|
||||||
@ -50,7 +50,7 @@ export const useUpdateOIDCConfig = () => {
|
|||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userinfoEndpoint,
|
userinfoEndpoint,
|
||||||
clientId,
|
clientId,
|
||||||
orgSlug,
|
organizationId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
isActive,
|
isActive,
|
||||||
manageGroupMemberships,
|
manageGroupMemberships,
|
||||||
@ -60,7 +60,7 @@ export const useUpdateOIDCConfig = () => {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess(_, dto) {
|
onSuccess(_, dto) {
|
||||||
queryClient.invalidateQueries({ queryKey: oidcConfigKeys.getOIDCConfig(dto.orgSlug) });
|
queryClient.invalidateQueries({ queryKey: oidcConfigKeys.getOIDCConfig(dto.organizationId) });
|
||||||
queryClient.invalidateQueries({ queryKey: organizationKeys.getUserOrganizations });
|
queryClient.invalidateQueries({ queryKey: organizationKeys.getUserOrganizations });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -81,7 +81,7 @@ export const useCreateOIDCConfig = () => {
|
|||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
isActive,
|
isActive,
|
||||||
orgSlug,
|
organizationId,
|
||||||
manageGroupMemberships,
|
manageGroupMemberships,
|
||||||
jwtSignatureAlgorithm
|
jwtSignatureAlgorithm
|
||||||
}: {
|
}: {
|
||||||
@ -95,7 +95,7 @@ export const useCreateOIDCConfig = () => {
|
|||||||
clientId: string;
|
clientId: string;
|
||||||
clientSecret: string;
|
clientSecret: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
orgSlug: string;
|
organizationId: string;
|
||||||
allowedEmailDomains?: string;
|
allowedEmailDomains?: string;
|
||||||
manageGroupMemberships?: boolean;
|
manageGroupMemberships?: boolean;
|
||||||
jwtSignatureAlgorithm?: OIDCJWTSignatureAlgorithm;
|
jwtSignatureAlgorithm?: OIDCJWTSignatureAlgorithm;
|
||||||
@ -112,7 +112,7 @@ export const useCreateOIDCConfig = () => {
|
|||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
isActive,
|
isActive,
|
||||||
orgSlug,
|
organizationId,
|
||||||
manageGroupMemberships,
|
manageGroupMemberships,
|
||||||
jwtSignatureAlgorithm
|
jwtSignatureAlgorithm
|
||||||
});
|
});
|
||||||
@ -120,7 +120,7 @@ export const useCreateOIDCConfig = () => {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess(_, dto) {
|
onSuccess(_, dto) {
|
||||||
queryClient.invalidateQueries({ queryKey: oidcConfigKeys.getOIDCConfig(dto.orgSlug) });
|
queryClient.invalidateQueries({ queryKey: oidcConfigKeys.getOIDCConfig(dto.organizationId) });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -5,18 +5,18 @@ import { apiRequest } from "@app/config/request";
|
|||||||
import { OIDCConfigData } from "./types";
|
import { OIDCConfigData } from "./types";
|
||||||
|
|
||||||
export const oidcConfigKeys = {
|
export const oidcConfigKeys = {
|
||||||
getOIDCConfig: (orgSlug: string) => [{ orgSlug }, "organization-oidc"] as const,
|
getOIDCConfig: (orgId: string) => [{ orgId }, "organization-oidc"] as const,
|
||||||
getOIDCManageGroupMembershipsEnabled: (orgId: string) =>
|
getOIDCManageGroupMembershipsEnabled: (orgId: string) =>
|
||||||
["oidc-manage-group-memberships", orgId] as const
|
["oidc-manage-group-memberships", orgId] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetOIDCConfig = (orgSlug: string) => {
|
export const useGetOIDCConfig = (orgId: string) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: oidcConfigKeys.getOIDCConfig(orgSlug),
|
queryKey: oidcConfigKeys.getOIDCConfig(orgId),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
try {
|
try {
|
||||||
const { data } = await apiRequest.get<OIDCConfigData>(
|
const { data } = await apiRequest.get<OIDCConfigData>(
|
||||||
`/api/v1/sso/oidc/config?orgSlug=${orgSlug}`
|
`/api/v1/sso/oidc/config?organizationId=${orgId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -105,7 +105,7 @@ export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle, hideDele
|
|||||||
const { mutateAsync: updateMutateAsync, isPending: updateIsLoading } = useUpdateOIDCConfig();
|
const { mutateAsync: updateMutateAsync, isPending: updateIsLoading } = useUpdateOIDCConfig();
|
||||||
const [isDeletePopupOpen, setIsDeletePopupOpen] = useToggle(false);
|
const [isDeletePopupOpen, setIsDeletePopupOpen] = useToggle(false);
|
||||||
|
|
||||||
const { data } = useGetOIDCConfig(currentOrg?.slug ?? "");
|
const { data } = useGetOIDCConfig(currentOrg?.id ?? "");
|
||||||
|
|
||||||
const { control, handleSubmit, reset, setValue, watch } = useForm<OIDCFormData>({
|
const { control, handleSubmit, reset, setValue, watch } = useForm<OIDCFormData>({
|
||||||
resolver: zodResolver(schema),
|
resolver: zodResolver(schema),
|
||||||
@ -134,7 +134,7 @@ export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle, hideDele
|
|||||||
clientId: "",
|
clientId: "",
|
||||||
clientSecret: "",
|
clientSecret: "",
|
||||||
isActive: false,
|
isActive: false,
|
||||||
orgSlug: currentOrg.slug
|
organizationId: currentOrg.id
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
@ -196,7 +196,7 @@ export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle, hideDele
|
|||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
orgSlug: currentOrg.slug,
|
organizationId: currentOrg.id,
|
||||||
jwtSignatureAlgorithm
|
jwtSignatureAlgorithm
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -212,7 +212,7 @@ export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle, hideDele
|
|||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
orgSlug: currentOrg.slug,
|
organizationId: currentOrg.id,
|
||||||
jwtSignatureAlgorithm
|
jwtSignatureAlgorithm
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ export const OrgOIDCSection = (): JSX.Element => {
|
|||||||
const { currentOrg } = useOrganization();
|
const { currentOrg } = useOrganization();
|
||||||
const { subscription } = useSubscription();
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
const { data, isPending } = useGetOIDCConfig(currentOrg?.slug ?? "");
|
const { data, isPending } = useGetOIDCConfig(currentOrg?.id ?? "");
|
||||||
const { mutateAsync } = useUpdateOIDCConfig();
|
const { mutateAsync } = useUpdateOIDCConfig();
|
||||||
const { mutateAsync: updateOrg } = useUpdateOrg();
|
const { mutateAsync: updateOrg } = useUpdateOrg();
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ export const OrgOIDCSection = (): JSX.Element => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
orgSlug: currentOrg?.slug,
|
organizationId: currentOrg?.id,
|
||||||
isActive: value
|
isActive: value
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ export const OrgOIDCSection = (): JSX.Element => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
orgSlug: currentOrg?.slug,
|
organizationId: currentOrg?.id,
|
||||||
manageGroupMemberships: value
|
manageGroupMemberships: value
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ export const OrgSsoTab = withPermission(
|
|||||||
const { subscription } = useSubscription();
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
const { data: oidcConfig, isPending: isLoadingOidcConfig } = useGetOIDCConfig(
|
const { data: oidcConfig, isPending: isLoadingOidcConfig } = useGetOIDCConfig(
|
||||||
currentOrg?.slug ?? ""
|
currentOrg?.id ?? ""
|
||||||
);
|
);
|
||||||
const { data: samlConfig, isPending: isLoadingSamlConfig } = useGetSSOConfig(
|
const { data: samlConfig, isPending: isLoadingSamlConfig } = useGetSSOConfig(
|
||||||
currentOrg?.id ?? ""
|
currentOrg?.id ?? ""
|
||||||
|
Reference in New Issue
Block a user