feat(auth): centralize SSO error handling logic (#9832)

Introduce `SsoErrorRedirectService` to handle SSO error redirection and
exception capturing across the authentication controllers. Refactor
Microsoft, Google, and SSO authentication controllers to utilize this
service, replacing the previous direct calls to `DomainManagerService`.
Added unit tests for the new service to ensure robust error handling.
This commit is contained in:
Antoine Moreaux
2025-01-27 18:55:20 +01:00
committed by GitHub
parent 10476fcb01
commit 2a911b4305
19 changed files with 524 additions and 291 deletions

View File

@ -23,6 +23,7 @@ import {
OIDCResponseType,
WorkspaceSSOIdentityProvider,
} from 'src/engine/core-modules/sso/workspace-sso-identity-provider.entity';
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
@Injectable()
export class SSOService {
@ -32,6 +33,7 @@ export class SSOService {
private readonly workspaceSSOIdentityProviderRepository: Repository<WorkspaceSSOIdentityProvider>,
private readonly environmentService: EnvironmentService,
private readonly billingService: BillingService,
private readonly exceptionHandlerService: ExceptionHandlerService,
) {}
private async isSSOEnabled(workspaceId: string) {
@ -48,6 +50,17 @@ export class SSOService {
}
}
private async getIssuerForOIDC(issuerUrl: string) {
try {
return await Issuer.discover(issuerUrl);
} catch (err) {
throw new SSOException(
'Invalid issuer',
SSOExceptionCode.INVALID_ISSUER_URL,
);
}
}
async createOIDCIdentityProvider(
data: Pick<
WorkspaceSSOIdentityProvider,
@ -58,21 +71,7 @@ export class SSOService {
try {
await this.isSSOEnabled(workspaceId);
if (!data.issuer) {
throw new SSOException(
'Invalid issuer URL',
SSOExceptionCode.INVALID_ISSUER_URL,
);
}
const issuer = await Issuer.discover(data.issuer);
if (!issuer.metadata.issuer) {
throw new SSOException(
'Invalid issuer URL from discovery',
SSOExceptionCode.INVALID_ISSUER_URL,
);
}
const issuer = await this.getIssuerForOIDC(data.issuer);
const identityProvider =
await this.workspaceSSOIdentityProviderRepository.save({
@ -96,6 +95,8 @@ export class SSOService {
return err;
}
this.exceptionHandlerService.captureExceptions([err]);
return new SSOException(
'Unknown SSO configuration error',
SSOExceptionCode.UNKNOWN_SSO_CONFIGURATION_ERROR,
@ -131,6 +132,7 @@ export class SSOService {
async findSSOIdentityProviderById(identityProviderId: string) {
return (await this.workspaceSSOIdentityProviderRepository.findOne({
where: { id: identityProviderId },
relations: ['workspace'],
})) as (SSOConfiguration & WorkspaceSSOIdentityProvider) | null;
}