From 3317b35f79d06c2a6ad9cf29154e5e8796d7641e Mon Sep 17 00:00:00 2001 From: Deepak Prabhakara Date: Wed, 25 Dec 2024 10:10:39 +0000 Subject: [PATCH] cleanup (#3401) --- .env.example | 4 - lib/env.ts | 4 - npm/src/controller/api.ts | 15 +- npm/src/controller/connection/oidc.ts | 40 +---- npm/src/controller/connection/saml.ts | 39 +---- npm/src/ee/ory/ory.ts | 206 -------------------------- npm/src/index.ts | 3 - npm/src/typings.ts | 8 - 8 files changed, 9 insertions(+), 310 deletions(-) delete mode 100644 npm/src/ee/ory/ory.ts diff --git a/.env.example b/.env.example index 52af72c8d..adcbf2f7d 100644 --- a/.env.example +++ b/.env.example @@ -107,10 +107,6 @@ BOXYHQ_HOSTED=0 # Setup link expiry in days SETUP_LINK_EXPIRY_DAYS=3 -# Ory integration. You need BOXYHQ_LICENSE_KEY to be set to use this. -ENTERPRISE_ORY_SDK_TOKEN= -ENTERPRISE_ORY_PROJECT_ID= - # Uncomment below if you wish to opt-out of sending `profile` scope in OIDC Provider Authorization Request #OPENID_REQUEST_PROFILE_SCOPE=false diff --git a/lib/env.ts b/lib/env.ts index d72c03185..42e0dad8c 100644 --- a/lib/env.ts +++ b/lib/env.ts @@ -126,10 +126,6 @@ const jacksonOptions: JacksonOption = { }, setupLinkExpiryDays, boxyhqHosted, - ory: { - projectId: process.env.ENTERPRISE_ORY_PROJECT_ID, - sdkToken: process.env.ENTERPRISE_ORY_SDK_TOKEN, - }, ssoTraces, }; diff --git a/npm/src/controller/api.ts b/npm/src/controller/api.ts index 9a7f39cc5..57eb7a9e6 100644 --- a/npm/src/controller/api.ts +++ b/npm/src/controller/api.ts @@ -24,19 +24,16 @@ import { JacksonError } from './error'; import { IndexNames, appID, transformConnections, transformConnection, isConnectionActive } from './utils'; import oidcConnection from './connection/oidc'; import samlConnection from './connection/saml'; -import { OryController } from '../ee/ory/ory'; export class ConnectionAPIController implements IConnectionAPIController { private connectionStore: Storable; private opts: JacksonOption; private eventController: IEventController; - private oryController: OryController; - constructor({ connectionStore, opts, eventController, oryController }) { + constructor({ connectionStore, opts, eventController }) { this.connectionStore = connectionStore; this.opts = opts; this.eventController = eventController; - this.oryController = oryController; } /** @@ -198,7 +195,7 @@ export class ConnectionAPIController implements IConnectionAPIController { ): Promise { metrics.increment('createConnection'); - const connection = await samlConnection.create(body, this.connectionStore, this.oryController); + const connection = await samlConnection.create(body, this.connectionStore); await this.eventController.notify('sso.created', connection); @@ -221,7 +218,7 @@ export class ConnectionAPIController implements IConnectionAPIController { throw new JacksonError('Please set OpenID response handler path (oidcPath) on Jackson', 500); } - const connection = await oidcConnection.create(body, this.connectionStore, this.oryController); + const connection = await oidcConnection.create(body, this.connectionStore); await this.eventController.notify('sso.created', connection); @@ -378,8 +375,7 @@ export class ConnectionAPIController implements IConnectionAPIController { const connection = await samlConnection.update( body, this.connectionStore, - this.getConnections.bind(this), - this.oryController + this.getConnections.bind(this) ); if ('deactivated' in body) { @@ -406,8 +402,7 @@ export class ConnectionAPIController implements IConnectionAPIController { const connection = await oidcConnection.update( body, this.connectionStore, - this.getConnections.bind(this), - this.oryController + this.getConnections.bind(this) ); if ('deactivated' in body) { diff --git a/npm/src/controller/connection/oidc.ts b/npm/src/controller/connection/oidc.ts index ce9fd62f1..4dcbc81b5 100644 --- a/npm/src/controller/connection/oidc.ts +++ b/npm/src/controller/connection/oidc.ts @@ -18,13 +18,11 @@ import { validateSortOrder, } from '../utils'; import { JacksonError } from '../error'; -import { OryController } from '../../ee/ory/ory'; const oidc = { create: async ( body: OIDCSSOConnectionWithDiscoveryUrl | OIDCSSOConnectionWithMetadata, - connectionStore: Storable, - oryController: OryController + connectionStore: Storable ) => { validateSSOConnection(body, 'oidc'); @@ -87,9 +85,6 @@ const oidc = { record.clientID = dbutils.keyDigest(dbutils.keyFromParts(tenant, product, oidcClientId)); const exists = await connectionStore.get(record.clientID); - const oryProjectId = exists?.ory?.projectId; - const oryOrganizationId = exists?.ory?.organizationId; - if (exists) { connectionClientSecret = exists.clientSecret; } else { @@ -98,21 +93,6 @@ const oidc = { record.clientSecret = connectionClientSecret; - const oryRes = await oryController.createConnection( - { - sdkToken: undefined, - projectId: oryProjectId, - domains: body.ory?.domains, - organizationId: oryOrganizationId, - error: undefined, - }, - tenant, - product - ); - if (oryRes) { - record.ory = oryRes; - } - await connectionStore.put( record.clientID, record, @@ -134,8 +114,7 @@ const oidc = { update: async ( body: UpdateOIDCConnectionParams, connectionStore: Storable, - connectionsGetter: IConnectionAPIController['getConnections'], - oryController: OryController + connectionsGetter: IConnectionAPIController['getConnections'] ) => { const { defaultRedirectUrl, @@ -234,21 +213,6 @@ const oidc = { record['deactivated'] = body.deactivated; } - const oryRes = await oryController.updateConnection( - { - sdkToken: undefined, - projectId: _savedConnection.ory?.projectId, - domains: _savedConnection.ory?.domains, - organizationId: _savedConnection.ory?.organizationId, - error: undefined, - }, - _savedConnection.tenant, - _savedConnection.product - ); - if (oryRes) { - record.ory = oryRes; - } - await connectionStore.put( clientInfo?.clientID, record, diff --git a/npm/src/controller/connection/saml.ts b/npm/src/controller/connection/saml.ts index aee61aac0..c0868ce98 100644 --- a/npm/src/controller/connection/saml.ts +++ b/npm/src/controller/connection/saml.ts @@ -22,7 +22,6 @@ import { validateSortOrder, } from '../utils'; import { JacksonError } from '../error'; -import { OryController } from '../../ee/ory/ory'; async function fetchMetadata(resource: string) { try { @@ -60,8 +59,7 @@ function validateMetadataURL(metadataUrl: string) { const saml = { create: async ( body: SAMLSSOConnectionWithRawMetadata | SAMLSSOConnectionWithEncodedMetadata, - connectionStore: Storable, - oryController: OryController + connectionStore: Storable ) => { const { encodedRawMetadata, @@ -155,8 +153,6 @@ const saml = { } const exists = await connectionStore.get(record.clientID); - const oryProjectId = exists?.ory?.projectId; - const oryOrganizationId = exists?.ory?.organizationId; if (exists) { connectionClientSecret = exists.clientSecret; @@ -166,21 +162,6 @@ const saml = { record.clientSecret = connectionClientSecret; - const oryRes = await oryController.createConnection( - { - sdkToken: undefined, - projectId: oryProjectId, - domains: body.ory?.domains, - organizationId: oryOrganizationId, - error: undefined, - }, - tenant, - product - ); - if (oryRes) { - record.ory = oryRes; - } - await connectionStore.put( record.clientID, record, @@ -206,8 +187,7 @@ const saml = { update: async ( body: UpdateSAMLConnectionParams, connectionStore: Storable, - connectionsGetter: IConnectionAPIController['getConnections'], - oryController: OryController + connectionsGetter: IConnectionAPIController['getConnections'] ) => { const { encodedRawMetadata, // could be empty @@ -319,21 +299,6 @@ const saml = { record['identifierFormat'] = body.identifierFormat; } - const oryRes = await oryController.updateConnection( - { - sdkToken: undefined, - projectId: _savedConnection.ory?.projectId, - domains: _savedConnection.ory?.domains, - organizationId: _savedConnection.ory?.organizationId, - error: undefined, - }, - _savedConnection.tenant, - _savedConnection.product - ); - if (oryRes) { - record.ory = oryRes; - } - await connectionStore.put( clientInfo?.clientID, record, diff --git a/npm/src/ee/ory/ory.ts b/npm/src/ee/ory/ory.ts deleted file mode 100644 index acf74e469..000000000 --- a/npm/src/ee/ory/ory.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { JacksonOption, OryConfig, OryRes } from '../../typings'; -import axios, { AxiosError } from 'axios'; -import { throwIfInvalidLicense } from '../common/checkLicense'; -import { ProductController } from '../product'; - -const basePath = 'https://api.console.ory.sh'; -const providerId = 'sso_boxyhq'; -const dataMapping = - 'base64://bG9jYWwgY2xhaW1zID0gewogIGVtYWlsX3ZlcmlmaWVkOiB0cnVlLAp9ICsgc3RkLmV4dFZhcignY2xhaW1zJyk7Cgp7CiAgaWRlbnRpdHk6IHsKICAgIHRyYWl0czogewogICAgICBbaWYgJ2VtYWlsJyBpbiBjbGFpbXMgJiYgY2xhaW1zLmVtYWlsX3ZlcmlmaWVkIHRoZW4gJ2VtYWlsJyBlbHNlIG51bGxdOiBjbGFpbXMuZW1haWwsCiAgICB9LAogIH0sCn0='; -const issuerUrl = 'https://sso.eu.boxyhq.com'; - -export class OryController { - private opts: JacksonOption; - private productController: ProductController; - - constructor({ opts, productController }: { opts: JacksonOption; productController: ProductController }) { - this.opts = opts; - this.productController = productController; - } - - private getOrgName(tenant: string, product: string): string { - return this.opts.boxyhqHosted ? tenant : `${tenant}:${product}`; - } - - private getIssuerUrl() { - if (this.opts.boxyhqHosted) { - return issuerUrl; - } else { - return this.opts.externalUrl; - } - } - - private async addOrUpdateConnection(config: OryConfig, tenant: string, product: string): Promise { - const project = await axios.get(`${basePath}/projects/${config.projectId}`, { - headers: { - Authorization: `Bearer ${config.sdkToken}`, - }, - }); - - let index = '-'; - try { - for (const idx in project.data.services.identity.config.selfservice.methods.oidc.config.providers) { - const provider = project.data.services.identity.config.selfservice.methods.oidc.config.providers[idx]; - if (provider.id === providerId && provider.organization_id === config.organizationId) { - index = idx; - break; - } - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (err) { - // empty - } - - const op = index === '-' ? 'add' : 'replace'; - - await axios.patch( - `${basePath}/normalized/projects/${config.projectId}/revision/${project.data.revision_id}`, - [ - { op: 'replace', path: '/kratos_selfservice_methods_oidc_enabled', value: true }, - { - op, - path: `/kratos_selfservice_methods_oidc_config_providers/${index}`, - value: { - provider_id: providerId, - provider: 'generic', - label: 'SSO', - client_id: `tenant=${tenant}&product=${product}`, - client_secret: this.opts.clientSecretVerifier, - organization_id: config.organizationId, - scope: [], - mapper_url: dataMapping, - additional_id_token_audiences: [], - issuer_url: this.getIssuerUrl(), - }, - }, - ], - { - headers: { - Authorization: `Bearer ${config.sdkToken}`, - }, - } - ); - } - - private async createOrganization(config: OryConfig, label: string): Promise { - if (!config.sdkToken || !config.projectId) { - throw new Error('Ory SDK Token or Project ID not set'); - } - - if (config && config.organizationId) { - try { - const res = await axios.get( - `${basePath}/projects/${config.projectId}/organizations/${config.organizationId}`, - { - headers: { - Authorization: `Bearer ${config.sdkToken}`, - }, - } - ); - return res.data.organization.id; - } catch (err) { - // if org doesn't exist fall through to section that creates it below - if ((err as AxiosError).response?.status !== 404) { - throw err; - } - } - } - - const res = await axios.post( - `${basePath}/projects/${config.projectId}/organizations`, - { - label, - domains: config.domains, - }, - { - headers: { - Authorization: `Bearer ${config.sdkToken}`, - }, - } - ); - return res.data.id; - } - - private async sanitizeConfig(config: OryConfig, tenant: string): Promise { - if (!config.sdkToken) { - config.sdkToken = this.opts.ory?.sdkToken; - } - if (!config.projectId) { - config.projectId = this.opts.ory?.projectId; - } - config.domains = config.domains || []; - if (!config.domains.includes(tenant)) { - config.domains.push(tenant); - } - return config; - } - - public async createConnection(config: OryConfig, tenant: string, product: string): Promise { - if (!(await this.isEnabled(config, tenant, product))) { - return null; - } - - const organizationId = await this.createOrganization(config, this.getOrgName(tenant, product)); - config.organizationId = organizationId; - - let error; - try { - await this.addOrUpdateConnection(config, tenant, product); - } catch (err) { - error = err; - } - - return { projectId: config.projectId, domains: config.domains, organizationId, error }; - } - - public async updateConnection(config: OryConfig, tenant: string, product: string): Promise { - if (!(await this.isEnabled(config, tenant, product))) { - return null; - } - - const organizationId = await this.createOrganization(config, this.getOrgName(tenant, product)); - - let error; - try { - await this.addOrUpdateConnection(config, tenant, product); - } catch (err) { - error = err; - } - - return { projectId: config.projectId, domains: config.domains, organizationId, error }; - } - - private async isEnabled(config: OryConfig, tenant: string, product: string): Promise { - if (this.opts.boxyhqHosted) { - const productConfig = await this.productController.get(product); - if ( - !productConfig || - !productConfig.ory || - !productConfig.ory.sdkToken || - !productConfig.ory.projectId - ) { - return false; - } - - config.sdkToken = productConfig.ory.sdkToken; - config.projectId = productConfig.ory.projectId; - - this.sanitizeConfig(config, tenant); - - return true; - } else { - if (!this.opts.ory?.sdkToken || !this.opts.ory?.projectId) { - return false; - } - try { - await throwIfInvalidLicense(this.opts.boxyhqLicenseKey); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (err) { - console.error('Ory is not enabled because of invalid license'); - return false; - } - this.sanitizeConfig(config, tenant); - return true; - } - } -} diff --git a/npm/src/index.ts b/npm/src/index.ts index 56e3260de..d1de3820b 100644 --- a/npm/src/index.ts +++ b/npm/src/index.ts @@ -19,7 +19,6 @@ import { BrandingController } from './ee/branding'; import SSOTraces from './sso-traces'; import EventController from './event'; import { ProductController } from './ee/product'; -import { OryController } from './ee/ory/ory'; const TRACES_TTL_DEFAULT = 7 * 24 * 60 * 60; @@ -99,12 +98,10 @@ export const controllers = async ( const eventController = new EventController({ opts }); const productController = new ProductController({ productStore, opts }); - const oryController = new OryController({ opts, productController }); const connectionAPIController = new ConnectionAPIController({ connectionStore, opts, eventController, - oryController, }); const adminController = new AdminController({ connectionStore, ssoTraces }); const healthCheckController = new HealthCheckController({ healthCheckStore }); diff --git a/npm/src/typings.ts b/npm/src/typings.ts index b9731814b..7d8f1f68f 100644 --- a/npm/src/typings.ts +++ b/npm/src/typings.ts @@ -30,7 +30,6 @@ export interface SSOConnection { name?: string; label?: string; description?: string; - ory?: OryConfig; sortOrder?: number | null; } @@ -142,7 +141,6 @@ export type UpdateConnectionParams = TenantProduct & { defaultRedirectUrl?: string; redirectUrl?: string[] | string; deactivated?: boolean; - ory?: OryConfig; sortOrder?: number | null; }; @@ -503,11 +501,6 @@ export interface JacksonOption { /** The number of days a setup link is valid for. Defaults to 3 days. */ setupLinkExpiryDays?: number; boxyhqHosted?: boolean; - - ory?: { - projectId: string | undefined; - sdkToken: string | undefined; - }; ssoTraces?: SSOTracesOption; } @@ -650,7 +643,6 @@ export interface ProductConfig { primaryColor: string | null; faviconUrl: string | null; companyName: string | null; - ory: OryConfig | null; development?: boolean; }