feat(sso): allow to use OIDC and SAML (#7246)

## What it does
### Backend
- [x] Add a mutation to create OIDC and SAML configuration
- [x] Add a mutation to delete an SSO config
- [x] Add a feature flag to toggle SSO
- [x] Add a mutation to activate/deactivate an SSO config
- [x] Add a mutation to delete an SSO config
- [x] Add strategy to use OIDC or SAML
- [ ] Improve error management

### Frontend
- [x] Add section "security" in settings
- [x] Add page to list SSO configurations
- [x] Add page and forms to create OIDC or SAML configuration
- [x] Add field to "connect with SSO" in the signin/signup process
- [x] Trigger auth when a user switch to a workspace with SSO enable
- [x] Add an option on the security page to activate/deactivate the
global invitation link
- [ ] Add new Icons for SSO Identity Providers (okta, Auth0, Azure,
Microsoft)

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Antoine Moreaux
2024-10-21 20:07:08 +02:00
committed by GitHub
parent 11c3f1c399
commit 0f0a7966b1
132 changed files with 5245 additions and 306 deletions

View File

@ -60,6 +60,11 @@ export const seedFeatureFlags = async (
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IsSSOEnabled,
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IsGmailSendEmailScopeEnabled,
workspaceId: workspaceId,

View File

@ -0,0 +1,66 @@
/* @license Enterprise */
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddWorkspaceSSOIdentityProvider1727181198403
implements MigrationInterface
{
name = 'AddWorkspaceSSOIdentityProvider1727181198403';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TYPE "core"."idp_type_enum" AS ENUM('OIDC', 'SAML');
`);
await queryRunner.query(`
CREATE TABLE "core"."workspaceSSOIdentityProvider" (
"id" uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
"name" varchar NULL,
"workspaceId" uuid NOT NULL,
"createdAt" timestamptz DEFAULT now() NOT NULL,
"updatedAt" timestamptz DEFAULT now() NOT NULL,
"type" "core"."idp_type_enum" DEFAULT 'OIDC' NOT NULL,
"issuer" varchar NOT NULL,
"ssoURL" varchar NULL,
"clientID" varchar NULL,
"clientSecret" varchar NULL,
"certificate" varchar NULL,
"fingerprint" varchar NULL,
"status" varchar DEFAULT 'Active' NOT NULL
);
`);
await queryRunner.query(`
ALTER TABLE "core"."workspaceSSOIdentityProvider"
ADD CONSTRAINT "FK_workspaceId"
FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id")
ON DELETE CASCADE;
`);
await queryRunner.query(`
ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_OIDC" CHECK (
("type" = 'OIDC' AND "clientID" IS NOT NULL AND "clientSecret" IS NOT NULL) OR "type" = 'SAML'
)
`);
await queryRunner.query(`
ALTER TABLE "core"."workspaceSSOIdentityProvider" ADD CONSTRAINT "CHK_SAML" CHECK (
("type" = 'SAML' AND "ssoURL" IS NOT NULL AND "certificate" IS NOT NULL) OR "type" = 'OIDC'
)
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE "core"."workspaceSSOIdentityProvider"
DROP CONSTRAINT "FK_workspaceId";
`);
await queryRunner.query(`
DROP TABLE "core"."workspaceSSOIdentityProvider";
`);
await queryRunner.query(`
DROP TYPE "core"."idp_type_enum";
`);
}
}

View File

@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddIsPublicInviteLinkEnabledOnWorkspace1728986317196
implements MigrationInterface
{
name = 'AddIsPublicInviteLinkEnabledOnWorkspace1728986317196';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."workspace" ADD "isPublicInviteLinkEnabled" boolean NOT NULL DEFAULT true`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."workspace" DROP COLUMN "isPublicInviteLinkEnabled"`,
);
}
}

View File

@ -13,6 +13,7 @@ import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-works
import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { WorkspaceSSOIdentityProvider } from 'src/engine/core-modules/sso/workspace-sso-identity-provider.entity';
@Injectable()
export class TypeORMService implements OnModuleInit, OnModuleDestroy {
@ -36,6 +37,7 @@ export class TypeORMService implements OnModuleInit, OnModuleDestroy {
BillingSubscription,
BillingSubscriptionItem,
PostgresCredentials,
WorkspaceSSOIdentityProvider,
],
metadataTableName: '_typeorm_generated_columns_and_materialized_views',
ssl: environmentService.get('PG_SSL_ALLOW_SELF_SIGNED')