mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-24 08:12:15 +00:00
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:
co-authored by
Stefan Benz
parent
6699a6f966
commit
255d42da65
@@ -0,0 +1,27 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed 61.sql
|
||||
addSAMLSignatureAlgorithm string
|
||||
)
|
||||
|
||||
type IDPTemplate6SAMLSignatureAlgorithm struct {
|
||||
dbClient *database.DB
|
||||
}
|
||||
|
||||
func (mig *IDPTemplate6SAMLSignatureAlgorithm) Execute(ctx context.Context, _ eventstore.Event) error {
|
||||
_, err := mig.dbClient.ExecContext(ctx, addSAMLSignatureAlgorithm)
|
||||
return err
|
||||
}
|
||||
|
||||
func (mig *IDPTemplate6SAMLSignatureAlgorithm) String() string {
|
||||
return "61_idp_templates6_add_saml_signature_algorithm"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE IF EXISTS projections.idp_templates6_saml ADD COLUMN IF NOT EXISTS signature_algorithm TEXT;
|
||||
@@ -157,6 +157,7 @@ type Steps struct {
|
||||
s58ReplaceLoginNames3View *ReplaceLoginNames3View
|
||||
s59SetupWebkeys *SetupWebkeys
|
||||
s60GenerateSystemID *GenerateSystemID
|
||||
s61IDPTemplate6SAMLSignatureAlgorithm *IDPTemplate6SAMLSignatureAlgorithm
|
||||
}
|
||||
|
||||
func MustNewSteps(v *viper.Viper) *Steps {
|
||||
|
||||
@@ -218,6 +218,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
|
||||
steps.s57CreateResourceCounts = &CreateResourceCounts{dbClient: dbClient}
|
||||
steps.s58ReplaceLoginNames3View = &ReplaceLoginNames3View{dbClient: dbClient}
|
||||
steps.s60GenerateSystemID = &GenerateSystemID{eventstore: eventstoreClient}
|
||||
steps.s61IDPTemplate6SAMLSignatureAlgorithm = &IDPTemplate6SAMLSignatureAlgorithm{dbClient: dbClient}
|
||||
|
||||
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil, nil)
|
||||
logging.OnError(err).Fatal("unable to start projections")
|
||||
@@ -266,6 +267,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
|
||||
steps.s57CreateResourceCounts,
|
||||
steps.s58ReplaceLoginNames3View,
|
||||
steps.s60GenerateSystemID,
|
||||
steps.s61IDPTemplate6SAMLSignatureAlgorithm,
|
||||
} {
|
||||
setupErr = executeMigration(ctx, eventstoreClient, step, "migration failed")
|
||||
if setupErr != nil {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2373,6 +2373,7 @@
|
||||
"METADATAURL": "Metadata URL",
|
||||
"BINDING": "Binding",
|
||||
"SIGNEDREQUEST": "Signed Request",
|
||||
"SIGNATUREALGORITHM": "Signature Algorithm",
|
||||
"NAMEIDFORMAT": "NameID Format",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME": "Custom Mapping Attribute Name",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME_DESC": "Alternative attribute name to map the user in case the `nameid-format` returned is `transient`, e.g. `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`"
|
||||
|
||||
@@ -2368,6 +2368,7 @@
|
||||
"METADATAURL": "Metaadatok URL",
|
||||
"BINDING": "Kötés",
|
||||
"SIGNEDREQUEST": "Aláírt kérés",
|
||||
"SIGNATUREALGORITHM": "Aláírási algoritmus",
|
||||
"NAMEIDFORMAT": "NameID formátum",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME": "Egyéni leképezési attribútumnév",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME_DESC": "Alternatív attribútumnév a felhasználó leképezéséhez, ha a visszakapott `nameid-format` `transient`, pl. `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`"
|
||||
|
||||
@@ -2150,6 +2150,7 @@
|
||||
"METADATAURL": "URL metadata",
|
||||
"BINDING": "Mengikat",
|
||||
"SIGNEDREQUEST": "Permintaan yang Ditandatangani",
|
||||
"SIGNATUREALGORITHM": "Algoritma tanda tangan",
|
||||
"NAMEIDFORMAT": "Format ID Nama",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME": "Nama Atribut Pemetaan Khusus",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME_DESC": "Nama atribut alternatif untuk memetakan pengguna jika `format nameid` yang dikembalikan adalah `sementara`, mis. `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`"
|
||||
|
||||
@@ -2370,6 +2370,7 @@
|
||||
"METADATAURL": "Metadata URL",
|
||||
"BINDING": "Binding",
|
||||
"SIGNEDREQUEST": "署名付きリクエスト",
|
||||
"SIGNATUREALGORITHM": "署名アルゴリズム",
|
||||
"NAMEIDFORMAT": "NameIDフォーマット",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME": "カスタム属性名",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME_DESC": "NameIDフォーマットが`transient`の場合にユーザーをマッピングするためのカスタム属性名 (例: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`)"
|
||||
|
||||
@@ -2370,6 +2370,7 @@
|
||||
"METADATAURL": "메타데이터 URL",
|
||||
"BINDING": "바인딩",
|
||||
"SIGNEDREQUEST": "서명된 요청",
|
||||
"SIGNATUREALGORITHM": "서명 알고리즘",
|
||||
"NAMEIDFORMAT": "NameID 형식",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME": "사용자 매핑 속성 이름",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME_DESC": "`nameid-format`이 `transient`인 경우 사용자 매핑에 사용할 대체 속성 이름, 예: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`"
|
||||
|
||||
@@ -2369,7 +2369,8 @@
|
||||
"METADATAXML": "Metadata Xml",
|
||||
"METADATAURL": "Metadata URL",
|
||||
"BINDING": "Binding",
|
||||
"SIGNEDREQUEST": "Ondertekend Verzoek"
|
||||
"SIGNEDREQUEST": "Ondertekend Verzoek",
|
||||
"SIGNATUREALGORITHM": "Handtekeningalgoritme"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Succesvol opgeslagen.",
|
||||
|
||||
@@ -2368,6 +2368,7 @@
|
||||
"METADATAURL": "URL metadata",
|
||||
"BINDING": "Legare",
|
||||
"SIGNEDREQUEST": "Solicitare semnată",
|
||||
"SIGNATUREALGORITHM": "Algoritm de semnătură",
|
||||
"NAMEIDFORMAT": "Format ID nume",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME": "Nume atribut mapare personalizat",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME_DESC": "Nume alternativ de atribut pentru a mapa utilizatorul în cazul în care nameid-format returnat este tranzitoriu, de exemplu, http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
|
||||
|
||||
@@ -2373,6 +2373,7 @@
|
||||
"METADATAURL": "Metadata URL",
|
||||
"BINDING": "Binding",
|
||||
"SIGNEDREQUEST": "İmzalı İstek",
|
||||
"SIGNATUREALGORITHM": "İmza algoritması",
|
||||
"NAMEIDFORMAT": "NameID Formatı",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME": "Özel Eşleme Özellik Adı",
|
||||
"TRANSIENTMAPPINGATTRIBUTENAME_DESC": "`nameid-format` `transient` döndürülmesi durumunda kullanıcıyı eşlemek için alternatif özellik adı, örn. `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`"
|
||||
|
||||
@@ -3,6 +3,7 @@ package admin
|
||||
import (
|
||||
"github.com/crewjam/saml"
|
||||
"github.com/muhlemmer/gu"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
|
||||
idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||
@@ -480,12 +481,14 @@ func addSAMLProviderToCommand(req *admin_pb.AddSAMLProviderRequest) *command.SAM
|
||||
if req.NameIdFormat != nil {
|
||||
nameIDFormat = gu.Ptr(idp_grpc.SAMLNameIDFormatToDomain(req.GetNameIdFormat()))
|
||||
}
|
||||
|
||||
return &command.SAMLProvider{
|
||||
Name: req.Name,
|
||||
Metadata: req.GetMetadataXml(),
|
||||
MetadataURL: req.GetMetadataUrl(),
|
||||
Binding: bindingToCommand(req.Binding),
|
||||
WithSignedRequest: req.WithSignedRequest,
|
||||
SignatureAlgorithm: signatureAlgorithmToCommand(req.GetSignatureAlgorithm()),
|
||||
NameIDFormat: nameIDFormat,
|
||||
TransientMappingAttributeName: req.GetTransientMappingAttributeName(),
|
||||
FederatedLogoutEnabled: req.GetFederatedLogoutEnabled(),
|
||||
@@ -498,12 +501,14 @@ func updateSAMLProviderToCommand(req *admin_pb.UpdateSAMLProviderRequest) *comma
|
||||
if req.NameIdFormat != nil {
|
||||
nameIDFormat = gu.Ptr(idp_grpc.SAMLNameIDFormatToDomain(req.GetNameIdFormat()))
|
||||
}
|
||||
|
||||
return &command.SAMLProvider{
|
||||
Name: req.Name,
|
||||
Metadata: req.GetMetadataXml(),
|
||||
MetadataURL: req.GetMetadataUrl(),
|
||||
Binding: bindingToCommand(req.Binding),
|
||||
WithSignedRequest: req.WithSignedRequest,
|
||||
SignatureAlgorithm: signatureAlgorithmToCommand(req.GetSignatureAlgorithm()),
|
||||
NameIDFormat: nameIDFormat,
|
||||
TransientMappingAttributeName: req.GetTransientMappingAttributeName(),
|
||||
FederatedLogoutEnabled: req.GetFederatedLogoutEnabled(),
|
||||
@@ -525,3 +530,18 @@ func bindingToCommand(binding idp_pb.SAMLBinding) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func signatureAlgorithmToCommand(signatureAlgorithm idp_pb.SAMLSignatureAlgorithm) string {
|
||||
switch signatureAlgorithm {
|
||||
case idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_UNSPECIFIED:
|
||||
return ""
|
||||
case idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1:
|
||||
return dsig.RSASHA1SignatureMethod
|
||||
case idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA256:
|
||||
return dsig.RSASHA256SignatureMethod
|
||||
case idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA512:
|
||||
return dsig.RSASHA512SignatureMethod
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package admin
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/test"
|
||||
admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/idp"
|
||||
@@ -157,3 +159,40 @@ func Test_updateOIDCConfigToDomain(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_signatureAlgorithmToCommand(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
signatureAlgorithm idp.SAMLSignatureAlgorithm
|
||||
wantSignatureAlgorithm string
|
||||
}{
|
||||
{
|
||||
name: "signature algorithm default value",
|
||||
signatureAlgorithm: 11,
|
||||
wantSignatureAlgorithm: "",
|
||||
},
|
||||
{
|
||||
name: "RSA_SHA1",
|
||||
signatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1,
|
||||
wantSignatureAlgorithm: "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
|
||||
},
|
||||
{
|
||||
name: "RSA_SHA256",
|
||||
signatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA256,
|
||||
wantSignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
},
|
||||
{
|
||||
name: "RSA_SHA512",
|
||||
signatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA512,
|
||||
wantSignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got := signatureAlgorithmToCommand(tt.signatureAlgorithm)
|
||||
require.Equal(t, tt.wantSignatureAlgorithm, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package idp
|
||||
import (
|
||||
"github.com/crewjam/saml"
|
||||
"github.com/muhlemmer/gu"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
|
||||
obj_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||
@@ -667,6 +668,7 @@ func samlConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.SAMLI
|
||||
MetadataXml: template.Metadata,
|
||||
Binding: bindingToPb(template.Binding),
|
||||
WithSignedRequest: template.WithSignedRequest,
|
||||
SignatureAlgorithm: gu.Ptr(signatureAlgorithmToPb(template.SignatureAlgorithm)),
|
||||
NameIdFormat: nameIDFormat,
|
||||
TransientMappingAttributeName: gu.Ptr(template.TransientMappingAttributeName),
|
||||
FederatedLogoutEnabled: gu.Ptr(template.FederatedLogoutEnabled),
|
||||
@@ -703,3 +705,16 @@ func nameIDToPb(format domain.SAMLNameIDFormat) idp_pb.SAMLNameIDFormat {
|
||||
return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func signatureAlgorithmToPb(signatureAlgorithm string) idp_pb.SAMLSignatureAlgorithm {
|
||||
switch signatureAlgorithm {
|
||||
case dsig.RSASHA1SignatureMethod:
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1
|
||||
case dsig.RSASHA256SignatureMethod:
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA256
|
||||
case dsig.RSASHA512SignatureMethod:
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA512
|
||||
default:
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"connectrpc.com/connect"
|
||||
"github.com/crewjam/saml"
|
||||
"github.com/muhlemmer/gu"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
@@ -335,6 +336,7 @@ func samlConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.SAMLIDPTemplate
|
||||
MetadataXml: template.Metadata,
|
||||
Binding: bindingToPb(template.Binding),
|
||||
WithSignedRequest: template.WithSignedRequest,
|
||||
SignatureAlgorithm: signatureAlgorithmToPb(template.SignatureAlgorithm),
|
||||
NameIdFormat: nameIDFormat,
|
||||
TransientMappingAttributeName: gu.Ptr(template.TransientMappingAttributeName),
|
||||
FederatedLogoutEnabled: gu.Ptr(template.FederatedLogoutEnabled),
|
||||
@@ -371,3 +373,16 @@ func nameIDToPb(format domain.SAMLNameIDFormat) idp_pb.SAMLNameIDFormat {
|
||||
return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func signatureAlgorithmToPb(signatureAlgorithm string) idp_pb.SAMLSignatureAlgorithm {
|
||||
switch signatureAlgorithm {
|
||||
case dsig.RSASHA1SignatureMethod:
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1
|
||||
case dsig.RSASHA256SignatureMethod:
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA256
|
||||
case dsig.RSASHA512SignatureMethod:
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA512
|
||||
default:
|
||||
return idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/crewjam/saml"
|
||||
"github.com/muhlemmer/gu"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp"
|
||||
@@ -473,12 +474,14 @@ func addSAMLProviderToCommand(req *mgmt_pb.AddSAMLProviderRequest) *command.SAML
|
||||
if req.NameIdFormat != nil {
|
||||
nameIDFormat = gu.Ptr(idp_grpc.SAMLNameIDFormatToDomain(req.GetNameIdFormat()))
|
||||
}
|
||||
|
||||
return &command.SAMLProvider{
|
||||
Name: req.Name,
|
||||
Metadata: req.GetMetadataXml(),
|
||||
MetadataURL: req.GetMetadataUrl(),
|
||||
Binding: bindingToCommand(req.Binding),
|
||||
WithSignedRequest: req.WithSignedRequest,
|
||||
SignatureAlgorithm: signatureAlgorithmToCommand(req.GetSignatureAlgorithm()),
|
||||
NameIDFormat: nameIDFormat,
|
||||
TransientMappingAttributeName: req.GetTransientMappingAttributeName(),
|
||||
FederatedLogoutEnabled: req.GetFederatedLogoutEnabled(),
|
||||
@@ -491,12 +494,14 @@ func updateSAMLProviderToCommand(req *mgmt_pb.UpdateSAMLProviderRequest) *comman
|
||||
if req.NameIdFormat != nil {
|
||||
nameIDFormat = gu.Ptr(idp_grpc.SAMLNameIDFormatToDomain(req.GetNameIdFormat()))
|
||||
}
|
||||
|
||||
return &command.SAMLProvider{
|
||||
Name: req.Name,
|
||||
Metadata: req.GetMetadataXml(),
|
||||
MetadataURL: req.GetMetadataUrl(),
|
||||
Binding: bindingToCommand(req.Binding),
|
||||
WithSignedRequest: req.WithSignedRequest,
|
||||
SignatureAlgorithm: signatureAlgorithmToCommand(req.GetSignatureAlgorithm()),
|
||||
NameIDFormat: nameIDFormat,
|
||||
TransientMappingAttributeName: req.GetTransientMappingAttributeName(),
|
||||
FederatedLogoutEnabled: req.GetFederatedLogoutEnabled(),
|
||||
@@ -518,3 +523,18 @@ func bindingToCommand(binding idp_pb.SAMLBinding) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func signatureAlgorithmToCommand(signatureAlgorithm idp_pb.SAMLSignatureAlgorithm) string {
|
||||
switch signatureAlgorithm {
|
||||
case idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_UNSPECIFIED:
|
||||
return ""
|
||||
case idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1:
|
||||
return dsig.RSASHA1SignatureMethod
|
||||
case idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA256:
|
||||
return dsig.RSASHA256SignatureMethod
|
||||
case idp_pb.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA512:
|
||||
return dsig.RSASHA512SignatureMethod
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package management
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/test"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/idp"
|
||||
mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management"
|
||||
@@ -157,3 +159,40 @@ func Test_updateOIDCConfigToDomain(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_signatureAlgorithmToCommand(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
signatureAlgorithm idp.SAMLSignatureAlgorithm
|
||||
wantSignatureAlgorithm string
|
||||
}{
|
||||
{
|
||||
name: "signature algorithm default value",
|
||||
signatureAlgorithm: 11,
|
||||
wantSignatureAlgorithm: "",
|
||||
},
|
||||
{
|
||||
name: "RSA_SHA1",
|
||||
signatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1,
|
||||
wantSignatureAlgorithm: "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
|
||||
},
|
||||
{
|
||||
name: "RSA_SHA256",
|
||||
signatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA256,
|
||||
wantSignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
},
|
||||
{
|
||||
name: "RSA_SHA512",
|
||||
signatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA512,
|
||||
wantSignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got := signatureAlgorithmToCommand(tt.signatureAlgorithm)
|
||||
require.Equal(t, tt.wantSignatureAlgorithm, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ type SAMLProvider struct {
|
||||
MetadataURL string
|
||||
Binding string
|
||||
WithSignedRequest bool
|
||||
SignatureAlgorithm string
|
||||
NameIDFormat *domain.SAMLNameIDFormat
|
||||
TransientMappingAttributeName string
|
||||
FederatedLogoutEnabled bool
|
||||
|
||||
@@ -737,6 +737,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
gu.Ptr(domain.SAMLNameIDFormatUnspecified),
|
||||
"",
|
||||
false,
|
||||
@@ -758,6 +759,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
|
||||
}, []byte("-----BEGIN CERTIFICATE-----\nMIIC2zCCAcOgAwIBAgIIAy/jm1gAAdEwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UE\nChMHWklUQURFTDAeFw0yMzA4MzAwNzExMTVaFw0yNDA4MjkwNzExMTVaMBIxEDAO\nBgNVBAoTB1pJVEFERUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDE\nd3TztGgSb3LBVZn8f60NbFCyZW+F9HPiMCr9F9T45Zc0fgmMwxId0WzRD5Y/3yc1\ndHJzt+Bsxvw12aUHbIPiothqk3lINoFzl2H/cSfIW3nehKyNOUqdBQ8B4mvaqH81\njTjoJ/JTJAwzglHk6JAWjhOyx9aep1yBqYa3QASeTaW9sxkpB0Co1L2UPNhuMwZq\n8RA9NkTfmYVcVBeNqihler5MhruFtqrv+J0ftwc1stw8uCN89ADyr4Ni+e+FeWar\nQs9Bkfc6KLF/5IXa9HCsHNPaaoYPY6I6RSaG4/DKoSKIEe1/GSVG1FTpZ8trUZxv\nU+xXS6gEalXcrJsiX8aXAgMBAAGjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE\nDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCx\n/dRNIj0N/16zJhZR/ahkc2AkvDXYxyr4JRT5wK9GQDNl/oaX3debRuSi/tfaXFIX\naJA6PxM4J49ZaiEpLrKfxMz5kAhjKchCBEMcH3mGt+iNZH7EOyTvHjpGrP2OZrsh\nO17yrvN3HuQxIU6roJlqtZz2iAADsoPtwOO4D7hupm9XTMkSnAmlMWOo/q46Jz89\n1sMxB+dXmH/zV0wgwh0omZfLV0u89mvdq269VhcjNBpBYSnN1ccqYWd5iwziob3I\nvaavGHGfkbvRUn/tKftYuTK30q03R+e9YbmlWZ0v695owh2e/apCzowQsCKfSVC8\nOxVyt5XkHq1tWwVyBmFp\n-----END CERTIFICATE-----\n"),
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
gu.Ptr(domain.SAMLNameIDFormatUnspecified),
|
||||
"",
|
||||
false,
|
||||
@@ -828,6 +830,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
gu.Ptr(domain.SAMLNameIDFormatUnspecified),
|
||||
"",
|
||||
false,
|
||||
@@ -849,6 +852,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
|
||||
}, []byte("-----BEGIN CERTIFICATE-----\nMIIC2zCCAcOgAwIBAgIIAy/jm1gAAdEwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UE\nChMHWklUQURFTDAeFw0yMzA4MzAwNzExMTVaFw0yNDA4MjkwNzExMTVaMBIxEDAO\nBgNVBAoTB1pJVEFERUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDE\nd3TztGgSb3LBVZn8f60NbFCyZW+F9HPiMCr9F9T45Zc0fgmMwxId0WzRD5Y/3yc1\ndHJzt+Bsxvw12aUHbIPiothqk3lINoFzl2H/cSfIW3nehKyNOUqdBQ8B4mvaqH81\njTjoJ/JTJAwzglHk6JAWjhOyx9aep1yBqYa3QASeTaW9sxkpB0Co1L2UPNhuMwZq\n8RA9NkTfmYVcVBeNqihler5MhruFtqrv+J0ftwc1stw8uCN89ADyr4Ni+e+FeWar\nQs9Bkfc6KLF/5IXa9HCsHNPaaoYPY6I6RSaG4/DKoSKIEe1/GSVG1FTpZ8trUZxv\nU+xXS6gEalXcrJsiX8aXAgMBAAGjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE\nDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCx\n/dRNIj0N/16zJhZR/ahkc2AkvDXYxyr4JRT5wK9GQDNl/oaX3debRuSi/tfaXFIX\naJA6PxM4J49ZaiEpLrKfxMz5kAhjKchCBEMcH3mGt+iNZH7EOyTvHjpGrP2OZrsh\nO17yrvN3HuQxIU6roJlqtZz2iAADsoPtwOO4D7hupm9XTMkSnAmlMWOo/q46Jz89\n1sMxB+dXmH/zV0wgwh0omZfLV0u89mvdq269VhcjNBpBYSnN1ccqYWd5iwziob3I\nvaavGHGfkbvRUn/tKftYuTK30q03R+e9YbmlWZ0v695owh2e/apCzowQsCKfSVC8\nOxVyt5XkHq1tWwVyBmFp\n-----END CERTIFICATE-----\n"),
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
gu.Ptr(domain.SAMLNameIDFormatUnspecified),
|
||||
"",
|
||||
false,
|
||||
|
||||
@@ -1758,6 +1758,7 @@ type SAMLIDPWriteModel struct {
|
||||
Certificate []byte
|
||||
Binding string
|
||||
WithSignedRequest bool
|
||||
SignatureAlgorithm string
|
||||
NameIDFormat *domain.SAMLNameIDFormat
|
||||
TransientMappingAttributeName string
|
||||
FederatedLogoutEnabled bool
|
||||
@@ -1787,6 +1788,7 @@ func (wm *SAMLIDPWriteModel) reduceAddedEvent(e *idp.SAMLIDPAddedEvent) {
|
||||
wm.Certificate = e.Certificate
|
||||
wm.Binding = e.Binding
|
||||
wm.WithSignedRequest = e.WithSignedRequest
|
||||
wm.SignatureAlgorithm = e.SignatureAlgorithm
|
||||
wm.NameIDFormat = e.NameIDFormat
|
||||
wm.TransientMappingAttributeName = e.TransientMappingAttributeName
|
||||
wm.FederatedLogoutEnabled = e.FederatedLogoutEnabled
|
||||
@@ -1813,6 +1815,9 @@ func (wm *SAMLIDPWriteModel) reduceChangedEvent(e *idp.SAMLIDPChangedEvent) {
|
||||
if e.WithSignedRequest != nil {
|
||||
wm.WithSignedRequest = *e.WithSignedRequest
|
||||
}
|
||||
if e.SignatureAlgorithm != nil {
|
||||
wm.SignatureAlgorithm = *e.SignatureAlgorithm
|
||||
}
|
||||
if e.NameIDFormat != nil {
|
||||
wm.NameIDFormat = e.NameIDFormat
|
||||
}
|
||||
@@ -1833,6 +1838,7 @@ func (wm *SAMLIDPWriteModel) NewChanges(
|
||||
secretCrypto crypto.EncryptionAlgorithm,
|
||||
binding string,
|
||||
withSignedRequest bool,
|
||||
signatureAlgorithm string,
|
||||
nameIDFormat *domain.SAMLNameIDFormat,
|
||||
transientMappingAttributeName string,
|
||||
federatedLogoutEnabled bool,
|
||||
@@ -1861,6 +1867,9 @@ func (wm *SAMLIDPWriteModel) NewChanges(
|
||||
if wm.WithSignedRequest != withSignedRequest {
|
||||
changes = append(changes, idp.ChangeSAMLWithSignedRequest(withSignedRequest))
|
||||
}
|
||||
if wm.SignatureAlgorithm != signatureAlgorithm {
|
||||
changes = append(changes, idp.ChangeSAMLSignatureAlgorithm(signatureAlgorithm))
|
||||
}
|
||||
if wm.NameIDFormat != nameIDFormat {
|
||||
changes = append(changes, idp.ChangeSAMLNameIDFormat(nameIDFormat))
|
||||
}
|
||||
@@ -1902,6 +1911,9 @@ func (wm *SAMLIDPWriteModel) ToProvider(callbackURL string, idpAlg crypto.Encryp
|
||||
if wm.Binding != "" {
|
||||
opts = append(opts, saml2.WithBinding(wm.Binding))
|
||||
}
|
||||
if wm.WithSignedRequest && wm.SignatureAlgorithm != "" {
|
||||
opts = append(opts, saml2.WithSignatureAlgorithm(wm.SignatureAlgorithm))
|
||||
}
|
||||
if wm.NameIDFormat != nil {
|
||||
opts = append(opts, saml2.WithNameIDFormat(*wm.NameIDFormat))
|
||||
}
|
||||
|
||||
@@ -1793,6 +1793,7 @@ func (c *Commands) prepareAddInstanceSAMLProvider(a *instance.Aggregate, writeMo
|
||||
cert,
|
||||
provider.Binding,
|
||||
provider.WithSignedRequest,
|
||||
provider.SignatureAlgorithm,
|
||||
provider.NameIDFormat,
|
||||
provider.TransientMappingAttributeName,
|
||||
provider.FederatedLogoutEnabled,
|
||||
@@ -1847,6 +1848,7 @@ func (c *Commands) prepareUpdateInstanceSAMLProvider(a *instance.Aggregate, writ
|
||||
c.idpConfigEncryption,
|
||||
provider.Binding,
|
||||
provider.WithSignedRequest,
|
||||
provider.SignatureAlgorithm,
|
||||
provider.NameIDFormat,
|
||||
provider.TransientMappingAttributeName,
|
||||
provider.FederatedLogoutEnabled,
|
||||
@@ -1893,6 +1895,7 @@ func (c *Commands) prepareRegenerateInstanceSAMLProviderCertificate(a *instance.
|
||||
c.idpConfigEncryption,
|
||||
writeModel.Binding,
|
||||
writeModel.WithSignedRequest,
|
||||
writeModel.SignatureAlgorithm,
|
||||
writeModel.NameIDFormat,
|
||||
writeModel.TransientMappingAttributeName,
|
||||
writeModel.FederatedLogoutEnabled,
|
||||
|
||||
@@ -921,6 +921,7 @@ func (wm *InstanceSAMLIDPWriteModel) NewChangedEvent(
|
||||
secretCrypto crypto.EncryptionAlgorithm,
|
||||
binding string,
|
||||
withSignedRequest bool,
|
||||
signatureAlgorithm string,
|
||||
nameIDFormat *domain.SAMLNameIDFormat,
|
||||
transientMappingAttributeName string,
|
||||
federatedLogoutEnabled bool,
|
||||
@@ -934,6 +935,7 @@ func (wm *InstanceSAMLIDPWriteModel) NewChangedEvent(
|
||||
secretCrypto,
|
||||
binding,
|
||||
withSignedRequest,
|
||||
signatureAlgorithm,
|
||||
nameIDFormat,
|
||||
transientMappingAttributeName,
|
||||
federatedLogoutEnabled,
|
||||
|
||||
@@ -5435,6 +5435,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
nil,
|
||||
"",
|
||||
false,
|
||||
@@ -5477,6 +5478,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"binding",
|
||||
true,
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
gu.Ptr(domain.SAMLNameIDFormatTransient),
|
||||
"customAttribute",
|
||||
true,
|
||||
@@ -5500,6 +5502,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) {
|
||||
Metadata: validSAMLMetadata,
|
||||
Binding: "binding",
|
||||
WithSignedRequest: true,
|
||||
SignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
NameIDFormat: gu.Ptr(domain.SAMLNameIDFormatTransient),
|
||||
TransientMappingAttributeName: "customAttribute",
|
||||
FederatedLogoutEnabled: true,
|
||||
@@ -5666,6 +5669,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
nil,
|
||||
"",
|
||||
false,
|
||||
@@ -5705,6 +5709,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"binding",
|
||||
false,
|
||||
"",
|
||||
gu.Ptr(domain.SAMLNameIDFormatUnspecified),
|
||||
"",
|
||||
false,
|
||||
@@ -5850,6 +5855,7 @@ func TestCommandSide_RegenerateInstanceSAMLProviderCertificate(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"binding",
|
||||
false,
|
||||
"",
|
||||
gu.Ptr(domain.SAMLNameIDFormatUnspecified),
|
||||
"",
|
||||
false,
|
||||
|
||||
@@ -1766,6 +1766,7 @@ func (c *Commands) prepareAddOrgSAMLProvider(a *org.Aggregate, writeModel *OrgSA
|
||||
cert,
|
||||
provider.Binding,
|
||||
provider.WithSignedRequest,
|
||||
provider.SignatureAlgorithm,
|
||||
provider.NameIDFormat,
|
||||
provider.TransientMappingAttributeName,
|
||||
provider.FederatedLogoutEnabled,
|
||||
@@ -1820,6 +1821,7 @@ func (c *Commands) prepareUpdateOrgSAMLProvider(a *org.Aggregate, writeModel *Or
|
||||
c.idpConfigEncryption,
|
||||
provider.Binding,
|
||||
provider.WithSignedRequest,
|
||||
provider.SignatureAlgorithm,
|
||||
provider.NameIDFormat,
|
||||
provider.TransientMappingAttributeName,
|
||||
provider.FederatedLogoutEnabled,
|
||||
@@ -1866,6 +1868,7 @@ func (c *Commands) prepareRegenerateOrgSAMLProviderCertificate(a *org.Aggregate,
|
||||
c.idpConfigEncryption,
|
||||
writeModel.Binding,
|
||||
writeModel.WithSignedRequest,
|
||||
writeModel.SignatureAlgorithm,
|
||||
writeModel.NameIDFormat,
|
||||
writeModel.TransientMappingAttributeName,
|
||||
writeModel.FederatedLogoutEnabled,
|
||||
|
||||
@@ -933,6 +933,7 @@ func (wm *OrgSAMLIDPWriteModel) NewChangedEvent(
|
||||
secretCrypto crypto.EncryptionAlgorithm,
|
||||
binding string,
|
||||
withSignedRequest bool,
|
||||
signatureAlgorithm string,
|
||||
nameIDFormat *domain.SAMLNameIDFormat,
|
||||
transientMappingAttributeName string,
|
||||
federatedLogoutEnabled bool,
|
||||
@@ -946,6 +947,7 @@ func (wm *OrgSAMLIDPWriteModel) NewChangedEvent(
|
||||
secretCrypto,
|
||||
binding,
|
||||
withSignedRequest,
|
||||
signatureAlgorithm,
|
||||
nameIDFormat,
|
||||
transientMappingAttributeName,
|
||||
federatedLogoutEnabled,
|
||||
|
||||
@@ -5517,6 +5517,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
nil,
|
||||
"",
|
||||
false,
|
||||
@@ -5559,6 +5560,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"binding",
|
||||
true,
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
gu.Ptr(domain.SAMLNameIDFormatTransient),
|
||||
"customAttribute",
|
||||
true,
|
||||
@@ -5583,6 +5585,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) {
|
||||
Metadata: validSAMLMetadata,
|
||||
Binding: "binding",
|
||||
WithSignedRequest: true,
|
||||
SignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
NameIDFormat: gu.Ptr(domain.SAMLNameIDFormatTransient),
|
||||
TransientMappingAttributeName: "customAttribute",
|
||||
FederatedLogoutEnabled: true,
|
||||
@@ -5757,6 +5760,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
nil,
|
||||
"",
|
||||
false,
|
||||
@@ -5797,6 +5801,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"binding",
|
||||
false,
|
||||
"",
|
||||
gu.Ptr(domain.SAMLNameIDFormatUnspecified),
|
||||
"",
|
||||
false,
|
||||
@@ -5948,6 +5953,7 @@ func TestCommandSide_RegenerateOrgSAMLProviderCertificate(t *testing.T) {
|
||||
[]byte("certificate"),
|
||||
"binding",
|
||||
false,
|
||||
"",
|
||||
gu.Ptr(domain.SAMLNameIDFormatUnspecified),
|
||||
"",
|
||||
false,
|
||||
|
||||
@@ -32,6 +32,7 @@ type Provider struct {
|
||||
spOptions *samlsp.Options
|
||||
|
||||
binding string
|
||||
signatureAlgorithm string
|
||||
nameIDFormat saml.NameIDFormat
|
||||
transientMappingAttributeName string
|
||||
|
||||
@@ -84,6 +85,12 @@ func WithBinding(binding string) ProviderOpts {
|
||||
}
|
||||
}
|
||||
|
||||
func WithSignatureAlgorithm(signatureAlgorithm string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.signatureAlgorithm = signatureAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
func WithNameIDFormat(format domain.SAMLNameIDFormat) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.nameIDFormat = nameIDFormatFromDomain(format)
|
||||
@@ -219,6 +226,9 @@ func (p *Provider) GetSP() (*samlsp.Middleware, error) {
|
||||
if p.binding != "" {
|
||||
sp.Binding = p.binding
|
||||
}
|
||||
if p.signatureAlgorithm != "" {
|
||||
sp.ServiceProvider.SignatureMethod = p.signatureAlgorithm
|
||||
}
|
||||
sp.ServiceProvider.MetadataValidDuration = time.Until(sp.ServiceProvider.Certificate.NotAfter)
|
||||
return sp, nil
|
||||
}
|
||||
|
||||
@@ -165,6 +165,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
nameIDFormat saml.NameIDFormat
|
||||
transientMappingAttributeName string
|
||||
withSignedRequest bool
|
||||
signatureAlgorithm string
|
||||
requesttracker samlsp.RequestTracker
|
||||
entityID string
|
||||
}
|
||||
@@ -257,6 +258,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
WithAutoUpdate(),
|
||||
WithBinding("binding"),
|
||||
WithSignedRequest(),
|
||||
WithSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"),
|
||||
WithCustomRequestTracker(&requesttracker.RequestTracker{}),
|
||||
WithEntityID("entityID"),
|
||||
WithNameIDFormat(domain.SAMLNameIDFormatTransient),
|
||||
@@ -274,6 +276,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
nameIDFormat: saml.TransientNameIDFormat,
|
||||
transientMappingAttributeName: "attribute",
|
||||
withSignedRequest: true,
|
||||
signatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
requesttracker: &requesttracker.RequestTracker{},
|
||||
},
|
||||
},
|
||||
@@ -297,6 +300,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
a.Equal(tt.want.nameIDFormat, provider.nameIDFormat)
|
||||
a.Equal(tt.want.transientMappingAttributeName, provider.transientMappingAttributeName)
|
||||
a.Equal(tt.want.withSignedRequest, provider.spOptions.SignRequest)
|
||||
a.Equal(tt.want.signatureAlgorithm, provider.signatureAlgorithm)
|
||||
a.Equal(tt.want.requesttracker, provider.requestTracker)
|
||||
a.Equal(tt.want.entityID, provider.spOptions.EntityID)
|
||||
}
|
||||
|
||||
@@ -163,6 +163,7 @@ type SAMLIDPTemplate struct {
|
||||
Certificate []byte
|
||||
Binding string
|
||||
WithSignedRequest bool
|
||||
SignatureAlgorithm string
|
||||
NameIDFormat sql.Null[domain.SAMLNameIDFormat]
|
||||
TransientMappingAttributeName string
|
||||
FederatedLogoutEnabled bool
|
||||
@@ -717,6 +718,10 @@ var (
|
||||
name: projection.SAMLWithSignedRequestCol,
|
||||
table: samlIdpTemplateTable,
|
||||
}
|
||||
SAMLSignatureAlgorithmCol = Column{
|
||||
name: projection.SAMLSignatureAlgorithmCol,
|
||||
table: samlIdpTemplateTable,
|
||||
}
|
||||
SAMLNameIDFormatCol = Column{
|
||||
name: projection.SAMLNameIDFormatCol,
|
||||
table: samlIdpTemplateTable,
|
||||
@@ -951,6 +956,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
SAMLCertificateCol.identifier(),
|
||||
SAMLBindingCol.identifier(),
|
||||
SAMLWithSignedRequestCol.identifier(),
|
||||
SAMLSignatureAlgorithmCol.identifier(),
|
||||
SAMLNameIDFormatCol.identifier(),
|
||||
SAMLTransientMappingAttributeNameCol.identifier(),
|
||||
SAMLFederatedLogoutEnabledCol.identifier(),
|
||||
@@ -1071,6 +1077,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
var samlCertificate []byte
|
||||
samlBinding := sql.NullString{}
|
||||
samlWithSignedRequest := sql.NullBool{}
|
||||
samlSignatureAlgorithm := sql.NullString{}
|
||||
samlNameIDFormat := sql.Null[domain.SAMLNameIDFormat]{}
|
||||
samlTransientMappingAttributeName := sql.NullString{}
|
||||
samlFederatedLogoutEnabled := sql.NullBool{}
|
||||
@@ -1189,6 +1196,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
&samlCertificate,
|
||||
&samlBinding,
|
||||
&samlWithSignedRequest,
|
||||
&samlSignatureAlgorithm,
|
||||
&samlNameIDFormat,
|
||||
&samlTransientMappingAttributeName,
|
||||
&samlFederatedLogoutEnabled,
|
||||
@@ -1329,6 +1337,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
Certificate: samlCertificate,
|
||||
Binding: samlBinding.String,
|
||||
WithSignedRequest: samlWithSignedRequest.Bool,
|
||||
SignatureAlgorithm: samlSignatureAlgorithm.String,
|
||||
NameIDFormat: samlNameIDFormat,
|
||||
TransientMappingAttributeName: samlTransientMappingAttributeName.String,
|
||||
FederatedLogoutEnabled: samlFederatedLogoutEnabled.Bool,
|
||||
@@ -1463,6 +1472,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
SAMLCertificateCol.identifier(),
|
||||
SAMLBindingCol.identifier(),
|
||||
SAMLWithSignedRequestCol.identifier(),
|
||||
SAMLSignatureAlgorithmCol.identifier(),
|
||||
SAMLNameIDFormatCol.identifier(),
|
||||
SAMLTransientMappingAttributeNameCol.identifier(),
|
||||
SAMLFederatedLogoutEnabledCol.identifier(),
|
||||
@@ -1588,6 +1598,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
var samlCertificate []byte
|
||||
samlBinding := sql.NullString{}
|
||||
samlWithSignedRequest := sql.NullBool{}
|
||||
samlSignatureAlgorithm := sql.NullString{}
|
||||
samlNameIDFormat := sql.Null[domain.SAMLNameIDFormat]{}
|
||||
samlTransientMappingAttributeName := sql.NullString{}
|
||||
samlFederatedLogoutEnabled := sql.NullBool{}
|
||||
@@ -1706,6 +1717,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
&samlCertificate,
|
||||
&samlBinding,
|
||||
&samlWithSignedRequest,
|
||||
&samlSignatureAlgorithm,
|
||||
&samlNameIDFormat,
|
||||
&samlTransientMappingAttributeName,
|
||||
&samlFederatedLogoutEnabled,
|
||||
@@ -1845,6 +1857,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
Certificate: samlCertificate,
|
||||
Binding: samlBinding.String,
|
||||
WithSignedRequest: samlWithSignedRequest.Bool,
|
||||
SignatureAlgorithm: samlSignatureAlgorithm.String,
|
||||
NameIDFormat: samlNameIDFormat,
|
||||
TransientMappingAttributeName: samlTransientMappingAttributeName.String,
|
||||
FederatedLogoutEnabled: samlFederatedLogoutEnabled.Bool,
|
||||
|
||||
@@ -97,6 +97,7 @@ var (
|
||||
` projections.idp_templates6_saml.certificate,` +
|
||||
` projections.idp_templates6_saml.binding,` +
|
||||
` projections.idp_templates6_saml.with_signed_request,` +
|
||||
` projections.idp_templates6_saml.signature_algorithm,` +
|
||||
` projections.idp_templates6_saml.name_id_format,` +
|
||||
` projections.idp_templates6_saml.transient_mapping_attribute_name,` +
|
||||
` projections.idp_templates6_saml.federated_logout_enabled,` +
|
||||
@@ -227,6 +228,7 @@ var (
|
||||
"certificate",
|
||||
"binding",
|
||||
"with_signed_request",
|
||||
"signature_algorithm",
|
||||
"name_id_format",
|
||||
"transient_mapping_attribute_name",
|
||||
"federated_logout_enabled",
|
||||
@@ -344,6 +346,7 @@ var (
|
||||
` projections.idp_templates6_saml.certificate,` +
|
||||
` projections.idp_templates6_saml.binding,` +
|
||||
` projections.idp_templates6_saml.with_signed_request,` +
|
||||
` projections.idp_templates6_saml.signature_algorithm,` +
|
||||
` projections.idp_templates6_saml.name_id_format,` +
|
||||
` projections.idp_templates6_saml.transient_mapping_attribute_name,` +
|
||||
` projections.idp_templates6_saml.federated_logout_enabled,` +
|
||||
@@ -475,6 +478,7 @@ var (
|
||||
"certificate",
|
||||
"binding",
|
||||
"with_signed_request",
|
||||
"signature_algorithm",
|
||||
"name_id_format",
|
||||
"transient_mapping_attribute_name",
|
||||
"federated_logout_enabled",
|
||||
@@ -635,6 +639,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -790,6 +795,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -943,6 +949,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -1094,6 +1101,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -1244,6 +1252,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -1394,6 +1403,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -1545,6 +1555,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -1691,7 +1702,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
"binding",
|
||||
false,
|
||||
true,
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
domain.SAMLNameIDFormatTransient,
|
||||
"customAttribute",
|
||||
true,
|
||||
@@ -1751,7 +1763,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
Key: nil,
|
||||
Certificate: nil,
|
||||
Binding: "binding",
|
||||
WithSignedRequest: false,
|
||||
WithSignedRequest: true,
|
||||
SignatureAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
NameIDFormat: sql.Null[domain.SAMLNameIDFormat]{V: domain.SAMLNameIDFormatTransient, Valid: true},
|
||||
TransientMappingAttributeName: "customAttribute",
|
||||
FederatedLogoutEnabled: true,
|
||||
@@ -1850,6 +1863,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
database.TextArray[string]{"server"},
|
||||
@@ -2021,6 +2035,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -2173,6 +2188,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -2353,6 +2369,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
database.TextArray[string]{"server"},
|
||||
@@ -2533,6 +2550,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -2686,6 +2704,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id-ldap",
|
||||
database.TextArray[string]{"server"},
|
||||
@@ -2801,6 +2820,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
"binding",
|
||||
false,
|
||||
nil,
|
||||
domain.SAMLNameIDFormatTransient,
|
||||
"customAttribute",
|
||||
true,
|
||||
@@ -2922,6 +2942,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -3040,6 +3061,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -3158,6 +3180,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -3276,6 +3299,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@@ -3382,6 +3406,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
Certificate: nil,
|
||||
Binding: "binding",
|
||||
WithSignedRequest: false,
|
||||
SignatureAlgorithm: "",
|
||||
NameIDFormat: sql.Null[domain.SAMLNameIDFormat]{V: domain.SAMLNameIDFormatTransient, Valid: true},
|
||||
TransientMappingAttributeName: "customAttribute",
|
||||
FederatedLogoutEnabled: true,
|
||||
|
||||
@@ -171,6 +171,7 @@ const (
|
||||
SAMLCertificateCol = "certificate"
|
||||
SAMLBindingCol = "binding"
|
||||
SAMLWithSignedRequestCol = "with_signed_request"
|
||||
SAMLSignatureAlgorithmCol = "signature_algorithm"
|
||||
SAMLNameIDFormatCol = "name_id_format"
|
||||
SAMLTransientMappingAttributeName = "transient_mapping_attribute_name"
|
||||
SAMLFederatedLogoutEnabled = "federated_logout_enabled"
|
||||
@@ -376,6 +377,7 @@ func (*idpTemplateProjection) Init() *old_handler.Check {
|
||||
handler.NewColumn(SAMLCertificateCol, handler.ColumnTypeBytes),
|
||||
handler.NewColumn(SAMLBindingCol, handler.ColumnTypeText, handler.Nullable()),
|
||||
handler.NewColumn(SAMLWithSignedRequestCol, handler.ColumnTypeBool, handler.Nullable()),
|
||||
handler.NewColumn(SAMLSignatureAlgorithmCol, handler.ColumnTypeText, handler.Default("")),
|
||||
handler.NewColumn(SAMLNameIDFormatCol, handler.ColumnTypeEnum, handler.Nullable()),
|
||||
handler.NewColumn(SAMLTransientMappingAttributeName, handler.ColumnTypeText, handler.Nullable()),
|
||||
handler.NewColumn(SAMLFederatedLogoutEnabled, handler.ColumnTypeBool, handler.Default(false)),
|
||||
@@ -1991,6 +1993,7 @@ func (p *idpTemplateProjection) reduceSAMLIDPAdded(event eventstore.Event) (*han
|
||||
handler.NewCol(SAMLCertificateCol, idpEvent.Certificate),
|
||||
handler.NewCol(SAMLBindingCol, idpEvent.Binding),
|
||||
handler.NewCol(SAMLWithSignedRequestCol, idpEvent.WithSignedRequest),
|
||||
handler.NewCol(SAMLSignatureAlgorithmCol, idpEvent.SignatureAlgorithm),
|
||||
handler.NewCol(SAMLTransientMappingAttributeName, idpEvent.TransientMappingAttributeName),
|
||||
handler.NewCol(SAMLFederatedLogoutEnabled, idpEvent.FederatedLogoutEnabled),
|
||||
}
|
||||
@@ -2522,6 +2525,9 @@ func reduceSAMLIDPChangedColumns(idpEvent idp.SAMLIDPChangedEvent) []handler.Col
|
||||
if idpEvent.WithSignedRequest != nil {
|
||||
SAMLCols = append(SAMLCols, handler.NewCol(SAMLWithSignedRequestCol, *idpEvent.WithSignedRequest))
|
||||
}
|
||||
if idpEvent.SignatureAlgorithm != nil {
|
||||
SAMLCols = append(SAMLCols, handler.NewCol(SAMLSignatureAlgorithmCol, *idpEvent.SignatureAlgorithm))
|
||||
}
|
||||
if idpEvent.NameIDFormat != nil {
|
||||
SAMLCols = append(SAMLCols, handler.NewCol(SAMLNameIDFormatCol, *idpEvent.NameIDFormat))
|
||||
}
|
||||
|
||||
@@ -2789,6 +2789,7 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
"nameIDFormat": 3,
|
||||
"transientMappingAttributeName": "customAttribute",
|
||||
"withSignedRequest": true,
|
||||
"signatureAlgorithm": "",
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
@@ -2825,7 +2826,7 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates6_saml (idp_id, instance_id, metadata, key, certificate, binding, with_signed_request, transient_mapping_attribute_name, federated_logout_enabled, name_id_format) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
|
||||
expectedStmt: "INSERT INTO projections.idp_templates6_saml (idp_id, instance_id, metadata, key, certificate, binding, with_signed_request, signature_algorithm, transient_mapping_attribute_name, federated_logout_enabled, name_id_format) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
@@ -2834,6 +2835,7 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
anyArg{},
|
||||
"binding",
|
||||
true,
|
||||
"",
|
||||
"customAttribute",
|
||||
true,
|
||||
domain.SAMLNameIDFormatTransient,
|
||||
@@ -2863,6 +2865,7 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
"nameIDFormat": 3,
|
||||
"transientMappingAttributeName": "customAttribute",
|
||||
"withSignedRequest": true,
|
||||
"signatureAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
@@ -2899,7 +2902,7 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates6_saml (idp_id, instance_id, metadata, key, certificate, binding, with_signed_request, transient_mapping_attribute_name, federated_logout_enabled, name_id_format) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
|
||||
expectedStmt: "INSERT INTO projections.idp_templates6_saml (idp_id, instance_id, metadata, key, certificate, binding, with_signed_request, signature_algorithm, transient_mapping_attribute_name, federated_logout_enabled, name_id_format) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
@@ -2908,6 +2911,7 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
anyArg{},
|
||||
"binding",
|
||||
true,
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
"customAttribute",
|
||||
true,
|
||||
domain.SAMLNameIDFormatTransient,
|
||||
@@ -2958,6 +2962,47 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance reduceSAMLIDPChanged - signature algorithm",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
instance.SAMLIDPChangedEventType,
|
||||
instance.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"signatureAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
|
||||
}`),
|
||||
), instance.SAMLIDPChangedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceSAMLIDPChanged,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("instance"),
|
||||
sequence: 15,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates6 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
"custom-zitadel-instance",
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates6_saml SET signature_algorithm = $1 WHERE (idp_id = $2) AND (instance_id = $3)",
|
||||
expectedArgs: []interface{}{
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance reduceSAMLIDPChanged",
|
||||
args: args{
|
||||
@@ -2976,6 +3021,7 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
"certificate": `+stringToJSONByte("certificate")+`,
|
||||
"binding": "binding",
|
||||
"withSignedRequest": true,
|
||||
"signatureAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
@@ -3007,13 +3053,14 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates6_saml SET (metadata, key, certificate, binding, with_signed_request, federated_logout_enabled) = ($1, $2, $3, $4, $5, $6) WHERE (idp_id = $7) AND (instance_id = $8)",
|
||||
expectedStmt: "UPDATE projections.idp_templates6_saml SET (metadata, key, certificate, binding, with_signed_request, signature_algorithm, federated_logout_enabled) = ($1, $2, $3, $4, $5, $6, $7) WHERE (idp_id = $8) AND (instance_id = $9)",
|
||||
expectedArgs: []interface{}{
|
||||
[]byte("metadata"),
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
"binding",
|
||||
true,
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
||||
true,
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
|
||||
@@ -16,6 +16,7 @@ type SAMLIDPAddedEvent struct {
|
||||
Key *crypto.CryptoValue `json:"key,omitempty"`
|
||||
Certificate []byte `json:"certificate,omitempty"`
|
||||
Binding string `json:"binding,omitempty"`
|
||||
SignatureAlgorithm string `json:"signatureAlgorithm,omitempty"`
|
||||
WithSignedRequest bool `json:"withSignedRequest,omitempty"`
|
||||
NameIDFormat *domain.SAMLNameIDFormat `json:"nameIDFormat,omitempty"`
|
||||
TransientMappingAttributeName string `json:"transientMappingAttributeName,omitempty"`
|
||||
@@ -32,6 +33,7 @@ func NewSAMLIDPAddedEvent(
|
||||
certificate []byte,
|
||||
binding string,
|
||||
withSignedRequest bool,
|
||||
signatureAlgorithm string,
|
||||
nameIDFormat *domain.SAMLNameIDFormat,
|
||||
transientMappingAttributeName string,
|
||||
federatedLogoutEnabled bool,
|
||||
@@ -46,6 +48,7 @@ func NewSAMLIDPAddedEvent(
|
||||
Certificate: certificate,
|
||||
Binding: binding,
|
||||
WithSignedRequest: withSignedRequest,
|
||||
SignatureAlgorithm: signatureAlgorithm,
|
||||
NameIDFormat: nameIDFormat,
|
||||
TransientMappingAttributeName: transientMappingAttributeName,
|
||||
FederatedLogoutEnabled: federatedLogoutEnabled,
|
||||
@@ -84,6 +87,7 @@ type SAMLIDPChangedEvent struct {
|
||||
Certificate []byte `json:"certificate,omitempty"`
|
||||
Binding *string `json:"binding,omitempty"`
|
||||
WithSignedRequest *bool `json:"withSignedRequest,omitempty"`
|
||||
SignatureAlgorithm *string `json:"signatureAlgorithm,omitempty"`
|
||||
NameIDFormat *domain.SAMLNameIDFormat `json:"nameIDFormat,omitempty"`
|
||||
TransientMappingAttributeName *string `json:"transientMappingAttributeName,omitempty"`
|
||||
FederatedLogoutEnabled *bool `json:"federatedLogoutEnabled,omitempty"`
|
||||
@@ -146,6 +150,12 @@ func ChangeSAMLWithSignedRequest(withSignedRequest bool) func(*SAMLIDPChangedEve
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeSAMLSignatureAlgorithm(signatureAlgorithm string) func(*SAMLIDPChangedEvent) {
|
||||
return func(e *SAMLIDPChangedEvent) {
|
||||
e.SignatureAlgorithm = &signatureAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeSAMLNameIDFormat(nameIDFormat *domain.SAMLNameIDFormat) func(*SAMLIDPChangedEvent) {
|
||||
return func(e *SAMLIDPChangedEvent) {
|
||||
e.NameIDFormat = nameIDFormat
|
||||
|
||||
@@ -1022,6 +1022,7 @@ func NewSAMLIDPAddedEvent(
|
||||
certificate []byte,
|
||||
binding string,
|
||||
withSignedRequest bool,
|
||||
signatureAlgorithm string,
|
||||
nameIDFormat *domain.SAMLNameIDFormat,
|
||||
transientMappingAttributeName string,
|
||||
federatedLogoutEnabled bool,
|
||||
@@ -1041,6 +1042,7 @@ func NewSAMLIDPAddedEvent(
|
||||
certificate,
|
||||
binding,
|
||||
withSignedRequest,
|
||||
signatureAlgorithm,
|
||||
nameIDFormat,
|
||||
transientMappingAttributeName,
|
||||
federatedLogoutEnabled,
|
||||
|
||||
@@ -1023,6 +1023,7 @@ func NewSAMLIDPAddedEvent(
|
||||
certificate []byte,
|
||||
binding string,
|
||||
withSignedRequest bool,
|
||||
signatureAlgorithm string,
|
||||
nameIDFormat *domain.SAMLNameIDFormat,
|
||||
transientMappingAttributeName string,
|
||||
federatedLogoutEnabled bool,
|
||||
@@ -1043,6 +1044,7 @@ func NewSAMLIDPAddedEvent(
|
||||
certificate,
|
||||
binding,
|
||||
withSignedRequest,
|
||||
signatureAlgorithm,
|
||||
nameIDFormat,
|
||||
transientMappingAttributeName,
|
||||
federatedLogoutEnabled,
|
||||
|
||||
@@ -7087,6 +7087,9 @@ message AddSAMLProviderRequest {
|
||||
// Optionally enable federated logout. If enabled, ZITADEL will send a logout request to the identity provider,
|
||||
// if the user terminates the session in ZITADEL. Be sure to provide a SLO endpoint as part of the metadata.
|
||||
optional bool federated_logout_enabled = 9;
|
||||
// Specify a Signature Algorithm that should be used to sign SAML requests and responses.
|
||||
// Can be used only if the `with_signed_request` option is set to true.
|
||||
zitadel.idp.v1.SAMLSignatureAlgorithm signature_algorithm = 10;
|
||||
}
|
||||
|
||||
message AddSAMLProviderResponse {
|
||||
@@ -7124,6 +7127,9 @@ message UpdateSAMLProviderRequest {
|
||||
// Optionally enable federated logout. If enabled, ZITADEL will send a logout request to the identity provider,
|
||||
// if the user terminates the session in ZITADEL. Be sure to provide a SLO endpoint as part of the metadata.
|
||||
optional bool federated_logout_enabled = 10;
|
||||
// Specify a Signature Algorithm that should be used to sign SAML requests and responses.
|
||||
// Can be used only if the `with_signed_request` option is set to true.
|
||||
zitadel.idp.v1.SAMLSignatureAlgorithm signature_algorithm = 11;
|
||||
}
|
||||
|
||||
message UpdateSAMLProviderResponse {
|
||||
|
||||
+10
-1
@@ -276,6 +276,13 @@ enum SAMLBinding {
|
||||
SAML_BINDING_ARTIFACT = 3;
|
||||
}
|
||||
|
||||
enum SAMLSignatureAlgorithm {
|
||||
SAML_SIGNATURE_UNSPECIFIED = 0;
|
||||
SAML_SIGNATURE_RSA_SHA1 = 1;
|
||||
SAML_SIGNATURE_RSA_SHA256 = 2;
|
||||
SAML_SIGNATURE_RSA_SHA512 = 3;
|
||||
}
|
||||
|
||||
enum SAMLNameIDFormat {
|
||||
SAML_NAME_ID_FORMAT_UNSPECIFIED = 0;
|
||||
SAML_NAME_ID_FORMAT_EMAIL_ADDRESS = 1;
|
||||
@@ -479,9 +486,11 @@ message SAMLConfig {
|
||||
// Optional name of the attribute, which will be used to map the user
|
||||
// in case the nameid-format returned is `urn:oasis:names:tc:SAML:2.0:nameid-format:transient`.
|
||||
optional string transient_mapping_attribute_name = 5;
|
||||
// Boolean weather federated logout is enabled. If enabled, ZITADEL will send a logout request to the identity provider,
|
||||
// Boolean value to indicate whether federated logout is enabled. If enabled, ZITADEL will send a logout request to the identity provider,
|
||||
// if the user terminates the session in ZITADEL. Be sure to provide a SLO endpoint as part of the metadata.
|
||||
optional bool federated_logout_enabled = 6;
|
||||
// Optional value to indicate the configured Signing Algorithm used to sign SAML requests and responses.
|
||||
optional zitadel.idp.v1.SAMLSignatureAlgorithm signature_algorithm = 7;
|
||||
}
|
||||
|
||||
message AzureADConfig {
|
||||
|
||||
@@ -64,6 +64,13 @@ enum SAMLBinding {
|
||||
SAML_BINDING_ARTIFACT = 3;
|
||||
}
|
||||
|
||||
enum SAMLSignatureAlgorithm {
|
||||
SAML_SIGNATURE_UNSPECIFIED = 0;
|
||||
SAML_SIGNATURE_RSA_SHA1 = 1;
|
||||
SAML_SIGNATURE_RSA_SHA256 = 2;
|
||||
SAML_SIGNATURE_RSA_SHA512 = 3;
|
||||
}
|
||||
|
||||
enum SAMLNameIDFormat {
|
||||
SAML_NAME_ID_FORMAT_UNSPECIFIED = 0;
|
||||
SAML_NAME_ID_FORMAT_EMAIL_ADDRESS = 1;
|
||||
@@ -306,6 +313,9 @@ message SAMLConfig {
|
||||
// Boolean weather federated logout is enabled. If enabled, ZITADEL will send a logout request to the identity provider,
|
||||
// if the user terminates the session in ZITADEL. Be sure to provide a SLO endpoint as part of the metadata.
|
||||
optional bool federated_logout_enabled = 6;
|
||||
// Specify a Signature Algorithm that should used to sign SAML requests and responses.
|
||||
// Can be set only if `with_signed_request` is set.
|
||||
SAMLSignatureAlgorithm signature_algorithm = 7;
|
||||
}
|
||||
|
||||
message AzureADConfig {
|
||||
|
||||
@@ -13794,6 +13794,9 @@ message AddSAMLProviderRequest {
|
||||
// Optionally enable federated logout. If enabled, ZITADEL will send a logout request to the identity provider,
|
||||
// if the user terminates the session in ZITADEL. Be sure to provide a SLO endpoint as part of the metadata.
|
||||
optional bool federated_logout_enabled = 9;
|
||||
// Specify a Signature Algorithm that should be used to sign SAML requests and responses.
|
||||
// Can be used only if the `with_signed_request` option is set to true.
|
||||
zitadel.idp.v1.SAMLSignatureAlgorithm signature_algorithm = 10;
|
||||
}
|
||||
|
||||
message AddSAMLProviderResponse {
|
||||
@@ -13831,6 +13834,9 @@ message UpdateSAMLProviderRequest {
|
||||
// Optionally enable federated logout. If enabled, ZITADEL will send a logout request to the identity provider,
|
||||
// if the user terminates the session in ZITADEL. Be sure to provide a SLO endpoint as part of the metadata.
|
||||
optional bool federated_logout_enabled = 10;
|
||||
// Specify a Signature Algorithm that should be used to sign SAML requests and responses.
|
||||
// Can be used only if the `with_signed_request` option is set to true.
|
||||
zitadel.idp.v1.SAMLSignatureAlgorithm signature_algorithm = 11;
|
||||
}
|
||||
|
||||
message UpdateSAMLProviderResponse {
|
||||
|
||||
Reference in New Issue
Block a user