diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a1b46fdd..48016f96c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added an optional `webUrl` field to the GitLab connection config, used to build links to repositories in the GitLab web UI when the API host differs from the browsable host. [#1457](https://github.com/sourcebot-dev/sourcebot/pull/1457) +- [EE] Added Idira SSO support through OpenID Connect. [#1459](https://github.com/sourcebot-dev/sourcebot/pull/1459) ### Fixed - Prevented focus rings in workspace connector dialogs from being clipped. [#1457](https://github.com/sourcebot-dev/sourcebot/pull/1457) diff --git a/docs/docs/configuration/idp.mdx b/docs/docs/configuration/idp.mdx index b5fffa1d7..da56c15d1 100644 --- a/docs/docs/configuration/idp.mdx +++ b/docs/docs/configuration/idp.mdx @@ -601,6 +601,57 @@ A JumpCloud connection can be used for [authentication](/docs/configuration/auth +### Idira + +[Idira custom OpenID Connect application documentation](https://docs.cyberark.com/manage/latest/en/content/identity/applications/appscustom/openidaddconfigapp.htm) + +An Idira connection can be used for [authentication](/docs/configuration/auth). Sourcebot uses Idira's OpenID Connect support to authenticate users. + + + + + In the Idira Admin Portal, go to **Manage > Identities > Web apps**, add the custom **OpenID Connect** application, and configure its Trust settings. + + When configuring the application: + - Add `/api/auth/callback/idira` to the **Authorized Redirect URIs** (ex. https://sourcebot.coolcorp.com/api/auth/callback/idira) + - Keep exact redirect URI matching enabled + - Grant the users, groups, or roles that should be able to sign in permission to run the application + + From the application's Trust page, note the `CLIENT_ID` and `ISSUER`. Generate a client secret and store it securely. Idira displays the secret only until you confirm that you have saved it. + + + Provide the client id, secret, and issuer URL to Sourcebot using environment variables. These variables can be named whatever you like + (ex. `IDIRA_IDENTITY_PROVIDER_CLIENT_ID`, `IDIRA_IDENTITY_PROVIDER_CLIENT_SECRET`, and `IDIRA_IDENTITY_PROVIDER_ISSUER`). + + + Add the Idira provider to the `identityProviders` object in the [config file](/docs/configuration/config-file): + + ```json wrap icon="code" + { + "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json", + "identityProviders": { + "idira": { + "provider": "idira", + "purpose": "sso", + "clientId": { + "env": "IDIRA_IDENTITY_PROVIDER_CLIENT_ID" + }, + "clientSecret": { + "env": "IDIRA_IDENTITY_PROVIDER_CLIENT_SECRET" + }, + "issuer": { + "env": "IDIRA_IDENTITY_PROVIDER_ISSUER" + } + } + } + } + ``` + + If you use a custom identity provider id instead of `idira`, use that id in the callback URL as described in [multiple identity providers](#configuring-multiple-providers-of-the-same-type). + + + + ### Google Cloud IAP [Google Cloud IAP Documentation](https://cloud.google.com/iap/docs) @@ -688,5 +739,3 @@ Each provider keeps the same fields documented above. The only differences are: Each instance needs its own OAuth client (its own `clientId` and `clientSecret`) registered with the matching callback URL. - - diff --git a/docs/snippets/schemas/v3/identityProvider.schema.mdx b/docs/snippets/schemas/v3/identityProvider.schema.mdx index 8280622b2..0be1f8f6d 100644 --- a/docs/snippets/schemas/v3/identityProvider.schema.mdx +++ b/docs/snippets/schemas/v3/identityProvider.schema.mdx @@ -991,6 +991,119 @@ "issuer" ] }, + "IdiraIdentityProviderConfig": { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, "BitbucketServerIdentityProviderConfig": { "type": "object", "additionalProperties": false, @@ -2078,6 +2191,119 @@ "issuer" ] }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, { "type": "object", "additionalProperties": false, diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index 172d04988..a9603abdc 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -5962,6 +5962,119 @@ "issuer" ] }, + "IdiraIdentityProviderConfig": { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, "BitbucketServerIdentityProviderConfig": { "type": "object", "additionalProperties": false, @@ -7049,6 +7162,119 @@ "issuer" ] }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, { "type": "object", "additionalProperties": false, @@ -8145,6 +8371,119 @@ "issuer" ] }, + "IdiraIdentityProviderConfig": { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, "BitbucketServerIdentityProviderConfig": { "type": "object", "additionalProperties": false, @@ -9232,6 +9571,119 @@ "issuer" ] }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, { "type": "object", "additionalProperties": false, diff --git a/packages/schemas/src/v3/identityProvider.schema.ts b/packages/schemas/src/v3/identityProvider.schema.ts index 1c17b57f9..a95db0c1a 100644 --- a/packages/schemas/src/v3/identityProvider.schema.ts +++ b/packages/schemas/src/v3/identityProvider.schema.ts @@ -990,6 +990,119 @@ const schema = { "issuer" ] }, + "IdiraIdentityProviderConfig": { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, "BitbucketServerIdentityProviderConfig": { "type": "object", "additionalProperties": false, @@ -2077,6 +2190,119 @@ const schema = { "issuer" ] }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, { "type": "object", "additionalProperties": false, diff --git a/packages/schemas/src/v3/identityProvider.type.ts b/packages/schemas/src/v3/identityProvider.type.ts index 980aaa7b8..936bdb72b 100644 --- a/packages/schemas/src/v3/identityProvider.type.ts +++ b/packages/schemas/src/v3/identityProvider.type.ts @@ -11,6 +11,7 @@ export type IdentityProviderConfig = | AuthentikIdentityProviderConfig | BitbucketCloudIdentityProviderConfig | JumpCloudIdentityProviderConfig + | IdiraIdentityProviderConfig | BitbucketServerIdentityProviderConfig; export interface GitHubIdentityProviderConfig { @@ -416,6 +417,53 @@ export interface JumpCloudIdentityProviderConfig { googleCloudSecret: string; }; } +export interface IdiraIdentityProviderConfig { + provider: "idira"; + /** + * Optional human-readable label shown on the login screen. Defaults to 'Idira'. + */ + displayName?: string; + purpose: "sso"; + clientId: + | { + /** + * The name of the environment variable that contains the token. + */ + env: string; + } + | { + /** + * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets + */ + googleCloudSecret: string; + }; + clientSecret: + | { + /** + * The name of the environment variable that contains the token. + */ + env: string; + } + | { + /** + * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets + */ + googleCloudSecret: string; + }; + issuer: + | { + /** + * The name of the environment variable that contains the token. + */ + env: string; + } + | { + /** + * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets + */ + googleCloudSecret: string; + }; +} export interface BitbucketServerIdentityProviderConfig { provider: "bitbucket-server"; /** diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index 2112b3d5b..48e42f300 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -5961,6 +5961,119 @@ const schema = { "issuer" ] }, + "IdiraIdentityProviderConfig": { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, "BitbucketServerIdentityProviderConfig": { "type": "object", "additionalProperties": false, @@ -7048,6 +7161,119 @@ const schema = { "issuer" ] }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, { "type": "object", "additionalProperties": false, @@ -8144,6 +8370,119 @@ const schema = { "issuer" ] }, + "IdiraIdentityProviderConfig": { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, "BitbucketServerIdentityProviderConfig": { "type": "object", "additionalProperties": false, @@ -9231,6 +9570,119 @@ const schema = { "issuer" ] }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "issuer" + ] + }, { "type": "object", "additionalProperties": false, diff --git a/packages/schemas/src/v3/index.type.ts b/packages/schemas/src/v3/index.type.ts index 088b6829f..df59a13f4 100644 --- a/packages/schemas/src/v3/index.type.ts +++ b/packages/schemas/src/v3/index.type.ts @@ -41,6 +41,7 @@ export type IdentityProviderConfig = | AuthentikIdentityProviderConfig | BitbucketCloudIdentityProviderConfig | JumpCloudIdentityProviderConfig + | IdiraIdentityProviderConfig | BitbucketServerIdentityProviderConfig; export interface SourcebotConfig { @@ -1756,6 +1757,53 @@ export interface JumpCloudIdentityProviderConfig { googleCloudSecret: string; }; } +export interface IdiraIdentityProviderConfig { + provider: "idira"; + /** + * Optional human-readable label shown on the login screen. Defaults to 'Idira'. + */ + displayName?: string; + purpose: "sso"; + clientId: + | { + /** + * The name of the environment variable that contains the token. + */ + env: string; + } + | { + /** + * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets + */ + googleCloudSecret: string; + }; + clientSecret: + | { + /** + * The name of the environment variable that contains the token. + */ + env: string; + } + | { + /** + * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets + */ + googleCloudSecret: string; + }; + issuer: + | { + /** + * The name of the environment variable that contains the token. + */ + env: string; + } + | { + /** + * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets + */ + googleCloudSecret: string; + }; +} export interface BitbucketServerIdentityProviderConfig { provider: "bitbucket-server"; /** diff --git a/packages/web/public/idira.svg b/packages/web/public/idira.svg new file mode 100644 index 000000000..fb92b20d0 --- /dev/null +++ b/packages/web/public/idira.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/web/src/app/login/components/loginForm.tsx b/packages/web/src/app/login/components/loginForm.tsx index 9f9fb9662..6274ab34e 100644 --- a/packages/web/src/app/login/components/loginForm.tsx +++ b/packages/web/src/app/login/components/loginForm.tsx @@ -60,6 +60,8 @@ export const LoginForm = ({ callbackUrl, error, context, isAnonymousAccessEnable return "wa_login_with_microsoft_entra_id" as const; case "jumpcloud": return "wa_login_with_jumpcloud" as const; + case "idira": + return "wa_login_with_idira" as const; default: return "wa_login_with_github" as const; // fallback } diff --git a/packages/web/src/ee/features/sso/sso.ts b/packages/web/src/ee/features/sso/sso.ts index ca5b6b686..84e06a68a 100644 --- a/packages/web/src/ee/features/sso/sso.ts +++ b/packages/web/src/ee/features/sso/sso.ts @@ -162,6 +162,26 @@ export const getEEIdentityProviders = async (): Promise => { }); } + if (idpConfig.provider === "idira") { + const clientId = await getTokenFromConfig(idpConfig.clientId); + const clientSecret = await getTokenFromConfig(idpConfig.clientSecret); + const issuer = (await getTokenFromConfig(idpConfig.issuer)).replace(/\/+$/, ''); + providers.push({ + __provider: createIdiraProvider({ + id, + clientId, + clientSecret, + issuer, + allowDangerousEmailAccountLinking: env.AUTH_EE_ALLOW_EMAIL_ACCOUNT_LINKING === 'true', + }), + id, + type: idpConfig.provider, + displayName: idpConfig.displayName, + purpose: idpConfig.purpose, + issuerUrl: issuer, + }); + } + if (idpConfig.provider === "bitbucket-server") { const clientId = await getTokenFromConfig(idpConfig.clientId); const clientSecret = await getTokenFromConfig(idpConfig.clientSecret); @@ -403,6 +423,36 @@ const createJumpCloudProvider = (id: string, clientId: string, clientSecret: str } as Provider; } +type CreateIdiraProviderOptions = { + id: string; + clientId: string; + clientSecret: string; + issuer: string; + allowDangerousEmailAccountLinking: boolean; +}; + +const createIdiraProvider = ({ + id, + clientId, + clientSecret, + issuer, + allowDangerousEmailAccountLinking, +}: CreateIdiraProviderOptions): Provider => ({ + id, + name: "Idira", + type: "oidc", + clientId, + clientSecret, + issuer, + checks: ["pkce", "state"], + authorization: { + params: { + scope: "openid profile email", + }, + }, + allowDangerousEmailAccountLinking, +} as Provider); + const createGCPIAPProvider = (id: string, audience: string): Provider => { return Credentials({ id, diff --git a/packages/web/src/lib/posthogEvents.ts b/packages/web/src/lib/posthogEvents.ts index 15353cbd5..152a293e4 100644 --- a/packages/web/src/lib/posthogEvents.ts +++ b/packages/web/src/lib/posthogEvents.ts @@ -143,6 +143,7 @@ export type PosthogEventMap = { wa_login_with_keycloak: {}, wa_login_with_microsoft_entra_id: {}, wa_login_with_jumpcloud: {}, + wa_login_with_idira: {}, wa_login_with_magic_link: {}, wa_login_with_credentials: {}, ////////////////////////////////////////////////////////////////// diff --git a/packages/web/src/lib/utils.ts b/packages/web/src/lib/utils.ts index bc7720416..b49050f2a 100644 --- a/packages/web/src/lib/utils.ts +++ b/packages/web/src/lib/utils.ts @@ -13,6 +13,7 @@ import keycloakLogo from "@/public/keycloak.svg"; import microsoftLogo from "@/public/microsoft_entra.svg"; import authentikLogo from "@/public/authentik.svg"; import jumpcloudLogo from "@/public/jumpcloud.svg"; +import idiraLogo from "@/public/idira.svg"; import { ServiceError } from "./serviceError"; import { ConnectionType } from "@sourcebot/db"; import { CodeHostType } from "@sourcebot/db"; @@ -155,6 +156,15 @@ export const getAuthProviderInfo = (providerType: string): AuthProviderInfo => { src: jumpcloudLogo, }, }; + case "idira": + return { + id: "idira", + name: "Idira", + displayName: "Idira", + icon: { + src: idiraLogo, + }, + }; case "credentials": return { id: "credentials", @@ -654,4 +664,4 @@ export const fetchWithRetry = async ( } // Unreachable, but TypeScript needs it throw new Error('fetchWithRetry: exhausted retries'); -} \ No newline at end of file +} diff --git a/schemas/v3/identityProvider.json b/schemas/v3/identityProvider.json index fcc98d081..264fd8f7d 100644 --- a/schemas/v3/identityProvider.json +++ b/schemas/v3/identityProvider.json @@ -278,6 +278,32 @@ }, "required": ["provider", "purpose", "clientId", "clientSecret", "issuer"] }, + "IdiraIdentityProviderConfig": { + "type": "object", + "additionalProperties": false, + "properties": { + "provider": { + "const": "idira" + }, + "displayName": { + "type": "string", + "description": "Optional human-readable label shown on the login screen. Defaults to 'Idira'." + }, + "purpose": { + "const": "sso" + }, + "clientId": { + "$ref": "./shared.json#/definitions/Token" + }, + "clientSecret": { + "$ref": "./shared.json#/definitions/Token" + }, + "issuer": { + "$ref": "./shared.json#/definitions/Token" + } + }, + "required": ["provider", "purpose", "clientId", "clientSecret", "issuer"] + }, "BitbucketServerIdentityProviderConfig": { "type": "object", "additionalProperties": false, @@ -343,6 +369,9 @@ { "$ref": "#/definitions/JumpCloudIdentityProviderConfig" }, + { + "$ref": "#/definitions/IdiraIdentityProviderConfig" + }, { "$ref": "#/definitions/BitbucketServerIdentityProviderConfig" }