wip using identityprovider from config

This commit is contained in:
msukkari 2025-10-31 11:55:39 -07:00
parent 6bc03f7a0e
commit d4cf329af2
4 changed files with 195 additions and 149 deletions

View file

@ -20,6 +20,7 @@ import { getAuditService } from '@/ee/features/audit/factory';
import { SINGLE_TENANT_ORG_ID } from './lib/constants'; import { SINGLE_TENANT_ORG_ID } from './lib/constants';
const auditService = getAuditService(); const auditService = getAuditService();
const ssoProviders = hasEntitlement("sso") ? await getSSOProviders() : [];
export const runtime = 'nodejs'; export const runtime = 'nodejs';
@ -38,11 +39,7 @@ declare module 'next-auth/jwt' {
} }
export const getProviders = () => { export const getProviders = () => {
const providers: Provider[] = []; const providers: Provider[] = ssoProviders;
if (hasEntitlement("sso")) {
providers.push(...getSSOProviders());
}
if (env.SMTP_CONNECTION_URL && env.EMAIL_FROM_ADDRESS && env.AUTH_EMAIL_CODE_LOGIN_ENABLED === 'true') { if (env.SMTP_CONNECTION_URL && env.EMAIL_FROM_ADDRESS && env.AUTH_EMAIL_CODE_LOGIN_ENABLED === 'true') {
providers.push(EmailProvider({ providers.push(EmailProvider({

View file

@ -12,19 +12,70 @@ import Credentials from "next-auth/providers/credentials";
import type { User as AuthJsUser } from "next-auth"; import type { User as AuthJsUser } from "next-auth";
import { onCreateUser } from "@/lib/authUtils"; import { onCreateUser } from "@/lib/authUtils";
import { createLogger } from "@sourcebot/logger"; import { createLogger } from "@sourcebot/logger";
import { hasEntitlement } from "@sourcebot/shared"; import { hasEntitlement, loadConfig } from "@sourcebot/shared";
import { getTokenFromConfig } from "@sourcebot/crypto";
import { SINGLE_TENANT_ORG_ID } from "@/lib/constants";
const logger = createLogger('web-sso'); const logger = createLogger('web-sso');
export const getSSOProviders = (): Provider[] => { export const getSSOProviders = async (): Promise<Provider[]> => {
const providers: Provider[] = []; const providers: Provider[] = [];
const config = env.CONFIG_PATH ? await loadConfig(env.CONFIG_PATH) : undefined;
const identityProviders = config?.identityProviders ?? [];
for (const identityProvider of identityProviders) {
if (identityProvider.provider === "github") {
const clientId = await getTokenFromConfig(identityProvider.clientId, SINGLE_TENANT_ORG_ID, db);
const clientSecret = await getTokenFromConfig(identityProvider.clientSecret, SINGLE_TENANT_ORG_ID, db);
const baseUrl = identityProvider.baseUrl ? await getTokenFromConfig(identityProvider.baseUrl, SINGLE_TENANT_ORG_ID, db) : undefined;
providers.push(createGitHubProvider(clientId, clientSecret, baseUrl));
}
if (identityProvider.provider === "gitlab") {
const clientId = await getTokenFromConfig(identityProvider.clientId, SINGLE_TENANT_ORG_ID, db);
const clientSecret = await getTokenFromConfig(identityProvider.clientSecret, SINGLE_TENANT_ORG_ID, db);
const baseUrl = identityProvider.baseUrl ? await getTokenFromConfig(identityProvider.baseUrl, SINGLE_TENANT_ORG_ID, db) : undefined;
providers.push(createGitLabProvider(clientId, clientSecret, baseUrl));
}
}
if (env.AUTH_EE_GITHUB_CLIENT_ID && env.AUTH_EE_GITHUB_CLIENT_SECRET) { if (env.AUTH_EE_GITHUB_CLIENT_ID && env.AUTH_EE_GITHUB_CLIENT_SECRET) {
providers.push(GitHub({ providers.push(createGitHubProvider(env.AUTH_EE_GITHUB_CLIENT_ID, env.AUTH_EE_GITHUB_CLIENT_SECRET, env.AUTH_EE_GITHUB_BASE_URL));
clientId: env.AUTH_EE_GITHUB_CLIENT_ID, }
clientSecret: env.AUTH_EE_GITHUB_CLIENT_SECRET,
if (env.AUTH_EE_GITLAB_CLIENT_ID && env.AUTH_EE_GITLAB_CLIENT_SECRET) {
providers.push(createGitLabProvider(env.AUTH_EE_GITLAB_CLIENT_ID, env.AUTH_EE_GITLAB_CLIENT_SECRET, env.AUTH_EE_GITLAB_BASE_URL));
}
if (env.AUTH_EE_GOOGLE_CLIENT_ID && env.AUTH_EE_GOOGLE_CLIENT_SECRET) {
providers.push(createGoogleProvider(env.AUTH_EE_GOOGLE_CLIENT_ID, env.AUTH_EE_GOOGLE_CLIENT_SECRET));
}
if (env.AUTH_EE_OKTA_CLIENT_ID && env.AUTH_EE_OKTA_CLIENT_SECRET && env.AUTH_EE_OKTA_ISSUER) {
providers.push(createOktaProvider(env.AUTH_EE_OKTA_CLIENT_ID, env.AUTH_EE_OKTA_CLIENT_SECRET, env.AUTH_EE_OKTA_ISSUER));
}
if (env.AUTH_EE_KEYCLOAK_CLIENT_ID && env.AUTH_EE_KEYCLOAK_CLIENT_SECRET && env.AUTH_EE_KEYCLOAK_ISSUER) {
providers.push(createKeycloakProvider(env.AUTH_EE_KEYCLOAK_CLIENT_ID, env.AUTH_EE_KEYCLOAK_CLIENT_SECRET, env.AUTH_EE_KEYCLOAK_ISSUER));
}
if (env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID && env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET && env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER) {
providers.push(createMicrosoftEntraIDProvider(env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID, env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET, env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER));
}
if (env.AUTH_EE_GCP_IAP_ENABLED && env.AUTH_EE_GCP_IAP_AUDIENCE) {
providers.push(createGCPIAPProvider(env.AUTH_EE_GCP_IAP_AUDIENCE));
}
return providers;
}
const createGitHubProvider = (clientId: string, clientSecret: string, baseUrl?: string): Provider => {
return GitHub({
clientId: clientId,
clientSecret: clientSecret,
enterprise: { enterprise: {
baseUrl: env.AUTH_EE_GITHUB_BASE_URL, baseUrl: baseUrl,
}, },
authorization: { authorization: {
params: { params: {
@ -41,15 +92,16 @@ export const getSSOProviders = (): Provider[] => {
].join(' '), ].join(' '),
}, },
}, },
})); });
} }
if (env.AUTH_EE_GITLAB_CLIENT_ID && env.AUTH_EE_GITLAB_CLIENT_SECRET) { const createGitLabProvider = (clientId: string, clientSecret: string, baseUrl?: string): Provider => {
providers.push(Gitlab({ const url = baseUrl ?? 'https://gitlab.com';
clientId: env.AUTH_EE_GITLAB_CLIENT_ID, return Gitlab({
clientSecret: env.AUTH_EE_GITLAB_CLIENT_SECRET, clientId: clientId,
clientSecret: clientSecret,
authorization: { authorization: {
url: `${env.AUTH_EE_GITLAB_BASE_URL}/oauth/authorize`, url: `${url}/oauth/authorize`,
params: { params: {
scope: [ scope: [
"read_user", "read_user",
@ -64,47 +116,47 @@ export const getSSOProviders = (): Provider[] => {
}, },
}, },
token: { token: {
url: `${env.AUTH_EE_GITLAB_BASE_URL}/oauth/token`, url: `${url}/oauth/token`,
}, },
userinfo: { userinfo: {
url: `${env.AUTH_EE_GITLAB_BASE_URL}/api/v4/user`, url: `${url}/api/v4/user`,
}, },
})); });
} }
if (env.AUTH_EE_GOOGLE_CLIENT_ID && env.AUTH_EE_GOOGLE_CLIENT_SECRET) { const createGoogleProvider = (clientId: string, clientSecret: string): Provider => {
providers.push(Google({ return Google({
clientId: env.AUTH_EE_GOOGLE_CLIENT_ID, clientId: clientId,
clientSecret: env.AUTH_EE_GOOGLE_CLIENT_SECRET, clientSecret: clientSecret,
})); });
} }
if (env.AUTH_EE_OKTA_CLIENT_ID && env.AUTH_EE_OKTA_CLIENT_SECRET && env.AUTH_EE_OKTA_ISSUER) { const createOktaProvider = (clientId: string, clientSecret: string, issuer: string): Provider => {
providers.push(Okta({ return Okta({
clientId: env.AUTH_EE_OKTA_CLIENT_ID, clientId: clientId,
clientSecret: env.AUTH_EE_OKTA_CLIENT_SECRET, clientSecret: clientSecret,
issuer: env.AUTH_EE_OKTA_ISSUER, issuer: issuer,
})); });
} }
if (env.AUTH_EE_KEYCLOAK_CLIENT_ID && env.AUTH_EE_KEYCLOAK_CLIENT_SECRET && env.AUTH_EE_KEYCLOAK_ISSUER) { const createKeycloakProvider = (clientId: string, clientSecret: string, issuer: string): Provider => {
providers.push(Keycloak({ return Keycloak({
clientId: env.AUTH_EE_KEYCLOAK_CLIENT_ID, clientId: clientId,
clientSecret: env.AUTH_EE_KEYCLOAK_CLIENT_SECRET, clientSecret: clientSecret,
issuer: env.AUTH_EE_KEYCLOAK_ISSUER, issuer: issuer,
})); });
} }
if (env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID && env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET && env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER) { const createMicrosoftEntraIDProvider = (clientId: string, clientSecret: string, issuer: string): Provider => {
providers.push(MicrosoftEntraID({ return MicrosoftEntraID({
clientId: env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID, clientId: clientId,
clientSecret: env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET, clientSecret: clientSecret,
issuer: env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER, issuer: issuer,
})); });
} }
if (env.AUTH_EE_GCP_IAP_ENABLED && env.AUTH_EE_GCP_IAP_AUDIENCE) { const createGCPIAPProvider = (audience: string): Provider => {
providers.push(Credentials({ return Credentials({
id: "gcp-iap", id: "gcp-iap",
name: "Google Cloud IAP", name: "Google Cloud IAP",
credentials: {}, credentials: {},
@ -122,7 +174,7 @@ export const getSSOProviders = (): Provider[] => {
const ticket = await oauth2Client.verifySignedJwtWithCertsAsync( const ticket = await oauth2Client.verifySignedJwtWithCertsAsync(
iapAssertion, iapAssertion,
pubkeys, pubkeys,
env.AUTH_EE_GCP_IAP_AUDIENCE, audience,
['https://cloud.google.com/iap'] ['https://cloud.google.com/iap']
); );
@ -176,8 +228,5 @@ export const getSSOProviders = (): Provider[] => {
return null; return null;
} }
}, },
})); });
}
return providers;
} }

View file

@ -9,7 +9,7 @@
"const": "github" "const": "github"
}, },
"purpose": { "purpose": {
"enum": ["sso", "identity"] "enum": ["sso", "integration"]
}, },
"clientId": { "clientId": {
"$ref": "./shared.json#/definitions/Token" "$ref": "./shared.json#/definitions/Token"
@ -30,7 +30,7 @@
"const": "gitlab" "const": "gitlab"
}, },
"purpose": { "purpose": {
"enum": ["sso", "identity"] "enum": ["sso", "integration"]
}, },
"clientId": { "clientId": {
"$ref": "./shared.json#/definitions/Token" "$ref": "./shared.json#/definitions/Token"

View file

@ -130,7 +130,7 @@
"type": "array", "type": "array",
"description": "Defines a collection of identity providers that are available to Sourcebot.", "description": "Defines a collection of identity providers that are available to Sourcebot.",
"items": { "items": {
"$ref": "./authProvider.json" "$ref": "./identityProvider.json"
} }
} }
}, },