feat(saml): add SignatureMethod config for SAML IDP (#10520)

# Which Problems Are Solved
When a SAML IDP is created, the signing algorithm defaults to
`RSA-SHA1`.
This PR adds the functionality to configure the signing algorithm while
creating or updating a SAML IDP. When nothing is specified, `RSA-SHA1`
is the default.

Available options:
* RSA_SHA1
* RSA_SHA256
* RSA_SHA512


# How the Problems Are Solved

By introducing a new optional config to specify the Signing Algorithm. 

# Additional Changes
N/A

# Additional Context
- Closes #9842 

An existing bug in the UpdateSAMLProvider API will be fixed as a
followup in a different
[PR](https://github.com/zitadel/zitadel/pull/10557).

---------

Co-authored-by: Stefan Benz <[email protected]>
This commit is contained in:
Gayathri Vijayan
2025-08-27 09:07:13 +00:00
committed by GitHub
co-authored by Stefan Benz
parent 6699a6f966
commit 255d42da65
42 changed files with 413 additions and 7 deletions
@@ -71,6 +71,15 @@
</div>
<div *ngIf="showOptional">
<div class="transient-info">
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.SAML.SIGNATUREALGORITHM' | translate }}</cnsl-label>
<mat-select formControlName="signatureAlgorithm">
<mat-option *ngFor="let signatureAlgorithm of signatureAlgorithmValues" [value]="signatureAlgorithm">{{
signatureAlgorithm
}}</mat-option>
</mat-select>
</cnsl-form-field>
<cnsl-form-field class="formfield">
<cnsl-label>{{ 'IDP.SAML.NAMEIDFORMAT' | translate }}</cnsl-label>
<mat-select formControlName="nameIdFormat">
@@ -6,6 +6,7 @@ import {
Provider,
SAMLBinding,
SAMLNameIDFormat,
SAMLSignatureAlgorithm,
} from '../../../proto/generated/zitadel/idp_pb';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
@@ -38,6 +39,7 @@ interface SAMLProviderForm {
metadataUrl: FormControl<string>;
binding: FormControl<string>;
withSignedRequest: FormControl<boolean>;
signatureAlgorithm: FormControl<string>;
nameIdFormat: FormControl<string>;
transientMappingAttributeName: FormControl<string>;
federatedLogoutEnabled: FormControl<boolean>;
@@ -65,6 +67,7 @@ export class ProviderSamlSpComponent {
private service!: ManagementService | AdminService;
bindingValues: string[] = getEnumKeys(SAMLBinding);
nameIDFormatValues: string[] = getEnumKeys(SAMLNameIDFormat);
signatureAlgorithmValues: string[] = Object.keys(SAMLSignatureAlgorithm);
public justCreated$: BehaviorSubject<string> = new BehaviorSubject<string>('');
public justActivated$ = new BehaviorSubject<boolean>(false);
@@ -131,6 +134,9 @@ export class ProviderSamlSpComponent {
private _initializeForm(): void {
const defaultBinding = getEnumKeyFromValue(SAMLBinding, SAMLBinding.SAML_BINDING_POST) || this.bindingValues[0];
const defaultSignatureAlgorithm =
getEnumKeyFromValue(SAMLSignatureAlgorithm, SAMLSignatureAlgorithm.SAML_SIGNATURE_UNSPECIFIED) ||
this.signatureAlgorithmValues[0];
const defaultNameIdFormat =
getEnumKeyFromValue(SAMLNameIDFormat, SAMLNameIDFormat.SAML_NAME_ID_FORMAT_PERSISTENT) || this.nameIDFormatValues[0];
@@ -141,6 +147,7 @@ export class ProviderSamlSpComponent {
metadataUrl: new FormControl('', { nonNullable: true }),
binding: new FormControl(defaultBinding, { nonNullable: true, validators: [requiredValidator] }),
withSignedRequest: new FormControl(true, { nonNullable: true, validators: [requiredValidator] }),
signatureAlgorithm: new FormControl(defaultSignatureAlgorithm, { nonNullable: true }),
nameIdFormat: new FormControl(defaultNameIdFormat, { nonNullable: true }),
transientMappingAttributeName: new FormControl('', { nonNullable: true }),
federatedLogoutEnabled: new FormControl(false, { nonNullable: true }),
@@ -223,6 +230,10 @@ export class ProviderSamlSpComponent {
}
req.setWithSignedRequest(this.withSignedRequest.value);
req.setBinding(SAMLBinding[this.binding.value as keyof typeof SAMLBinding]);
req.setSignatureAlgorithm(
SAMLSignatureAlgorithm[this.signatureAlgorithm.value as keyof typeof SAMLSignatureAlgorithm],
);
// @ts-ignore
req.setNameIdFormat(SAMLNameIDFormat[this.nameIDFormat.value as keyof typeof SAMLNameIDFormat]);
req.setTransientMappingAttributeName(this.transientMapping.value);
req.setFederatedLogoutEnabled(this.federatedLogoutEnabled.value);
@@ -260,6 +271,12 @@ export class ProviderSamlSpComponent {
req.setProviderOptions(this.options);
req.setBinding(SAMLBinding[this.binding.value as keyof typeof SAMLBinding]);
req.setWithSignedRequest(this.withSignedRequest.value);
if (this.signatureAlgorithm) {
// @ts-ignore
req.setSignatureAlgorithm(
SAMLSignatureAlgorithm[this.signatureAlgorithm.value as keyof typeof SAMLSignatureAlgorithm],
);
}
if (this.nameIDFormat) {
req.setNameIdFormat(SAMLNameIDFormat[this.nameIDFormat.value as keyof typeof SAMLNameIDFormat]);
}
@@ -343,6 +360,10 @@ export class ProviderSamlSpComponent {
return this.form.controls.nameIdFormat;
}
private get signatureAlgorithm(): FormControl<string> {
return this.form.controls.signatureAlgorithm;
}
private get transientMapping(): FormControl<string> {
return this.form.controls.transientMappingAttributeName;
}