From e57a9b57c8e770383316599a338ceef023d96de6 Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Thu, 23 May 2024 07:04:07 +0200 Subject: [PATCH] feat(saml): allow setting nameid-format and alternative mapping for transient format (#7979) # Which Problems Are Solved ZITADEL currently always uses `urn:oasis:names:tc:SAML:2.0:nameid-format:persistent` in SAML requests, relying on the IdP to respect that flag and always return a peristent nameid in order to be able to map the external user with an existing user (idp link) in ZITADEL. In case the IdP however returns a `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` (transient) nameid, the attribute will differ between each request and it will not be possible to match existing users. # How the Problems Are Solved This PR adds the following two options on SAML IdP: - **nameIDFormat**: allows to set the nameid-format used in the SAML Request - **transientMappingAttributeName**: allows to set an attribute name, which will be used instead of the nameid itself in case the returned nameid-format is transient # Additional Changes To reduce impact on current installations, the `idp_templates6_saml` table is altered with the two added columns by a setup job. New installations will automatically get the table with the two columns directly. All idp unit tests are updated to use `expectEventstore` instead of the deprecated `eventstoreExpect`. # Additional Context Closes #7483 Closes #7743 --------- Co-authored-by: peintnermax Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> --- cmd/setup/27.go | 27 ++ cmd/setup/27.sql | 2 + cmd/setup/config.go | 1 + cmd/setup/setup.go | 2 + .../provider-options.component.scss | 2 +- .../provider-saml-sp.component.html | 22 + .../provider-saml-sp.component.scss | 9 + .../provider-saml-sp.component.ts | 36 +- .../src/app/modules/providers/providers.scss | 8 +- console/src/assets/i18n/en.json | 7 +- console/src/assets/i18n/nl.json | 2 +- internal/api/grpc/admin/idp_converter.go | 37 +- internal/api/grpc/idp/converter.go | 43 +- internal/api/grpc/management/idp_converter.go | 37 +- .../api/grpc/user/v2/user_integration_test.go | 2 +- internal/api/idp/idp.go | 13 +- internal/api/idp/idp_integration_test.go | 118 +++-- .../api/ui/login/external_provider_handler.go | 11 +- internal/command/idp.go | 15 +- internal/command/idp_intent_test.go | 5 + internal/command/idp_model.go | 38 +- internal/command/instance_idp.go | 6 + internal/command/instance_idp_model.go | 5 + internal/command/instance_idp_test.go | 449 +++++++++--------- internal/command/org_idp.go | 6 + internal/command/org_idp_model.go | 5 + internal/command/org_idp_test.go | 449 +++++++++--------- internal/domain/idp.go | 9 + internal/idp/providers/saml/mapper.go | 5 +- internal/idp/providers/saml/saml.go | 43 +- internal/idp/providers/saml/saml_test.go | 51 +- internal/idp/providers/saml/session.go | 44 +- internal/idp/providers/saml/session_test.go | 80 +++- internal/integration/client.go | 9 +- internal/query/idp_template.go | 62 ++- internal/query/idp_template_test.go | 74 ++- internal/query/projection/idp_template.go | 48 +- .../query/projection/idp_template_test.go | 12 +- internal/repository/idp/saml.go | 67 ++- internal/repository/instance/idp.go | 5 + internal/repository/org/idp.go | 5 + internal/static/i18n/bg.yaml | 1 + internal/static/i18n/cs.yaml | 1 + internal/static/i18n/de.yaml | 1 + internal/static/i18n/en.yaml | 1 + internal/static/i18n/es.yaml | 1 + internal/static/i18n/fr.yaml | 1 + internal/static/i18n/it.yaml | 1 + internal/static/i18n/ja.yaml | 1 + internal/static/i18n/mk.yaml | 1 + internal/static/i18n/nl.yaml | 1 + internal/static/i18n/pl.yaml | 1 + internal/static/i18n/pt.yaml | 1 + internal/static/i18n/ru.yaml | 1 + internal/static/i18n/zh.yaml | 1 + proto/zitadel/admin.proto | 54 +-- proto/zitadel/idp.proto | 33 +- proto/zitadel/management.proto | 54 +-- 58 files changed, 1306 insertions(+), 720 deletions(-) create mode 100644 cmd/setup/27.go create mode 100644 cmd/setup/27.sql diff --git a/cmd/setup/27.go b/cmd/setup/27.go new file mode 100644 index 000000000..ee420ddfa --- /dev/null +++ b/cmd/setup/27.go @@ -0,0 +1,27 @@ +package setup + +import ( + "context" + _ "embed" + + "github.com/zitadel/zitadel/internal/database" + "github.com/zitadel/zitadel/internal/eventstore" +) + +var ( + //go:embed 27.sql + addSAMLNameIDFormat string +) + +type IDPTemplate6SAMLNameIDFormat struct { + dbClient *database.DB +} + +func (mig *IDPTemplate6SAMLNameIDFormat) Execute(ctx context.Context, _ eventstore.Event) error { + _, err := mig.dbClient.ExecContext(ctx, addSAMLNameIDFormat) + return err +} + +func (mig *IDPTemplate6SAMLNameIDFormat) String() string { + return "26_idp_templates6_add_saml_name_id_format" +} diff --git a/cmd/setup/27.sql b/cmd/setup/27.sql new file mode 100644 index 000000000..0e0503b7f --- /dev/null +++ b/cmd/setup/27.sql @@ -0,0 +1,2 @@ +ALTER TABLE IF EXISTS projections.idp_templates6_saml ADD COLUMN IF NOT EXISTS name_id_format SMALLINT; +ALTER TABLE IF EXISTS projections.idp_templates6_saml ADD COLUMN IF NOT EXISTS transient_mapping_attribute_name TEXT; diff --git a/cmd/setup/config.go b/cmd/setup/config.go index c66edb4db..1ba85804a 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -109,6 +109,7 @@ type Steps struct { s24AddActorToAuthTokens *AddActorToAuthTokens s25User11AddLowerFieldsToVerifiedEmail *User11AddLowerFieldsToVerifiedEmail s26AuthUsers3 *AuthUsers3 + s27IDPTemplate6SAMLNameIDFormat *IDPTemplate6SAMLNameIDFormat } func MustNewSteps(v *viper.Viper) *Steps { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 96d0f05bc..bb0111d5b 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -139,6 +139,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.s24AddActorToAuthTokens = &AddActorToAuthTokens{dbClient: queryDBClient} steps.s25User11AddLowerFieldsToVerifiedEmail = &User11AddLowerFieldsToVerifiedEmail{dbClient: esPusherDBClient} steps.s26AuthUsers3 = &AuthUsers3{dbClient: esPusherDBClient} + steps.s27IDPTemplate6SAMLNameIDFormat = &IDPTemplate6SAMLNameIDFormat{dbClient: esPusherDBClient} err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil) logging.OnError(err).Fatal("unable to start projections") @@ -190,6 +191,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.s18AddLowerFieldsToLoginNames, steps.s21AddBlockFieldToLimits, steps.s25User11AddLowerFieldsToVerifiedEmail, + steps.s27IDPTemplate6SAMLNameIDFormat, } { mustExecuteMigration(ctx, eventstoreClient, step, "migration failed") } diff --git a/console/src/app/modules/provider-options/provider-options.component.scss b/console/src/app/modules/provider-options/provider-options.component.scss index 5363ea02d..a39f3d6c5 100644 --- a/console/src/app/modules/provider-options/provider-options.component.scss +++ b/console/src/app/modules/provider-options/provider-options.component.scss @@ -1,7 +1,7 @@ .option-form { display: grid; grid-template-columns: 1fr; - max-width: 400px; + max-width: 500px; padding-bottom: 1rem; .checkbox-desc { diff --git a/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.html b/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.html index d8b5b89fd..79bab0f3d 100644 --- a/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.html +++ b/console/src/app/modules/providers/provider-saml-sp/provider-saml-sp.component.html @@ -70,6 +70,28 @@
+
+ + {{ 'IDP.SAML.NAMEIDFORMAT' | translate }} + + {{ + nameIdFormat + }} + + + + +
+

{{ 'IDP.SAML.TRANSIENTMAPPINGATTRIBUTENAME_DESC' | translate }}

+
+ + + {{ 'IDP.SAML.TRANSIENTMAPPINGATTRIBUTENAME' | translate }} + + +
+
+ = new BehaviorSubject(''); public justActivated$ = new BehaviorSubject(false); @@ -118,6 +125,8 @@ export class ProviderSamlSpComponent { metadataUrl: new UntypedFormControl('', []), binding: new UntypedFormControl(this.bindingValues[0], [requiredValidator]), withSignedRequest: new UntypedFormControl(true, [requiredValidator]), + nameIdFormat: new UntypedFormControl(SAMLNameIDFormat.SAML_NAME_ID_FORMAT_PERSISTENT, []), + transientMappingAttributeName: new UntypedFormControl('', []), }, atLeastOneIsFilled('metadataXml', 'metadataUrl'), ); @@ -196,8 +205,12 @@ export class ProviderSamlSpComponent { req.setWithSignedRequest(this.withSignedRequest?.value); // @ts-ignore req.setBinding(SAMLBinding[this.binding?.value]); + // @ts-ignore + req.setNameIdFormat(SAMLNameIDFormat[this.nameIDFormat?.value]); + req.setTransientMappingAttributeName(this.transientMapping?.value); req.setProviderOptions(this.options); + console.log(req); this.loading = true; this.service .updateSAMLProvider(req) @@ -229,6 +242,11 @@ export class ProviderSamlSpComponent { // @ts-ignore req.setBinding(SAMLBinding[this.binding?.value]); req.setWithSignedRequest(this.withSignedRequest?.value); + if (this.nameIDFormat) { + // @ts-ignore + req.setNameIdFormat(SAMLNameIDFormat[this.nameIDFormat.value]); + } + req.setTransientMappingAttributeName(this.transientMapping?.value); this.loading = true; this.service .addSAMLProvider(req) @@ -279,6 +297,14 @@ export class ProviderSamlSpComponent { return false; } + compareNameIDFormat(value: string, index: number) { + console.log(value, index); + if (value) { + return value === Object.keys(SAMLNameIDFormat)[index]; + } + return false; + } + private get name(): AbstractControl | null { return this.form.get('name'); } @@ -298,4 +324,12 @@ export class ProviderSamlSpComponent { private get withSignedRequest(): AbstractControl | null { return this.form.get('withSignedRequest'); } + + private get nameIDFormat(): AbstractControl | null { + return this.form.get('nameIdFormat'); + } + + private get transientMapping(): AbstractControl | null { + return this.form.get('transientMappingAttributeName'); + } } diff --git a/console/src/app/modules/providers/providers.scss b/console/src/app/modules/providers/providers.scss index ba96f6c30..85584b956 100644 --- a/console/src/app/modules/providers/providers.scss +++ b/console/src/app/modules/providers/providers.scss @@ -50,7 +50,7 @@ .formfield { display: block; - max-width: 400px; + max-width: 500px; &.pwd { display: none; @@ -132,7 +132,7 @@ } .string-list-component-wrapper { - max-width: 400px; + max-width: 500px; } .identity-provider-content { @@ -144,7 +144,7 @@ } .identity-provider-2-col { - max-width: 400px; + max-width: 500px; display: grid; grid-template-columns: 1fr 1fr; column-gap: 1rem; @@ -160,7 +160,7 @@ .flex-line { display: flex; align-items: flex-start; - max-width: 400px; + max-width: 500px; .formfield { flex: 1; diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index d85616fe5..9f686bbfb 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -2044,7 +2044,7 @@ "DESCRIPTION": "Enter the credentials for your Apple Provider" }, "SAML": { - "TITLE": "Sign in with Saml SP", + "TITLE": "Sign in with SAML SP", "DESCRIPTION": "Enter the credentials for your SAML Provider" } }, @@ -2177,7 +2177,10 @@ "METADATAXML": "Metadata Xml", "METADATAURL": "Metadata URL", "BINDING": "Binding", - "SIGNEDREQUEST": "Signed Request" + "SIGNEDREQUEST": "Signed Request", + "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`" }, "TOAST": { "SAVED": "Successfully saved.", diff --git a/console/src/assets/i18n/nl.json b/console/src/assets/i18n/nl.json index 296ddb3b3..1e4fb7abf 100644 --- a/console/src/assets/i18n/nl.json +++ b/console/src/assets/i18n/nl.json @@ -2044,7 +2044,7 @@ "DESCRIPTION": "Voer de inloggegevens in voor uw Apple Provider" }, "SAML": { - "TITLE": "Log in met Saml SP", + "TITLE": "Log in met SAML SP", "DESCRIPTION": "Voer de inloggegevens in voor uw SAML Provider" } }, diff --git a/internal/api/grpc/admin/idp_converter.go b/internal/api/grpc/admin/idp_converter.go index ce3884d2b..2914f94b3 100644 --- a/internal/api/grpc/admin/idp_converter.go +++ b/internal/api/grpc/admin/idp_converter.go @@ -2,6 +2,7 @@ package admin import ( "github.com/crewjam/saml" + "github.com/muhlemmer/gu" idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp" "github.com/zitadel/zitadel/internal/api/grpc/object" @@ -469,24 +470,36 @@ func updateAppleProviderToCommand(req *admin_pb.UpdateAppleProviderRequest) comm } func addSAMLProviderToCommand(req *admin_pb.AddSAMLProviderRequest) command.SAMLProvider { + var nameIDFormat *domain.SAMLNameIDFormat + 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, - IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions), + Name: req.Name, + Metadata: req.GetMetadataXml(), + MetadataURL: req.GetMetadataUrl(), + Binding: bindingToCommand(req.Binding), + WithSignedRequest: req.WithSignedRequest, + NameIDFormat: nameIDFormat, + TransientMappingAttributeName: req.GetTransientMappingAttributeName(), + IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions), } } func updateSAMLProviderToCommand(req *admin_pb.UpdateSAMLProviderRequest) command.SAMLProvider { + var nameIDFormat *domain.SAMLNameIDFormat + 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, - IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions), + Name: req.Name, + Metadata: req.GetMetadataXml(), + MetadataURL: req.GetMetadataUrl(), + Binding: bindingToCommand(req.Binding), + WithSignedRequest: req.WithSignedRequest, + NameIDFormat: nameIDFormat, + TransientMappingAttributeName: req.GetTransientMappingAttributeName(), + IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions), } } diff --git a/internal/api/grpc/idp/converter.go b/internal/api/grpc/idp/converter.go index 2acaf4d3d..9b3e09a10 100644 --- a/internal/api/grpc/idp/converter.go +++ b/internal/api/grpc/idp/converter.go @@ -2,6 +2,7 @@ package idp import ( "github.com/crewjam/saml" + "github.com/muhlemmer/gu" "google.golang.org/protobuf/types/known/durationpb" obj_grpc "github.com/zitadel/zitadel/internal/api/grpc/object" @@ -339,6 +340,21 @@ func azureADTenantTypeToCommand(tenantType idp_pb.AzureADTenantType) azuread.Ten } } +func SAMLNameIDFormatToDomain(format idp_pb.SAMLNameIDFormat) domain.SAMLNameIDFormat { + switch format { + case idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_UNSPECIFIED: + return domain.SAMLNameIDFormatUnspecified + case idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_EMAIL_ADDRESS: + return domain.SAMLNameIDFormatEmailAddress + case idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_PERSISTENT: + return domain.SAMLNameIDFormatPersistent + case idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_TRANSIENT: + return domain.SAMLNameIDFormatTransient + default: + return domain.SAMLNameIDFormatUnspecified + } +} + func ProvidersToPb(providers []*query.IDPTemplate) []*idp_pb.Provider { list := make([]*idp_pb.Provider, len(providers)) for i, provider := range providers { @@ -639,11 +655,17 @@ func appleConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.Appl } func samlConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.SAMLIDPTemplate) { + nameIDFormat := idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_PERSISTENT + if template.NameIDFormat.Valid { + nameIDFormat = nameIDToPb(template.NameIDFormat.V) + } providerConfig.Config = &idp_pb.ProviderConfig_Saml{ Saml: &idp_pb.SAMLConfig{ - MetadataXml: template.Metadata, - Binding: bindingToPb(template.Binding), - WithSignedRequest: template.WithSignedRequest, + MetadataXml: template.Metadata, + Binding: bindingToPb(template.Binding), + WithSignedRequest: template.WithSignedRequest, + NameIdFormat: nameIDFormat, + TransientMappingAttributeName: gu.Ptr(template.TransientMappingAttributeName), }, } } @@ -662,3 +684,18 @@ func bindingToPb(binding string) idp_pb.SAMLBinding { return idp_pb.SAMLBinding_SAML_BINDING_UNSPECIFIED } } + +func nameIDToPb(format domain.SAMLNameIDFormat) idp_pb.SAMLNameIDFormat { + switch format { + case domain.SAMLNameIDFormatUnspecified: + return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_UNSPECIFIED + case domain.SAMLNameIDFormatEmailAddress: + return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_EMAIL_ADDRESS + case domain.SAMLNameIDFormatPersistent: + return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_PERSISTENT + case domain.SAMLNameIDFormatTransient: + return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_TRANSIENT + default: + return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_UNSPECIFIED + } +} diff --git a/internal/api/grpc/management/idp_converter.go b/internal/api/grpc/management/idp_converter.go index d8949a544..48d5a85a9 100644 --- a/internal/api/grpc/management/idp_converter.go +++ b/internal/api/grpc/management/idp_converter.go @@ -4,6 +4,7 @@ import ( "context" "github.com/crewjam/saml" + "github.com/muhlemmer/gu" "github.com/zitadel/zitadel/internal/api/authz" idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp" @@ -462,24 +463,36 @@ func updateAppleProviderToCommand(req *mgmt_pb.UpdateAppleProviderRequest) comma } func addSAMLProviderToCommand(req *mgmt_pb.AddSAMLProviderRequest) command.SAMLProvider { + var nameIDFormat *domain.SAMLNameIDFormat + 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, - IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions), + Name: req.Name, + Metadata: req.GetMetadataXml(), + MetadataURL: req.GetMetadataUrl(), + Binding: bindingToCommand(req.Binding), + WithSignedRequest: req.WithSignedRequest, + NameIDFormat: nameIDFormat, + TransientMappingAttributeName: req.GetTransientMappingAttributeName(), + IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions), } } func updateSAMLProviderToCommand(req *mgmt_pb.UpdateSAMLProviderRequest) command.SAMLProvider { + var nameIDFormat *domain.SAMLNameIDFormat + 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, - IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions), + Name: req.Name, + Metadata: req.GetMetadataXml(), + MetadataURL: req.GetMetadataUrl(), + Binding: bindingToCommand(req.Binding), + WithSignedRequest: req.WithSignedRequest, + NameIDFormat: nameIDFormat, + TransientMappingAttributeName: req.GetTransientMappingAttributeName(), + IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions), } } diff --git a/internal/api/grpc/user/v2/user_integration_test.go b/internal/api/grpc/user/v2/user_integration_test.go index 19ce0aecc..824029724 100644 --- a/internal/api/grpc/user/v2/user_integration_test.go +++ b/internal/api/grpc/user/v2/user_integration_test.go @@ -1883,7 +1883,7 @@ func TestServer_StartIdentityProviderIntent(t *testing.T) { orgResp := Tester.CreateOrganization(IamCTX, fmt.Sprintf("NotDefaultOrg%d", time.Now().UnixNano()), fmt.Sprintf("%d@mouse.com", time.Now().UnixNano())) notDefaultOrgIdpID := Tester.AddOrgGenericOAuthProvider(t, CTX, orgResp.OrganizationId) samlIdpID := Tester.AddSAMLProvider(t, CTX) - samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX) + samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX, "") samlPostIdpID := Tester.AddSAMLPostProvider(t, CTX) type args struct { ctx context.Context diff --git a/internal/api/idp/idp.go b/internal/api/idp/idp.go index 6a2cb6e32..0209e0337 100644 --- a/internal/api/idp/idp.go +++ b/internal/api/idp/idp.go @@ -229,11 +229,6 @@ func (h *Handler) handleACS(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - sp, err := samlProvider.GetSP() - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } intent, err := h.commands.GetActiveIntent(ctx, data.RelayState) if err != nil { @@ -245,10 +240,10 @@ func (h *Handler) handleACS(w http.ResponseWriter, r *http.Request) { return } - session := saml2.Session{ - ServiceProvider: sp, - RequestID: intent.RequestID, - Request: r, + session, err := saml2.NewSession(samlProvider, intent.RequestID, r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return } idpUser, err := session.FetchUser(r.Context()) diff --git a/internal/api/idp/idp_integration_test.go b/internal/api/idp/idp_integration_test.go index 1ade5d7f3..8fdc24539 100644 --- a/internal/api/idp/idp_integration_test.go +++ b/internal/api/idp/idp_integration_test.go @@ -52,7 +52,7 @@ func TestMain(m *testing.M) { } func TestServer_SAMLCertificate(t *testing.T) { - samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX) + samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX, "") oauthIdpID := Tester.AddGenericOAuthProvider(t, CTX) type args struct { @@ -109,7 +109,7 @@ func TestServer_SAMLCertificate(t *testing.T) { } func TestServer_SAMLMetadata(t *testing.T) { - samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX) + samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX, "") oauthIdpID := Tester.AddGenericOAuthProvider(t, CTX) type args struct { @@ -167,7 +167,7 @@ func TestServer_SAMLMetadata(t *testing.T) { func TestServer_SAMLACS(t *testing.T) { userHuman := Tester.CreateHumanUser(CTX) - samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX) + samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX, "urn:oid:0.9.2342.19200300.100.1.1") // the username is set in urn:oid:0.9.2342.19200300.100.1.1 externalUserID := "test1" linkedExternalUserID := "test2" Tester.CreateUserIDPlink(CTX, userHuman.UserId, linkedExternalUserID, samlRedirectIdpID, linkedExternalUserID) @@ -180,13 +180,15 @@ func TestServer_SAMLACS(t *testing.T) { assert.NoError(t, err) type args struct { - ctx context.Context - successURL string - failureURL string - idpID string - username string - intentID string - response string + ctx context.Context + successURL string + failureURL string + idpID string + username string + nameID string + nameIDFormat string + intentID string + response string } type want struct { successful bool @@ -201,12 +203,14 @@ func TestServer_SAMLACS(t *testing.T) { { name: "intent invalid", args: args{ - ctx: CTX, - successURL: "https://example.com/success", - failureURL: "https://example.com/failure", - idpID: samlRedirectIdpID, - username: externalUserID, - intentID: "notexisting", + ctx: CTX, + successURL: "https://example.com/success", + failureURL: "https://example.com/failure", + idpID: samlRedirectIdpID, + username: externalUserID, + nameID: externalUserID, + nameIDFormat: string(saml.PersistentNameIDFormat), + intentID: "notexisting", }, want: want{ successful: false, @@ -217,12 +221,14 @@ func TestServer_SAMLACS(t *testing.T) { { name: "response invalid", args: args{ - ctx: CTX, - successURL: "https://example.com/success", - failureURL: "https://example.com/failure", - idpID: samlRedirectIdpID, - username: externalUserID, - response: "invalid", + ctx: CTX, + successURL: "https://example.com/success", + failureURL: "https://example.com/failure", + idpID: samlRedirectIdpID, + username: externalUserID, + nameID: externalUserID, + nameIDFormat: string(saml.PersistentNameIDFormat), + response: "invalid", }, want: want{ successful: false, @@ -232,11 +238,13 @@ func TestServer_SAMLACS(t *testing.T) { { name: "saml flow redirect, ok", args: args{ - ctx: CTX, - successURL: "https://example.com/success", - failureURL: "https://example.com/failure", - idpID: samlRedirectIdpID, - username: externalUserID, + ctx: CTX, + successURL: "https://example.com/success", + failureURL: "https://example.com/failure", + idpID: samlRedirectIdpID, + username: externalUserID, + nameID: externalUserID, + nameIDFormat: string(saml.PersistentNameIDFormat), }, want: want{ successful: true, @@ -246,11 +254,45 @@ func TestServer_SAMLACS(t *testing.T) { { name: "saml flow redirect with link, ok", args: args{ - ctx: CTX, - successURL: "https://example.com/success", - failureURL: "https://example.com/failure", - idpID: samlRedirectIdpID, - username: linkedExternalUserID, + ctx: CTX, + successURL: "https://example.com/success", + failureURL: "https://example.com/failure", + idpID: samlRedirectIdpID, + username: linkedExternalUserID, + nameID: linkedExternalUserID, + nameIDFormat: string(saml.PersistentNameIDFormat), + }, + want: want{ + successful: true, + user: userHuman.UserId, + }, + }, + { + name: "saml flow redirect (transient), ok", + args: args{ + ctx: CTX, + successURL: "https://example.com/success", + failureURL: "https://example.com/failure", + idpID: samlRedirectIdpID, + username: externalUserID, + nameID: "genericID", + nameIDFormat: string(saml.TransientNameIDFormat), + }, + want: want{ + successful: true, + user: "", + }, + }, + { + name: "saml flow redirect with link (transient), ok", + args: args{ + ctx: CTX, + successURL: "https://example.com/success", + failureURL: "https://example.com/failure", + idpID: samlRedirectIdpID, + username: linkedExternalUserID, + nameID: "genericID", + nameIDFormat: string(saml.TransientNameIDFormat), }, want: want{ successful: true, @@ -287,7 +329,7 @@ func TestServer_SAMLACS(t *testing.T) { relayState = tt.args.intentID } callbackURL := http_util.BuildOrigin(Tester.Host(), Tester.Server.Config.ExternalSecure) + "/idps/" + tt.args.idpID + "/saml/acs" - response := createResponse(t, idp, samlRequest, tt.args.username) + response := createResponse(t, idp, samlRequest, tt.args.nameID, tt.args.nameIDFormat, tt.args.username) //test purposes, use defined response if tt.args.response != "" { response = tt.args.response @@ -432,14 +474,16 @@ func getIDP(zitadelBaseURL string, idpIDs []string, user1, user2 string) (*saml. return &idpServer.IDP, nil } -func createResponse(t *testing.T, idp *saml.IdentityProvider, req *http.Request, username string) string { +func createResponse(t *testing.T, idp *saml.IdentityProvider, req *http.Request, nameID, nameIDFormat, username string) string { authnReq, err := saml.NewIdpAuthnRequest(idp, req) assert.NoError(t, authnReq.Validate()) err = idp.AssertionMaker.MakeAssertion(authnReq, &saml.Session{ - CreateTime: time.Now().UTC(), - Index: "", - NameID: username, + CreateTime: time.Now().UTC(), + Index: "", + NameID: nameID, + NameIDFormat: nameIDFormat, + UserName: username, }) assert.NoError(t, err) err = authnReq.MakeResponse() diff --git a/internal/api/ui/login/external_provider_handler.go b/internal/api/ui/login/external_provider_handler.go index 3cd14c0a7..e03b32086 100644 --- a/internal/api/ui/login/external_provider_handler.go +++ b/internal/api/ui/login/external_provider_handler.go @@ -319,12 +319,11 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque l.externalAuthFailed(w, r, authReq, nil, nil, err) return } - sp, err := provider.(*saml.Provider).GetSP() + session, err = saml.NewSession(provider.(*saml.Provider), authReq.SAMLRequestID, r) if err != nil { l.externalAuthFailed(w, r, authReq, nil, nil, err) return } - session = &saml.Session{ServiceProvider: sp, RequestID: authReq.SAMLRequestID, Request: r} case domain.IDPTypeJWT, domain.IDPTypeLDAP, domain.IDPTypeUnspecified: @@ -1029,13 +1028,19 @@ func (l *Login) samlProvider(ctx context.Context, identityProvider *query.IDPTem if err != nil { return nil, err } - opts := make([]saml.ProviderOpts, 0, 2) + opts := make([]saml.ProviderOpts, 0, 6) if identityProvider.SAMLIDPTemplate.WithSignedRequest { opts = append(opts, saml.WithSignedRequest()) } if identityProvider.SAMLIDPTemplate.Binding != "" { opts = append(opts, saml.WithBinding(identityProvider.SAMLIDPTemplate.Binding)) } + if identityProvider.SAMLIDPTemplate.NameIDFormat.Valid { + opts = append(opts, saml.WithNameIDFormat(identityProvider.SAMLIDPTemplate.NameIDFormat.V)) + } + if identityProvider.SAMLIDPTemplate.TransientMappingAttributeName != "" { + opts = append(opts, saml.WithTransientMappingAttributeName(identityProvider.SAMLIDPTemplate.TransientMappingAttributeName)) + } opts = append(opts, saml.WithEntityID(http_utils.BuildOrigin(authz.GetInstance(ctx).RequestedHost(), l.externalSecure)+"/idps/"+identityProvider.ID+"/saml/metadata"), saml.WithCustomRequestTracker( diff --git a/internal/command/idp.go b/internal/command/idp.go index a8b041c33..229d19b6e 100644 --- a/internal/command/idp.go +++ b/internal/command/idp.go @@ -5,6 +5,7 @@ import ( "time" "github.com/zitadel/zitadel/internal/command/preparation" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/repository/idp" "github.com/zitadel/zitadel/internal/zerrors" ) @@ -110,12 +111,14 @@ type LDAPProvider struct { } type SAMLProvider struct { - Name string - Metadata []byte - MetadataURL string - Binding string - WithSignedRequest bool - IDPOptions idp.Options + Name string + Metadata []byte + MetadataURL string + Binding string + WithSignedRequest bool + NameIDFormat *domain.SAMLNameIDFormat + TransientMappingAttributeName string + IDPOptions idp.Options } type AppleProvider struct { diff --git a/internal/command/idp_intent_test.go b/internal/command/idp_intent_test.go index 8bdbcb471..efcc9e0dd 100644 --- a/internal/command/idp_intent_test.go +++ b/internal/command/idp_intent_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/crewjam/saml" + "github.com/muhlemmer/gu" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zitadel/oidc/v3/pkg/oidc" @@ -631,6 +632,8 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) { []byte("certificate"), "", false, + gu.Ptr(domain.SAMLNameIDFormatUnspecified), + "", rep_idp.Options{}, )), ), @@ -649,6 +652,8 @@ 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), + "", rep_idp.Options{}, )), ), diff --git a/internal/command/idp_model.go b/internal/command/idp_model.go index 12bccd39f..fa38b4a07 100644 --- a/internal/command/idp_model.go +++ b/internal/command/idp_model.go @@ -1726,13 +1726,15 @@ func (wm *AppleIDPWriteModel) GetProviderOptions() idp.Options { type SAMLIDPWriteModel struct { eventstore.WriteModel - Name string - ID string - Metadata []byte - Key *crypto.CryptoValue - Certificate []byte - Binding string - WithSignedRequest bool + Name string + ID string + Metadata []byte + Key *crypto.CryptoValue + Certificate []byte + Binding string + WithSignedRequest bool + NameIDFormat *domain.SAMLNameIDFormat + TransientMappingAttributeName string idp.Options State domain.IDPState @@ -1759,6 +1761,8 @@ func (wm *SAMLIDPWriteModel) reduceAddedEvent(e *idp.SAMLIDPAddedEvent) { wm.Certificate = e.Certificate wm.Binding = e.Binding wm.WithSignedRequest = e.WithSignedRequest + wm.NameIDFormat = e.NameIDFormat + wm.TransientMappingAttributeName = e.TransientMappingAttributeName wm.Options = e.Options wm.State = domain.IDPStateActive } @@ -1782,6 +1786,12 @@ func (wm *SAMLIDPWriteModel) reduceChangedEvent(e *idp.SAMLIDPChangedEvent) { if e.WithSignedRequest != nil { wm.WithSignedRequest = *e.WithSignedRequest } + if e.NameIDFormat != nil { + wm.NameIDFormat = e.NameIDFormat + } + if e.TransientMappingAttributeName != nil { + wm.TransientMappingAttributeName = *e.TransientMappingAttributeName + } wm.Options.ReduceChanges(e.OptionChanges) } @@ -1793,6 +1803,8 @@ func (wm *SAMLIDPWriteModel) NewChanges( secretCrypto crypto.EncryptionAlgorithm, binding string, withSignedRequest bool, + nameIDFormat *domain.SAMLNameIDFormat, + transientMappingAttributeName string, options idp.Options, ) ([]idp.SAMLIDPChanges, error) { changes := make([]idp.SAMLIDPChanges, 0) @@ -1818,6 +1830,12 @@ func (wm *SAMLIDPWriteModel) NewChanges( if wm.WithSignedRequest != withSignedRequest { changes = append(changes, idp.ChangeSAMLWithSignedRequest(withSignedRequest)) } + if wm.NameIDFormat != nameIDFormat { + changes = append(changes, idp.ChangeSAMLNameIDFormat(nameIDFormat)) + } + if wm.TransientMappingAttributeName != transientMappingAttributeName { + changes = append(changes, idp.ChangeSAMLTransientMappingAttributeName(transientMappingAttributeName)) + } opts := wm.Options.Changes(options) if !opts.IsZero() { changes = append(changes, idp.ChangeSAMLOptions(opts)) @@ -1850,6 +1868,12 @@ func (wm *SAMLIDPWriteModel) ToProvider(callbackURL string, idpAlg crypto.Encryp if wm.Binding != "" { opts = append(opts, saml2.WithBinding(wm.Binding)) } + if wm.NameIDFormat != nil { + opts = append(opts, saml2.WithNameIDFormat(*wm.NameIDFormat)) + } + if wm.TransientMappingAttributeName != "" { + opts = append(opts, saml2.WithTransientMappingAttributeName(wm.TransientMappingAttributeName)) + } opts = append(opts, saml2.WithCustomRequestTracker( requesttracker.New( addRequest, diff --git a/internal/command/instance_idp.go b/internal/command/instance_idp.go index ed8d458e1..539136a08 100644 --- a/internal/command/instance_idp.go +++ b/internal/command/instance_idp.go @@ -1763,6 +1763,8 @@ func (c *Commands) prepareAddInstanceSAMLProvider(a *instance.Aggregate, writeMo cert, provider.Binding, provider.WithSignedRequest, + provider.NameIDFormat, + provider.TransientMappingAttributeName, provider.IDPOptions, ), }, nil @@ -1811,6 +1813,8 @@ func (c *Commands) prepareUpdateInstanceSAMLProvider(a *instance.Aggregate, writ c.idpConfigEncryption, provider.Binding, provider.WithSignedRequest, + provider.NameIDFormat, + provider.TransientMappingAttributeName, provider.IDPOptions, ) if err != nil || event == nil { @@ -1854,6 +1858,8 @@ func (c *Commands) prepareRegenerateInstanceSAMLProviderCertificate(a *instance. c.idpConfigEncryption, writeModel.Binding, writeModel.WithSignedRequest, + writeModel.NameIDFormat, + writeModel.TransientMappingAttributeName, writeModel.Options, ) if err != nil || event == nil { diff --git a/internal/command/instance_idp_model.go b/internal/command/instance_idp_model.go index 675944255..5c895b1fc 100644 --- a/internal/command/instance_idp_model.go +++ b/internal/command/instance_idp_model.go @@ -5,6 +5,7 @@ import ( "time" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/idp" "github.com/zitadel/zitadel/internal/repository/instance" @@ -915,6 +916,8 @@ func (wm *InstanceSAMLIDPWriteModel) NewChangedEvent( secretCrypto crypto.EncryptionAlgorithm, binding string, withSignedRequest bool, + nameIDFormat *domain.SAMLNameIDFormat, + transientMappingAttributeName string, options idp.Options, ) (*instance.SAMLIDPChangedEvent, error) { changes, err := wm.SAMLIDPWriteModel.NewChanges( @@ -925,6 +928,8 @@ func (wm *InstanceSAMLIDPWriteModel) NewChangedEvent( secretCrypto, binding, withSignedRequest, + nameIDFormat, + transientMappingAttributeName, options, ) if err != nil || len(changes) == 0 { diff --git a/internal/command/instance_idp_test.go b/internal/command/instance_idp_test.go index 3ff14610d..0f7998a63 100644 --- a/internal/command/instance_idp_test.go +++ b/internal/command/instance_idp_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/muhlemmer/gu" "github.com/stretchr/testify/assert" openid "github.com/zitadel/oidc/v3/pkg/oidc" "go.uber.org/mock/gomock" @@ -23,7 +24,7 @@ import ( func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -45,7 +46,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -61,7 +62,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -79,7 +80,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -98,7 +99,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { "invalid auth endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -118,7 +119,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { "invalid token endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -139,7 +140,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { "invalid user endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -161,7 +162,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { "invalid id attribute", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -184,7 +185,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewOAuthIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -229,7 +230,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewOAuthIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -287,7 +288,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -308,7 +309,7 @@ func TestCommandSide_AddInstanceGenericOAuthIDP(t *testing.T) { func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -329,7 +330,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -344,7 +345,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -360,7 +361,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -378,7 +379,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { "invalid auth endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -397,7 +398,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { "invalid token endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -417,7 +418,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { "invalid user endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -438,7 +439,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { "invalid id attribute", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -460,7 +461,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -483,7 +484,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewOAuthIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -525,7 +526,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewOAuthIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -607,7 +608,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceGenericOAuthProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -626,7 +627,7 @@ func TestCommandSide_UpdateInstanceGenericOAuthIDP(t *testing.T) { func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -648,7 +649,7 @@ func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -664,7 +665,7 @@ func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { { "invalid issuer", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -682,7 +683,7 @@ func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -701,7 +702,7 @@ func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -721,7 +722,7 @@ func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -761,7 +762,7 @@ func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -815,7 +816,7 @@ func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -836,7 +837,7 @@ func TestCommandSide_AddInstanceGenericOIDCIDP(t *testing.T) { func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -857,7 +858,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -872,7 +873,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -888,7 +889,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { { "invalid issuer", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -906,7 +907,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -925,7 +926,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -945,7 +946,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -982,7 +983,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1058,7 +1059,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceGenericOIDCProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -1077,7 +1078,7 @@ func TestCommandSide_UpdateInstanceGenericOIDCIDP(t *testing.T) { func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -1099,7 +1100,7 @@ func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -1114,7 +1115,7 @@ func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -1131,7 +1132,7 @@ func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { { "invalid client secret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -1149,7 +1150,7 @@ func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -1169,7 +1170,7 @@ func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { { name: "migrate ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1227,7 +1228,7 @@ func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { { name: "migrate ok full", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1300,7 +1301,7 @@ func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.MigrateInstanceGenericOIDCToAzureADProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -1319,7 +1320,7 @@ func TestCommandSide_MigrateInstanceGenericOIDCToAzureADProvider(t *testing.T) { func TestCommandSide_MigrateInstanceOIDCToGoogleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -1340,7 +1341,7 @@ func TestCommandSide_MigrateInstanceOIDCToGoogleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -1355,7 +1356,7 @@ func TestCommandSide_MigrateInstanceOIDCToGoogleIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -1372,7 +1373,7 @@ func TestCommandSide_MigrateInstanceOIDCToGoogleIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -1391,7 +1392,7 @@ func TestCommandSide_MigrateInstanceOIDCToGoogleIDP(t *testing.T) { { name: "migrate ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1443,7 +1444,7 @@ func TestCommandSide_MigrateInstanceOIDCToGoogleIDP(t *testing.T) { { name: "migrate ok full", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewOIDCIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1508,7 +1509,7 @@ func TestCommandSide_MigrateInstanceOIDCToGoogleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.MigrateInstanceGenericOIDCToGoogleProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -1527,7 +1528,7 @@ func TestCommandSide_MigrateInstanceOIDCToGoogleIDP(t *testing.T) { func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -1549,7 +1550,7 @@ func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -1565,7 +1566,7 @@ func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -1583,7 +1584,7 @@ func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { { "invalid client secret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -1602,7 +1603,7 @@ func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewAzureADIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1641,7 +1642,7 @@ func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewAzureADIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1695,7 +1696,7 @@ func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -1716,7 +1717,7 @@ func TestCommandSide_AddInstanceAzureADIDP(t *testing.T) { func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -1737,7 +1738,7 @@ func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -1752,7 +1753,7 @@ func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -1768,7 +1769,7 @@ func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -1786,7 +1787,7 @@ func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -1805,7 +1806,7 @@ func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewAzureADIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1841,7 +1842,7 @@ func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewAzureADIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -1917,7 +1918,7 @@ func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceAzureADProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -1936,7 +1937,7 @@ func TestCommandSide_UpdateInstanceAzureADIDP(t *testing.T) { func TestCommandSide_AddInstanceGitHubIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -1958,7 +1959,7 @@ func TestCommandSide_AddInstanceGitHubIDP(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -1974,7 +1975,7 @@ func TestCommandSide_AddInstanceGitHubIDP(t *testing.T) { { "invalid client secret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -1992,7 +1993,7 @@ func TestCommandSide_AddInstanceGitHubIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGitHubIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2028,7 +2029,7 @@ func TestCommandSide_AddInstanceGitHubIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGitHubIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2078,7 +2079,7 @@ func TestCommandSide_AddInstanceGitHubIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -2099,7 +2100,7 @@ func TestCommandSide_AddInstanceGitHubIDP(t *testing.T) { func TestCommandSide_UpdateInstanceGitHubIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -2120,7 +2121,7 @@ func TestCommandSide_UpdateInstanceGitHubIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -2135,7 +2136,7 @@ func TestCommandSide_UpdateInstanceGitHubIDP(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -2151,7 +2152,7 @@ func TestCommandSide_UpdateInstanceGitHubIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -2169,7 +2170,7 @@ func TestCommandSide_UpdateInstanceGitHubIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGitHubIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2202,7 +2203,7 @@ func TestCommandSide_UpdateInstanceGitHubIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGitHubIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2272,7 +2273,7 @@ func TestCommandSide_UpdateInstanceGitHubIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceGitHubProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -2291,7 +2292,7 @@ func TestCommandSide_UpdateInstanceGitHubIDP(t *testing.T) { func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -2313,7 +2314,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2329,7 +2330,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2347,7 +2348,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2366,7 +2367,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid auth endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2386,7 +2387,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid token endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2407,7 +2408,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid user endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2429,7 +2430,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGitHubEnterpriseIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2472,7 +2473,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGitHubEnterpriseIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2528,7 +2529,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -2549,7 +2550,7 @@ func TestCommandSide_AddInstanceGitHubEnterpriseIDP(t *testing.T) { func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -2570,7 +2571,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -2585,7 +2586,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -2601,7 +2602,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -2619,7 +2620,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid auth endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -2638,7 +2639,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid token endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -2658,7 +2659,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { "invalid user endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -2679,7 +2680,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -2701,7 +2702,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGitHubEnterpriseIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2741,7 +2742,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGitHubEnterpriseIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2820,7 +2821,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceGitHubEnterpriseProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -2839,7 +2840,7 @@ func TestCommandSide_UpdateInstanceGitHubEnterpriseIDP(t *testing.T) { func TestCommandSide_AddInstanceGitLabIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -2861,7 +2862,7 @@ func TestCommandSide_AddInstanceGitLabIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2877,7 +2878,7 @@ func TestCommandSide_AddInstanceGitLabIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2895,7 +2896,7 @@ func TestCommandSide_AddInstanceGitLabIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGitLabIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2931,7 +2932,7 @@ func TestCommandSide_AddInstanceGitLabIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGitLabIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -2980,7 +2981,7 @@ func TestCommandSide_AddInstanceGitLabIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -3001,7 +3002,7 @@ func TestCommandSide_AddInstanceGitLabIDP(t *testing.T) { func TestCommandSide_UpdateInstanceGitLabIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -3022,7 +3023,7 @@ func TestCommandSide_UpdateInstanceGitLabIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -3037,7 +3038,7 @@ func TestCommandSide_UpdateInstanceGitLabIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -3053,7 +3054,7 @@ func TestCommandSide_UpdateInstanceGitLabIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -3071,7 +3072,7 @@ func TestCommandSide_UpdateInstanceGitLabIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGitLabIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3104,7 +3105,7 @@ func TestCommandSide_UpdateInstanceGitLabIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGitLabIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3172,7 +3173,7 @@ func TestCommandSide_UpdateInstanceGitLabIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceGitLabProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -3191,7 +3192,7 @@ func TestCommandSide_UpdateInstanceGitLabIDP(t *testing.T) { func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -3213,7 +3214,7 @@ func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3229,7 +3230,7 @@ func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { { "invalid issuer", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3247,7 +3248,7 @@ func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3266,7 +3267,7 @@ func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3286,7 +3287,7 @@ func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGitLabSelfHostedIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3325,7 +3326,7 @@ func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGitLabSelfHostedIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3377,7 +3378,7 @@ func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -3398,7 +3399,7 @@ func TestCommandSide_AddInstanceGitLabSelfHostedIDP(t *testing.T) { func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -3419,7 +3420,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -3434,7 +3435,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -3450,7 +3451,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { { "invalid issuer", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -3468,7 +3469,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -3487,7 +3488,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -3507,7 +3508,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGitLabSelfHostedIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3543,7 +3544,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGitLabSelfHostedIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3616,7 +3617,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceGitLabSelfHostedProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -3635,7 +3636,7 @@ func TestCommandSide_UpdateInstanceGitLabSelfHostedIDP(t *testing.T) { func TestCommandSide_AddInstanceGoogleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -3657,7 +3658,7 @@ func TestCommandSide_AddInstanceGoogleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3673,7 +3674,7 @@ func TestCommandSide_AddInstanceGoogleIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3691,7 +3692,7 @@ func TestCommandSide_AddInstanceGoogleIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGoogleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3727,7 +3728,7 @@ func TestCommandSide_AddInstanceGoogleIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewGoogleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3776,7 +3777,7 @@ func TestCommandSide_AddInstanceGoogleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -3797,7 +3798,7 @@ func TestCommandSide_AddInstanceGoogleIDP(t *testing.T) { func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -3818,7 +3819,7 @@ func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -3833,7 +3834,7 @@ func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -3849,7 +3850,7 @@ func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -3867,7 +3868,7 @@ func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGoogleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3900,7 +3901,7 @@ func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewGoogleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -3968,7 +3969,7 @@ func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceGoogleProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -3987,7 +3988,7 @@ func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) { func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -4009,7 +4010,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4025,7 +4026,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { "invalid baseDN", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4043,7 +4044,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { "invalid bindDN", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4062,7 +4063,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { "invalid bindPassword", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4082,7 +4083,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { "invalid userBase", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4103,7 +4104,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { "invalid servers", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4125,7 +4126,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { "invalid userObjectClasses", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4148,7 +4149,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { "invalid userFilters", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4172,7 +4173,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -4223,7 +4224,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -4315,7 +4316,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -4336,7 +4337,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) { func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -4357,7 +4358,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4372,7 +4373,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4388,7 +4389,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { "invalid baseDN", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4406,7 +4407,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { "invalid bindDN", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4425,7 +4426,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { "invalid userbase", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4445,7 +4446,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { "invalid servers", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4466,7 +4467,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { "invalid userObjectClasses", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4488,7 +4489,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { "invalid userFilters", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4511,7 +4512,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -4538,7 +4539,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -4586,7 +4587,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -4705,7 +4706,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceLDAPProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -4724,7 +4725,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) { func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -4746,7 +4747,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4762,7 +4763,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { { "invalid teamID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4780,7 +4781,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { { "invalid keyID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4799,7 +4800,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { { "invalid privateKey", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4819,7 +4820,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewAppleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -4859,7 +4860,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewAppleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -4912,7 +4913,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -4933,7 +4934,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) { func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -4954,7 +4955,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4969,7 +4970,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -4985,7 +4986,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { { "invalid teamID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -5003,7 +5004,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { { "invalid keyID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -5022,7 +5023,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -5042,7 +5043,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewAppleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -5079,7 +5080,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewAppleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -5153,7 +5154,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceAppleProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -5172,7 +5173,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) { func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm certificateAndKeyGenerator func(id string) ([]byte, []byte, error) @@ -5195,7 +5196,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -5211,7 +5212,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { { "invalid metadata", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -5229,7 +5230,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewSAMLIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -5245,6 +5246,8 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { []byte("certificate"), "", false, + nil, + "", idp.Options{}, ), ), @@ -5268,7 +5271,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( instance.NewSAMLIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -5284,6 +5287,8 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { []byte("certificate"), "binding", true, + gu.Ptr(domain.SAMLNameIDFormatTransient), + "customAttribute", idp.Options{ IsCreationAllowed: true, IsLinkingAllowed: true, @@ -5300,10 +5305,12 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), provider: SAMLProvider{ - Name: "name", - Metadata: []byte("metadata"), - Binding: "binding", - WithSignedRequest: true, + Name: "name", + Metadata: []byte("metadata"), + Binding: "binding", + WithSignedRequest: true, + NameIDFormat: gu.Ptr(domain.SAMLNameIDFormatTransient), + TransientMappingAttributeName: "customAttribute", IDPOptions: idp.Options{ IsCreationAllowed: true, IsLinkingAllowed: true, @@ -5321,7 +5328,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, samlCertificateAndKeyGenerator: tt.fields.certificateAndKeyGenerator, @@ -5343,7 +5350,7 @@ func TestCommandSide_AddInstanceSAMLIDP(t *testing.T) { func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -5364,7 +5371,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -5379,7 +5386,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -5395,7 +5402,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { { "invalid metadata", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -5413,7 +5420,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -5432,7 +5439,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewSAMLIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -5448,6 +5455,8 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { []byte("certificate"), "", false, + nil, + "", idp.Options{}, )), ), @@ -5468,7 +5477,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewSAMLIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -5484,6 +5493,8 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { []byte("certificate"), "binding", false, + gu.Ptr(domain.SAMLNameIDFormatUnspecified), + "", idp.Options{}, )), ), @@ -5497,6 +5508,8 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { idp.ChangeSAMLMetadata([]byte("new metadata")), idp.ChangeSAMLBinding("new binding"), idp.ChangeSAMLWithSignedRequest(true), + idp.ChangeSAMLNameIDFormat(gu.Ptr(domain.SAMLNameIDFormatTransient)), + idp.ChangeSAMLTransientMappingAttributeName("customAttribute"), idp.ChangeSAMLOptions(idp.OptionChanges{ IsCreationAllowed: &t, IsLinkingAllowed: &t, @@ -5515,10 +5528,12 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { ctx: authz.WithInstanceID(context.Background(), "instance1"), id: "id1", provider: SAMLProvider{ - Name: "new name", - Metadata: []byte("new metadata"), - Binding: "new binding", - WithSignedRequest: true, + Name: "new name", + Metadata: []byte("new metadata"), + Binding: "new binding", + WithSignedRequest: true, + NameIDFormat: gu.Ptr(domain.SAMLNameIDFormatTransient), + TransientMappingAttributeName: "customAttribute", IDPOptions: idp.Options{ IsCreationAllowed: true, IsLinkingAllowed: true, @@ -5535,7 +5550,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateInstanceSAMLProvider(tt.args.ctx, tt.args.id, tt.args.provider) @@ -5554,7 +5569,7 @@ func TestCommandSide_UpdateInstanceGenericSAMLIDP(t *testing.T) { func TestCommandSide_RegenerateInstanceSAMLProviderCertificate(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm certificateAndKeyGenerator func(id string) ([]byte, []byte, error) } @@ -5575,7 +5590,7 @@ func TestCommandSide_RegenerateInstanceSAMLProviderCertificate(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: authz.WithInstanceID(context.Background(), "instance1"), @@ -5589,7 +5604,7 @@ func TestCommandSide_RegenerateInstanceSAMLProviderCertificate(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -5604,7 +5619,7 @@ func TestCommandSide_RegenerateInstanceSAMLProviderCertificate(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( instance.NewSAMLIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate, @@ -5620,6 +5635,8 @@ func TestCommandSide_RegenerateInstanceSAMLProviderCertificate(t *testing.T) { []byte("certificate"), "binding", false, + gu.Ptr(domain.SAMLNameIDFormatUnspecified), + "", idp.Options{}, )), ), @@ -5658,7 +5675,7 @@ func TestCommandSide_RegenerateInstanceSAMLProviderCertificate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, samlCertificateAndKeyGenerator: tt.fields.certificateAndKeyGenerator, } diff --git a/internal/command/org_idp.go b/internal/command/org_idp.go index f9d83ff9c..597783c78 100644 --- a/internal/command/org_idp.go +++ b/internal/command/org_idp.go @@ -1746,6 +1746,8 @@ func (c *Commands) prepareAddOrgSAMLProvider(a *org.Aggregate, writeModel *OrgSA cert, provider.Binding, provider.WithSignedRequest, + provider.NameIDFormat, + provider.TransientMappingAttributeName, provider.IDPOptions, ), }, nil @@ -1794,6 +1796,8 @@ func (c *Commands) prepareUpdateOrgSAMLProvider(a *org.Aggregate, writeModel *Or c.idpConfigEncryption, provider.Binding, provider.WithSignedRequest, + provider.NameIDFormat, + provider.TransientMappingAttributeName, provider.IDPOptions, ) if err != nil || event == nil { @@ -1837,6 +1841,8 @@ func (c *Commands) prepareRegenerateOrgSAMLProviderCertificate(a *org.Aggregate, c.idpConfigEncryption, writeModel.Binding, writeModel.WithSignedRequest, + writeModel.NameIDFormat, + writeModel.TransientMappingAttributeName, writeModel.Options, ) if err != nil || event == nil { diff --git a/internal/command/org_idp_model.go b/internal/command/org_idp_model.go index 2d8bc8f8f..df0009609 100644 --- a/internal/command/org_idp_model.go +++ b/internal/command/org_idp_model.go @@ -5,6 +5,7 @@ import ( "time" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/idp" "github.com/zitadel/zitadel/internal/repository/org" @@ -927,6 +928,8 @@ func (wm *OrgSAMLIDPWriteModel) NewChangedEvent( secretCrypto crypto.EncryptionAlgorithm, binding string, withSignedRequest bool, + nameIDFormat *domain.SAMLNameIDFormat, + transientMappingAttributeName string, options idp.Options, ) (*org.SAMLIDPChangedEvent, error) { changes, err := wm.SAMLIDPWriteModel.NewChanges( @@ -937,6 +940,8 @@ func (wm *OrgSAMLIDPWriteModel) NewChangedEvent( secretCrypto, binding, withSignedRequest, + nameIDFormat, + transientMappingAttributeName, options, ) if err != nil || len(changes) == 0 { diff --git a/internal/command/org_idp_test.go b/internal/command/org_idp_test.go index ebb868212..bcda24df2 100644 --- a/internal/command/org_idp_test.go +++ b/internal/command/org_idp_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/muhlemmer/gu" "github.com/stretchr/testify/assert" openid "github.com/zitadel/oidc/v3/pkg/oidc" "go.uber.org/mock/gomock" @@ -22,7 +23,7 @@ import ( func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -45,7 +46,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -62,7 +63,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -81,7 +82,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -101,7 +102,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { "invalid auth endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -122,7 +123,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { "invalid token endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -144,7 +145,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { "invalid user endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -167,7 +168,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { "invalid id attribute", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -191,7 +192,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewOAuthIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -237,7 +238,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewOAuthIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -296,7 +297,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -317,7 +318,7 @@ func TestCommandSide_AddOrgGenericOAuthIDP(t *testing.T) { func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -339,7 +340,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -355,7 +356,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -372,7 +373,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -391,7 +392,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { "invalid auth endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -411,7 +412,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { "invalid token endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -432,7 +433,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { "invalid user endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -454,7 +455,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { "invalid id attribute", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -477,7 +478,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -501,7 +502,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewOAuthIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -544,7 +545,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewOAuthIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -627,7 +628,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgGenericOAuthProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -646,7 +647,7 @@ func TestCommandSide_UpdateOrgGenericOAuthIDP(t *testing.T) { func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -669,7 +670,7 @@ func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -686,7 +687,7 @@ func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { { "invalid issuer", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -705,7 +706,7 @@ func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -725,7 +726,7 @@ func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -746,7 +747,7 @@ func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -787,7 +788,7 @@ func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -842,7 +843,7 @@ func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -863,7 +864,7 @@ func TestCommandSide_AddOrgGenericOIDCIDP(t *testing.T) { func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -885,7 +886,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -901,7 +902,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -918,7 +919,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { { "invalid issuer", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -937,7 +938,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -957,7 +958,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -978,7 +979,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1016,7 +1017,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1093,7 +1094,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgGenericOIDCProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -1112,7 +1113,7 @@ func TestCommandSide_UpdateOrgGenericOIDCIDP(t *testing.T) { func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -1134,7 +1135,7 @@ func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1150,7 +1151,7 @@ func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1168,7 +1169,7 @@ func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { { "invalid client secret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1187,7 +1188,7 @@ func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -1208,7 +1209,7 @@ func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { { name: "migrate ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1267,7 +1268,7 @@ func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { { name: "migrate full ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1338,7 +1339,7 @@ func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.MigrateOrgGenericOIDCToAzureADProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -1357,7 +1358,7 @@ func TestCommandSide_MigrateOrgGenericOIDCToAzureADProvider(t *testing.T) { func TestCommandSide_MigrateOrgOIDCToGoogleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -1379,7 +1380,7 @@ func TestCommandSide_MigrateOrgOIDCToGoogleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1396,7 +1397,7 @@ func TestCommandSide_MigrateOrgOIDCToGoogleIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1415,7 +1416,7 @@ func TestCommandSide_MigrateOrgOIDCToGoogleIDP(t *testing.T) { { "not found", fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -1435,7 +1436,7 @@ func TestCommandSide_MigrateOrgOIDCToGoogleIDP(t *testing.T) { { name: "migrate ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1488,7 +1489,7 @@ func TestCommandSide_MigrateOrgOIDCToGoogleIDP(t *testing.T) { { name: "migrate full ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewOIDCIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1554,7 +1555,7 @@ func TestCommandSide_MigrateOrgOIDCToGoogleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.MigrateOrgGenericOIDCToGoogleProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -1573,7 +1574,7 @@ func TestCommandSide_MigrateOrgOIDCToGoogleIDP(t *testing.T) { func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -1596,7 +1597,7 @@ func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -1613,7 +1614,7 @@ func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -1632,7 +1633,7 @@ func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { { "invalid client secret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -1652,7 +1653,7 @@ func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewAzureADIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1692,7 +1693,7 @@ func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewAzureADIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1747,7 +1748,7 @@ func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -1768,7 +1769,7 @@ func TestCommandSide_AddOrgAzureADIDP(t *testing.T) { func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -1790,7 +1791,7 @@ func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1806,7 +1807,7 @@ func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1823,7 +1824,7 @@ func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -1842,7 +1843,7 @@ func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -1862,7 +1863,7 @@ func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewAzureADIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1899,7 +1900,7 @@ func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewAzureADIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -1976,7 +1977,7 @@ func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgAzureADProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -1995,7 +1996,7 @@ func TestCommandSide_UpdateOrgAzureADIDP(t *testing.T) { func TestCommandSide_AddOrgGitHubIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -2018,7 +2019,7 @@ func TestCommandSide_AddOrgGitHubIDP(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2035,7 +2036,7 @@ func TestCommandSide_AddOrgGitHubIDP(t *testing.T) { { "invalid client secret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2054,7 +2055,7 @@ func TestCommandSide_AddOrgGitHubIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGitHubIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -2091,7 +2092,7 @@ func TestCommandSide_AddOrgGitHubIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGitHubIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -2142,7 +2143,7 @@ func TestCommandSide_AddOrgGitHubIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -2163,7 +2164,7 @@ func TestCommandSide_AddOrgGitHubIDP(t *testing.T) { func TestCommandSide_UpdateOrgGitHubIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -2185,7 +2186,7 @@ func TestCommandSide_UpdateOrgGitHubIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2201,7 +2202,7 @@ func TestCommandSide_UpdateOrgGitHubIDP(t *testing.T) { { "invalid client id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2218,7 +2219,7 @@ func TestCommandSide_UpdateOrgGitHubIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -2237,7 +2238,7 @@ func TestCommandSide_UpdateOrgGitHubIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGitHubIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -2271,7 +2272,7 @@ func TestCommandSide_UpdateOrgGitHubIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGitHubIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -2342,7 +2343,7 @@ func TestCommandSide_UpdateOrgGitHubIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgGitHubProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -2361,7 +2362,7 @@ func TestCommandSide_UpdateOrgGitHubIDP(t *testing.T) { func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -2384,7 +2385,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2401,7 +2402,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2420,7 +2421,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2440,7 +2441,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid auth endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2461,7 +2462,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid token endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2483,7 +2484,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid user endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2506,7 +2507,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGitHubEnterpriseIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -2550,7 +2551,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGitHubEnterpriseIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -2607,7 +2608,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -2628,7 +2629,7 @@ func TestCommandSide_AddOrgGitHubEnterpriseIDP(t *testing.T) { func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -2650,7 +2651,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2666,7 +2667,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2683,7 +2684,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2702,7 +2703,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid auth endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2722,7 +2723,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid token endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2743,7 +2744,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { "invalid user endpoint", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -2765,7 +2766,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -2788,7 +2789,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGitHubEnterpriseIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -2829,7 +2830,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGitHubEnterpriseIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -2909,7 +2910,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgGitHubEnterpriseProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -2928,7 +2929,7 @@ func TestCommandSide_UpdateOrgGitHubEnterpriseIDP(t *testing.T) { func TestCommandSide_AddOrgGitLabIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -2951,7 +2952,7 @@ func TestCommandSide_AddOrgGitLabIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2968,7 +2969,7 @@ func TestCommandSide_AddOrgGitLabIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -2987,7 +2988,7 @@ func TestCommandSide_AddOrgGitLabIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGitLabIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3024,7 +3025,7 @@ func TestCommandSide_AddOrgGitLabIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGitLabIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3074,7 +3075,7 @@ func TestCommandSide_AddOrgGitLabIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -3095,7 +3096,7 @@ func TestCommandSide_AddOrgGitLabIDP(t *testing.T) { func TestCommandSide_UpdateOrgGitLabIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -3117,7 +3118,7 @@ func TestCommandSide_UpdateOrgGitLabIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -3133,7 +3134,7 @@ func TestCommandSide_UpdateOrgGitLabIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -3150,7 +3151,7 @@ func TestCommandSide_UpdateOrgGitLabIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -3169,7 +3170,7 @@ func TestCommandSide_UpdateOrgGitLabIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGitLabIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3203,7 +3204,7 @@ func TestCommandSide_UpdateOrgGitLabIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGitLabIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3272,7 +3273,7 @@ func TestCommandSide_UpdateOrgGitLabIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgGitLabProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -3291,7 +3292,7 @@ func TestCommandSide_UpdateOrgGitLabIDP(t *testing.T) { func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -3314,7 +3315,7 @@ func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3331,7 +3332,7 @@ func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { { "invalid issuer", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3350,7 +3351,7 @@ func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3370,7 +3371,7 @@ func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3391,7 +3392,7 @@ func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGitLabSelfHostedIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3431,7 +3432,7 @@ func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGitLabSelfHostedIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3484,7 +3485,7 @@ func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -3505,7 +3506,7 @@ func TestCommandSide_AddOrgGitLabSelfHostedIDP(t *testing.T) { func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -3527,7 +3528,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -3543,7 +3544,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -3560,7 +3561,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { { "invalid issuer", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -3579,7 +3580,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -3599,7 +3600,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -3620,7 +3621,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGitLabSelfHostedIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3657,7 +3658,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGitLabSelfHostedIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3731,7 +3732,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgGitLabSelfHostedProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -3750,7 +3751,7 @@ func TestCommandSide_UpdateOrgGitLabSelfHostedIDP(t *testing.T) { func TestCommandSide_AddOrgGoogleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -3773,7 +3774,7 @@ func TestCommandSide_AddOrgGoogleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3790,7 +3791,7 @@ func TestCommandSide_AddOrgGoogleIDP(t *testing.T) { { "invalid clientSecret", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -3809,7 +3810,7 @@ func TestCommandSide_AddOrgGoogleIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGoogleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3846,7 +3847,7 @@ func TestCommandSide_AddOrgGoogleIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewGoogleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -3896,7 +3897,7 @@ func TestCommandSide_AddOrgGoogleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -3917,7 +3918,7 @@ func TestCommandSide_AddOrgGoogleIDP(t *testing.T) { func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -3939,7 +3940,7 @@ func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -3955,7 +3956,7 @@ func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -3972,7 +3973,7 @@ func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -3991,7 +3992,7 @@ func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGoogleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -4025,7 +4026,7 @@ func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewGoogleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -4094,7 +4095,7 @@ func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgGoogleProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -4113,7 +4114,7 @@ func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) { func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -4136,7 +4137,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4153,7 +4154,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { "invalid baseDN", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4172,7 +4173,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { "invalid binddn", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4192,7 +4193,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { "invalid password", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4213,7 +4214,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { "invalid userbase", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4235,7 +4236,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { "invalid servers", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4258,7 +4259,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { "invalid userObjectClasses", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4282,7 +4283,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { "invalid userFilters", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4307,7 +4308,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -4359,7 +4360,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -4452,7 +4453,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -4473,7 +4474,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) { func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -4495,7 +4496,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -4511,7 +4512,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -4528,7 +4529,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { "invalid baseDN", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -4547,7 +4548,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { "invalid binddn", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -4567,7 +4568,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { "invalid userbase", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -4588,7 +4589,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { "invalid servers", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -4610,7 +4611,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { "invalid userObjectClasses", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -4633,7 +4634,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { "invalid userFilters", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -4657,7 +4658,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -4685,7 +4686,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -4733,7 +4734,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -4853,7 +4854,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgLDAPProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -4872,7 +4873,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) { func TestCommandSide_AddOrgAppleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm } @@ -4895,7 +4896,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4912,7 +4913,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) { { "invalid teamID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4931,7 +4932,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) { { "invalid keyID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4951,7 +4952,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) { { "invalid privateKey", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -4972,7 +4973,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewAppleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5013,7 +5014,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewAppleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5067,7 +5068,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, } @@ -5088,7 +5089,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) { func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -5110,7 +5111,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -5126,7 +5127,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { { "invalid clientID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -5143,7 +5144,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { { "invalid teamID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -5162,7 +5163,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { { "invalid keyID", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -5182,7 +5183,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -5203,7 +5204,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewAppleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5241,7 +5242,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewAppleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5316,7 +5317,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgAppleProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -5339,7 +5340,7 @@ func stringPointer(s string) *string { func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore idGenerator id.Generator secretCrypto crypto.EncryptionAlgorithm certificateAndKeyGenerator func(id string) ([]byte, []byte, error) @@ -5363,7 +5364,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -5380,7 +5381,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { { "invalid metadata", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"), }, args{ @@ -5399,7 +5400,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { { name: "ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewSAMLIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5415,6 +5416,8 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { []byte("certificate"), "", false, + nil, + "", idp.Options{}, ), ), @@ -5438,7 +5441,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { { name: "ok all set", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), expectPush( org.NewSAMLIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5454,6 +5457,8 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { []byte("certificate"), "binding", true, + gu.Ptr(domain.SAMLNameIDFormatTransient), + "customAttribute", idp.Options{ IsCreationAllowed: true, IsLinkingAllowed: true, @@ -5471,10 +5476,12 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { ctx: context.Background(), resourceOwner: "org1", provider: SAMLProvider{ - Name: "name", - Metadata: []byte("metadata"), - Binding: "binding", - WithSignedRequest: true, + Name: "name", + Metadata: []byte("metadata"), + Binding: "binding", + WithSignedRequest: true, + NameIDFormat: gu.Ptr(domain.SAMLNameIDFormatTransient), + TransientMappingAttributeName: "customAttribute", IDPOptions: idp.Options{ IsCreationAllowed: true, IsLinkingAllowed: true, @@ -5492,7 +5499,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idGenerator: tt.fields.idGenerator, idpConfigEncryption: tt.fields.secretCrypto, samlCertificateAndKeyGenerator: tt.fields.certificateAndKeyGenerator, @@ -5514,7 +5521,7 @@ func TestCommandSide_AddOrgSAMLIDP(t *testing.T) { func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm } type args struct { @@ -5536,7 +5543,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -5552,7 +5559,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { { "invalid name", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -5569,7 +5576,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { { "invalid metadata", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -5588,7 +5595,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -5610,7 +5617,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { { name: "no changes", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewSAMLIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5626,6 +5633,8 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { []byte("certificate"), "", false, + nil, + "", idp.Options{}, )), ), @@ -5647,7 +5656,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewSAMLIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5663,6 +5672,8 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { []byte("certificate"), "binding", false, + gu.Ptr(domain.SAMLNameIDFormatUnspecified), + "", idp.Options{}, )), ), @@ -5676,6 +5687,8 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { idp.ChangeSAMLMetadata([]byte("new metadata")), idp.ChangeSAMLBinding("new binding"), idp.ChangeSAMLWithSignedRequest(true), + idp.ChangeSAMLNameIDFormat(gu.Ptr(domain.SAMLNameIDFormatTransient)), + idp.ChangeSAMLTransientMappingAttributeName("customAttribute"), idp.ChangeSAMLOptions(idp.OptionChanges{ IsCreationAllowed: &t, IsLinkingAllowed: &t, @@ -5695,10 +5708,12 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { resourceOwner: "org1", id: "id1", provider: SAMLProvider{ - Name: "new name", - Metadata: []byte("new metadata"), - Binding: "new binding", - WithSignedRequest: true, + Name: "new name", + Metadata: []byte("new metadata"), + Binding: "new binding", + WithSignedRequest: true, + NameIDFormat: gu.Ptr(domain.SAMLNameIDFormatTransient), + TransientMappingAttributeName: "customAttribute", IDPOptions: idp.Options{ IsCreationAllowed: true, IsLinkingAllowed: true, @@ -5715,7 +5730,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, } got, err := c.UpdateOrgSAMLProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider) @@ -5734,7 +5749,7 @@ func TestCommandSide_UpdateOrgSAMLIDP(t *testing.T) { func TestCommandSide_RegenerateOrgSAMLProviderCertificate(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore + eventstore func(*testing.T) *eventstore.Eventstore secretCrypto crypto.EncryptionAlgorithm certificateAndKeyGenerator func(id string) ([]byte, []byte, error) } @@ -5756,7 +5771,7 @@ func TestCommandSide_RegenerateOrgSAMLProviderCertificate(t *testing.T) { { "invalid id", fields{ - eventstore: eventstoreExpect(t), + eventstore: expectEventstore(), }, args{ ctx: context.Background(), @@ -5771,7 +5786,7 @@ func TestCommandSide_RegenerateOrgSAMLProviderCertificate(t *testing.T) { { name: "not found", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter(), ), }, @@ -5789,7 +5804,7 @@ func TestCommandSide_RegenerateOrgSAMLProviderCertificate(t *testing.T) { { name: "change ok", fields: fields{ - eventstore: eventstoreExpect(t, + eventstore: expectEventstore( expectFilter( eventFromEventPusher( org.NewSAMLIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, @@ -5805,6 +5820,8 @@ func TestCommandSide_RegenerateOrgSAMLProviderCertificate(t *testing.T) { []byte("certificate"), "binding", false, + gu.Ptr(domain.SAMLNameIDFormatUnspecified), + "", idp.Options{}, )), ), @@ -5844,7 +5861,7 @@ func TestCommandSide_RegenerateOrgSAMLProviderCertificate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := &Commands{ - eventstore: tt.fields.eventstore, + eventstore: tt.fields.eventstore(t), idpConfigEncryption: tt.fields.secretCrypto, samlCertificateAndKeyGenerator: tt.fields.certificateAndKeyGenerator, } diff --git a/internal/domain/idp.go b/internal/domain/idp.go index 3df11fa0d..e2571f6b0 100644 --- a/internal/domain/idp.go +++ b/internal/domain/idp.go @@ -134,3 +134,12 @@ const ( AutoLinkingOptionUsername AutoLinkingOptionEmail ) + +type SAMLNameIDFormat uint8 + +const ( + SAMLNameIDFormatUnspecified SAMLNameIDFormat = iota + SAMLNameIDFormatEmailAddress + SAMLNameIDFormatPersistent + SAMLNameIDFormatTransient +) diff --git a/internal/idp/providers/saml/mapper.go b/internal/idp/providers/saml/mapper.go index 506d9b3a0..eef16dfbb 100644 --- a/internal/idp/providers/saml/mapper.go +++ b/internal/idp/providers/saml/mapper.go @@ -1,7 +1,6 @@ package saml import ( - "github.com/crewjam/saml" "golang.org/x/text/language" "github.com/zitadel/zitadel/internal/domain" @@ -20,8 +19,8 @@ func NewUser() *UserMapper { return &UserMapper{Attributes: map[string][]string{}} } -func (u *UserMapper) SetID(id *saml.NameID) { - u.ID = id.Value +func (u *UserMapper) SetID(id string) { + u.ID = id } // GetID is an implementation of the [idp.User] interface. diff --git a/internal/idp/providers/saml/saml.go b/internal/idp/providers/saml/saml.go index fc08f6e80..702e1481e 100644 --- a/internal/idp/providers/saml/saml.go +++ b/internal/idp/providers/saml/saml.go @@ -11,6 +11,7 @@ import ( "github.com/crewjam/saml" "github.com/crewjam/saml/samlsp" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/idp" "github.com/zitadel/zitadel/internal/zerrors" ) @@ -26,7 +27,9 @@ type Provider struct { spOptions *samlsp.Options - binding string + binding string + nameIDFormat saml.NameIDFormat + transientMappingAttributeName string isLinkingAllowed bool isCreationAllowed bool @@ -77,6 +80,18 @@ func WithBinding(binding string) ProviderOpts { } } +func WithNameIDFormat(format domain.SAMLNameIDFormat) ProviderOpts { + return func(p *Provider) { + p.nameIDFormat = nameIDFormatFromDomain(format) + } +} + +func WithTransientMappingAttributeName(attribute string) ProviderOpts { + return func(p *Provider) { + p.transientMappingAttributeName = attribute + } +} + func WithCustomRequestTracker(tracker samlsp.RequestTracker) ProviderOpts { return func(p *Provider) { p.requestTracker = tracker @@ -124,6 +139,8 @@ func New( name: name, spOptions: &opts, Certificate: certificate, + // the library uses transient as default, which does not make sense for federating accounts + nameIDFormat: saml.PersistentNameIDFormat, } for _, option := range options { option(provider) @@ -156,10 +173,7 @@ func (p *Provider) GetSP() (*samlsp.Middleware, error) { if err != nil { return nil, zerrors.ThrowInternal(err, "SAML-qee09ffuq5", "Errors.Intent.IDPInvalid") } - // the library uses transient as default, which we currently can't handle (https://github.com/zitadel/zitadel/discussions/7421) - // for the moment we'll use persistent (for those who actually use it from the saml request) and add an option - // later on to specify on the provider: https://github.com/zitadel/zitadel/issues/7743 - sp.ServiceProvider.AuthnNameIDFormat = saml.PersistentNameIDFormat + sp.ServiceProvider.AuthnNameIDFormat = p.nameIDFormat if p.requestTracker != nil { sp.RequestTracker = p.requestTracker } @@ -180,3 +194,22 @@ func (p *Provider) BeginAuth(ctx context.Context, state string, _ ...idp.Paramet state: state, }, nil } + +func (p *Provider) TransientMappingAttributeName() string { + return p.transientMappingAttributeName +} + +func nameIDFormatFromDomain(format domain.SAMLNameIDFormat) saml.NameIDFormat { + switch format { + case domain.SAMLNameIDFormatUnspecified: + return saml.UnspecifiedNameIDFormat + case domain.SAMLNameIDFormatEmailAddress: + return saml.EmailAddressNameIDFormat + case domain.SAMLNameIDFormatPersistent: + return saml.PersistentNameIDFormat + case domain.SAMLNameIDFormatTransient: + return saml.TransientNameIDFormat + default: + return saml.UnspecifiedNameIDFormat + } +} diff --git a/internal/idp/providers/saml/saml_test.go b/internal/idp/providers/saml/saml_test.go index 28dc92168..dc8e8e211 100644 --- a/internal/idp/providers/saml/saml_test.go +++ b/internal/idp/providers/saml/saml_test.go @@ -3,10 +3,12 @@ package saml import ( "testing" + "github.com/crewjam/saml" "github.com/crewjam/saml/samlsp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/idp/providers/saml/requesttracker" ) @@ -20,16 +22,18 @@ func TestProvider_Options(t *testing.T) { options []ProviderOpts } type want struct { - err bool - name string - linkingAllowed bool - creationAllowed bool - autoCreation bool - autoUpdate bool - binding string - withSignedRequest bool - requesttracker samlsp.RequestTracker - entityID string + err bool + name string + linkingAllowed bool + creationAllowed bool + autoCreation bool + autoUpdate bool + binding string + nameIDFormat saml.NameIDFormat + transientMappingAttributeName string + withSignedRequest bool + requesttracker samlsp.RequestTracker + entityID string } tests := []struct { name string @@ -103,10 +107,11 @@ func TestProvider_Options(t *testing.T) { creationAllowed: false, autoCreation: false, autoUpdate: false, + nameIDFormat: saml.PersistentNameIDFormat, }, }, { - name: "all true", + name: "all set / true", fields: fields{ name: "saml", key: []byte("-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAxHd087RoEm9ywVWZ/H+tDWxQsmVvhfRz4jAq/RfU+OWXNH4J\njMMSHdFs0Q+WP98nNXRyc7fgbMb8NdmlB2yD4qLYapN5SDaBc5dh/3EnyFt53oSs\njTlKnQUPAeJr2qh/NY046CfyUyQMM4JR5OiQFo4TssfWnqdcgamGt0AEnk2lvbMZ\nKQdAqNS9lDzYbjMGavEQPTZE35mFXFQXjaooZXq+TIa7hbaq7/idH7cHNbLcPLgj\nfPQA8q+DYvnvhXlmq0LPQZH3Oiixf+SF2vRwrBzT2mqGD2OiOkUmhuPwyqEiiBHt\nfxklRtRU6WfLa1Gcb1PsV0uoBGpV3KybIl/GlwIDAQABAoIBAEQjDduLgOCL6Gem\n0X3hpdnW6/HC/jed/Sa//9jBECq2LYeWAqff64ON40hqOHi0YvvGA/+gEOSI6mWe\nsv5tIxxRz+6+cLybsq+tG96kluCE4TJMHy/nY7orS/YiWbd+4odnEApr+D3fbZ/b\nnZ1fDsHTyn8hkYx6jLmnWsJpIHDp7zxD76y7k2Bbg6DZrCGiVxngiLJk23dvz79W\np03lHLM7XE92aFwXQmhfxHGxrbuoB/9eY4ai5IHp36H4fw0vL6NXdNQAo/bhe0p9\nAYB7y0ZumF8Hg0Z/BmMeEzLy6HrYB+VE8cO93pNjhSyH+p2yDB/BlUyTiRLQAoM0\nVTmOZXECgYEA7NGlzpKNhyQEJihVqt0MW0LhKIO/xbBn+XgYfX6GpqPa/ucnMx5/\nVezpl3gK8IU4wPUhAyXXAHJiqNBcEeyxrw0MXLujDVMJgYaLysCLJdvMVgoY08mS\nK5IQivpbozpf4+0y3mOnA+Sy1kbfxv2X8xiWLODRQW3f3q/xoklwOR8CgYEA1GEe\nfaibOFTQAYcIVj77KXtBfYZsX3EGAyfAN9O7cKHq5oaxVstwnF47WxpuVtoKZxCZ\nbNm9D5WvQ9b+Ztpioe42tzwE7Bff/Osj868GcDdRPK7nFlh9N2yVn/D514dOYVwR\n4MBr1KrJzgRWt4QqS4H+to1GzudDTSNlG7gnK4kCgYBUi6AbOHzoYzZL/RhgcJwp\ntJ23nhmH1Su5h2OO4e3mbhcP66w19sxU+8iFN+kH5zfUw26utgKk+TE5vXExQQRK\nT2k7bg2PAzcgk80ybD0BHhA8I0yrx4m0nmfjhe/TPVLgh10iwgbtP+eM0i6v1vc5\nZWyvxu9N4ZEL6lpkqr0y1wKBgG/NAIQd8jhhTW7Aav8cAJQBsqQl038avJOEpYe+\nCnpsgoAAf/K0/f8TDCQVceh+t+MxtdK7fO9rWOxZjWsPo8Si5mLnUaAHoX4/OpnZ\nlYYVWMqdOEFnK+O1Yb7k2GFBdV2DXlX2dc1qavntBsls5ecB89id3pyk2aUN8Pf6\npYQhAoGAMGtrHFely9wyaxI0RTCyfmJbWZHGVGkv6ELK8wneJjdjl82XOBUGCg5q\naRCrTZ3dPitKwrUa6ibJCIFCIziiriBmjDvTHzkMvoJEap2TVxYNDR6IfINVsQ57\nlOsiC4A2uGq4Lbfld+gjoplJ5GX6qXtTgZ6m7eo0y7U6zm2tkN0=\n-----END RSA PRIVATE KEY-----\n"), @@ -121,18 +126,22 @@ func TestProvider_Options(t *testing.T) { WithSignedRequest(), WithCustomRequestTracker(&requesttracker.RequestTracker{}), WithEntityID("entityID"), + WithNameIDFormat(domain.SAMLNameIDFormatTransient), + WithTransientMappingAttributeName("attribute"), }, }, want: want{ - name: "saml", - linkingAllowed: true, - creationAllowed: true, - autoCreation: true, - autoUpdate: true, - binding: "binding", - withSignedRequest: true, - requesttracker: &requesttracker.RequestTracker{}, - entityID: "entityID", + name: "saml", + linkingAllowed: true, + creationAllowed: true, + autoCreation: true, + autoUpdate: true, + binding: "binding", + entityID: "entityID", + nameIDFormat: saml.TransientNameIDFormat, + transientMappingAttributeName: "attribute", + withSignedRequest: true, + requesttracker: &requesttracker.RequestTracker{}, }, }, } @@ -152,6 +161,8 @@ func TestProvider_Options(t *testing.T) { a.Equal(tt.want.autoCreation, provider.IsAutoCreation()) a.Equal(tt.want.autoUpdate, provider.IsAutoUpdate()) a.Equal(tt.want.binding, provider.binding) + 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.requesttracker, provider.requestTracker) a.Equal(tt.want.entityID, provider.spOptions.EntityID) diff --git a/internal/idp/providers/saml/session.go b/internal/idp/providers/saml/session.go index af5ec0caf..577e6a764 100644 --- a/internal/idp/providers/saml/session.go +++ b/internal/idp/providers/saml/session.go @@ -17,8 +17,9 @@ var _ idp.Session = (*Session)(nil) // Session is the [idp.Session] implementation for the SAML provider. type Session struct { - ServiceProvider *samlsp.Middleware - state string + ServiceProvider *samlsp.Middleware + state string + TransientMappingAttributeName string RequestID string Request *http.Request @@ -26,6 +27,19 @@ type Session struct { Assertion *saml.Assertion } +func NewSession(provider *Provider, requestID string, request *http.Request) (*Session, error) { + sp, err := provider.GetSP() + if err != nil { + return nil, err + } + return &Session{ + ServiceProvider: sp, + TransientMappingAttributeName: provider.TransientMappingAttributeName(), + RequestID: requestID, + Request: request, + }, nil +} + // GetAuth implements the [idp.Session] interface. func (s *Session) GetAuth(ctx context.Context) (string, bool) { url, _ := url.Parse(s.state) @@ -56,8 +70,17 @@ func (s *Session) FetchUser(ctx context.Context) (user idp.User, err error) { return nil, zerrors.ThrowInvalidArgument(err, "SAML-nuo0vphhh9", "Errors.Intent.ResponseInvalid") } + nameID := s.Assertion.Subject.NameID userMapper := NewUser() - userMapper.SetID(s.Assertion.Subject.NameID) + // use the nameID as default mapping id + userMapper.SetID(nameID.Value) + if nameID.Format == string(saml.TransientNameIDFormat) { + mappingID, err := s.transientMappingID() + if err != nil { + return nil, err + } + userMapper.SetID(mappingID) + } for _, statement := range s.Assertion.AttributeStatements { for _, attribute := range statement.Attributes { values := make([]string, len(attribute.Values)) @@ -70,6 +93,21 @@ func (s *Session) FetchUser(ctx context.Context) (user idp.User, err error) { return userMapper, nil } +func (s *Session) transientMappingID() (string, error) { + for _, statement := range s.Assertion.AttributeStatements { + for _, attribute := range statement.Attributes { + if attribute.Name != s.TransientMappingAttributeName { + continue + } + if len(attribute.Values) != 1 { + return "", zerrors.ThrowInvalidArgument(nil, "SAML-Soij4", "Errors.Intent.MissingSingleMappingAttribute") + } + return attribute.Values[0].Value, nil + } + } + return "", zerrors.ThrowInvalidArgument(nil, "SAML-swwg2", "Errors.Intent.MissingSingleMappingAttribute") +} + type TempResponseWriter struct { header http.Header content *bytes.Buffer diff --git a/internal/idp/providers/saml/session_test.go b/internal/idp/providers/saml/session_test.go index 3ab33a855..f16223438 100644 --- a/internal/idp/providers/saml/session_test.go +++ b/internal/idp/providers/saml/session_test.go @@ -27,7 +27,6 @@ func TestSession_FetchUser(t *testing.T) { options []ProviderOpts } type args struct { - intentID string requestID string request *http.Request } @@ -143,6 +142,7 @@ func TestSession_FetchUser(t *testing.T) { WithBinding(saml.HTTPRedirectBinding), WithSignedRequest(), WithCustomRequestTracker(&requesttracker.RequestTracker{}), + WithTransientMappingAttributeName("urn:oid:1.3.6.1.4.1.5923.1.1.1.6"), }, rootURL: "http://localhost:8080/idps/228968792372281708/", }, @@ -166,6 +166,76 @@ func TestSession_FetchUser(t *testing.T) { }, }, }, + { + name: "post with user param (transient with custom mapping)", + fields: fields{ + name: "saml", + key: []byte("-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAxHd087RoEm9ywVWZ/H+tDWxQsmVvhfRz4jAq/RfU+OWXNH4J\njMMSHdFs0Q+WP98nNXRyc7fgbMb8NdmlB2yD4qLYapN5SDaBc5dh/3EnyFt53oSs\njTlKnQUPAeJr2qh/NY046CfyUyQMM4JR5OiQFo4TssfWnqdcgamGt0AEnk2lvbMZ\nKQdAqNS9lDzYbjMGavEQPTZE35mFXFQXjaooZXq+TIa7hbaq7/idH7cHNbLcPLgj\nfPQA8q+DYvnvhXlmq0LPQZH3Oiixf+SF2vRwrBzT2mqGD2OiOkUmhuPwyqEiiBHt\nfxklRtRU6WfLa1Gcb1PsV0uoBGpV3KybIl/GlwIDAQABAoIBAEQjDduLgOCL6Gem\n0X3hpdnW6/HC/jed/Sa//9jBECq2LYeWAqff64ON40hqOHi0YvvGA/+gEOSI6mWe\nsv5tIxxRz+6+cLybsq+tG96kluCE4TJMHy/nY7orS/YiWbd+4odnEApr+D3fbZ/b\nnZ1fDsHTyn8hkYx6jLmnWsJpIHDp7zxD76y7k2Bbg6DZrCGiVxngiLJk23dvz79W\np03lHLM7XE92aFwXQmhfxHGxrbuoB/9eY4ai5IHp36H4fw0vL6NXdNQAo/bhe0p9\nAYB7y0ZumF8Hg0Z/BmMeEzLy6HrYB+VE8cO93pNjhSyH+p2yDB/BlUyTiRLQAoM0\nVTmOZXECgYEA7NGlzpKNhyQEJihVqt0MW0LhKIO/xbBn+XgYfX6GpqPa/ucnMx5/\nVezpl3gK8IU4wPUhAyXXAHJiqNBcEeyxrw0MXLujDVMJgYaLysCLJdvMVgoY08mS\nK5IQivpbozpf4+0y3mOnA+Sy1kbfxv2X8xiWLODRQW3f3q/xoklwOR8CgYEA1GEe\nfaibOFTQAYcIVj77KXtBfYZsX3EGAyfAN9O7cKHq5oaxVstwnF47WxpuVtoKZxCZ\nbNm9D5WvQ9b+Ztpioe42tzwE7Bff/Osj868GcDdRPK7nFlh9N2yVn/D514dOYVwR\n4MBr1KrJzgRWt4QqS4H+to1GzudDTSNlG7gnK4kCgYBUi6AbOHzoYzZL/RhgcJwp\ntJ23nhmH1Su5h2OO4e3mbhcP66w19sxU+8iFN+kH5zfUw26utgKk+TE5vXExQQRK\nT2k7bg2PAzcgk80ybD0BHhA8I0yrx4m0nmfjhe/TPVLgh10iwgbtP+eM0i6v1vc5\nZWyvxu9N4ZEL6lpkqr0y1wKBgG/NAIQd8jhhTW7Aav8cAJQBsqQl038avJOEpYe+\nCnpsgoAAf/K0/f8TDCQVceh+t+MxtdK7fO9rWOxZjWsPo8Si5mLnUaAHoX4/OpnZ\nlYYVWMqdOEFnK+O1Yb7k2GFBdV2DXlX2dc1qavntBsls5ecB89id3pyk2aUN8Pf6\npYQhAoGAMGtrHFely9wyaxI0RTCyfmJbWZHGVGkv6ELK8wneJjdjl82XOBUGCg5q\naRCrTZ3dPitKwrUa6ibJCIFCIziiriBmjDvTHzkMvoJEap2TVxYNDR6IfINVsQ57\nlOsiC4A2uGq4Lbfld+gjoplJ5GX6qXtTgZ6m7eo0y7U6zm2tkN0=\n-----END RSA PRIVATE KEY-----\n"), + certificate: []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"), + metadata: []byte("\n \n \n \n \n MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=\n \n \n \n \n \n \n MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=\n \n \n \n \n \n \n \n urn:oasis:names:tc:SAML:2.0:nameid-format:transient\n \n \n \n"), + options: []ProviderOpts{ + WithLinkingAllowed(), + WithCreationAllowed(), + WithAutoCreation(), + WithAutoUpdate(), + WithBinding(saml.HTTPRedirectBinding), + WithSignedRequest(), + WithCustomRequestTracker(&requesttracker.RequestTracker{}), + WithTransientMappingAttributeName("urn:oid:0.9.2342.19200300.100.1.1"), + }, + rootURL: "http://localhost:8080/idps/228968792372281708/", + }, + args: args{ + request: httpPostFormRequest(t, + "http://localhost:8080/idps/228968792372281708/saml/acs", + "232881438356144492", + "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgSUQ9ImlkLTA4ZTA3MTFhYzYwZjE2Mzc2MTdhYjZhNDZkZDk0ZTZkMWQ3MDgzMWQiIEluUmVzcG9uc2VUbz0iaWQtYjIyYzkwZGI4OGJmMDFkODJmZmIwYTdiNmZlMjVhYzlmY2IyYzY3OSIgVmVyc2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMjMtMDktMjFUMTM6NDk6MjMuOTM4WiIgRGVzdGluYXRpb249Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9pZHBzLzIyODk2ODc5MjM3MjI4MTcwOC9zYW1sL2FjcyI+PHNhbWw6SXNzdWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5odHRwOi8vbG9jYWxob3N0OjgwMDAvbWV0YWRhdGE8L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNyc2Etc2hhMSIvPjxkczpSZWZlcmVuY2UgVVJJPSIjaWQtMDhlMDcxMWFjNjBmMTYzNzYxN2FiNmE0NmRkOTRlNmQxZDcwODMxZCI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiLz48ZHM6RGlnZXN0VmFsdWU+OWF2ektOOWhpazE4ZkFRdnZNZzJBZFoyYm9VPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5VMkFJOFNzMng5TDAwV3RkaVFlbldCSVFCcGJLNnU4ZU9XVGE2WExKR0lWMWg4d3VOdURqM2luVGpMVUhITkNUSHhTdTFXSE9OSW1CL3QwWlE1Z3EvYXlkcVVqaEVkNG50LysyaXBKelZjZHVHUG5nYjlMWjJ5R1Rsd1JiQkcyMzd4eCtlRWhUMUcrTUFGa3BtbnUrei9RN09vUjdQWHVZOWt6NTRCb0tVM1htK1UyWm9GVy9pVjhId01kYTJMajVLT0pjcnppSWVtNHF0dHlIZXBqcjI3NUhPM2hybzgvVW0xMm8wdk10OUhwaHJua0RNVzgzM3Q5c0k2aW5GRndiOUJkdm5ORkVxYkhCZ2RsemR5T0NqaWdreVNlTzZQNzhQQlhUTWlhM3RVaGxEL0dlZ2hmbTJ4NVI1Q2QrOXJ5RktjYlBKLzlUaFhwbTlIYUJ4R1RZNEE9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJREJ6Q0NBZStnQXdJQkFnSUpBUHIvTXJsYzhFR2hNQTBHQ1NxR1NJYjNEUUVCQlFVQU1Cb3hHREFXQmdOVkJBTU1EM2QzZHk1bGVHRnRjR3hsTG1OdmJUQWVGdzB4TlRFeU1qZ3hPVEU1TkRWYUZ3MHlOVEV5TWpVeE9URTVORFZhTUJveEdEQVdCZ05WQkFNTUQzZDNkeTVsZUdGdGNHeGxMbU52YlRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTkRvV3pMb3M0TFd4VG44R3l1MmxFYmw0V2NlbFViZ0xONXpZbTRyb244QWhzK3J2Y3N1MnprZEQvczZqZEdKSThXcUpLaFlLMnU2MXlnblhnQVpxQzZnZ3RGUG5CcGl6Y0R6amdORDJnK2F1Y1NvVU9ESHQ2N2YwZlF1QW11cE4venA1TVp5c0o2SUhMSm5ZTE5wZkpZazk2bFJ6OU9Ebk8xTXBxdHI5UFd4bStwejduenE1RjB2UmVwa2dwY1J4djZ1ZlFCamxyRnl0Y2N5RVZkWHJ2RnRralhjbmhWVk5TUjRrSHVPT01TNkQ3cGViU0oxbXJDbXNoYkQ1U1gxalhQQktGUEFqb3pZWDZQeHFMeFV4MVk0ZmFGRWY0TUJCVmNJbnlCNG9VUk5CMnM1OWhFRWkyanE5aXpORTdFYkVLNkJZNXNFaG9DUGw5bTMyekU2bGprQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZCOVprbEMxT3JrMnpsNTZ6ZzA4ZWk3c3MvK2lNQjhHQTFVZEl3UVlNQmFBRkI5WmtsQzFPcmsyemw1NnpnMDhlaTdzcy8raU1Bd0dBMVVkRXdRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFRkJRQURnZ0VCQUFWb1RTUTVwQWlydzhPUjlGWjFiUlN1VERoWTl1eHpsL09MN2xVbXN2MmNNTmVDQjNCUlpxbTNtRnQrY3dOOEdzSDZmM3V2Tk9OSWhnRnBUR041TEVjWFF6ODl6SkV6QitxYUhxbWJGcEhRbC9zeDJCOGV6TmdULzg4MkgySUgwMGRYRVNFZnkvKzFnSGcycHhqR25oUkJONmVsL2dTYURpeVNJTUtiaWxEcmZmdXZ4aUNmYnBQTjBOUlJpUEpoZDJheTlLdUwvUnhRUmwxZ2w5Y0hhV2lvdVdXYmExYlNCYjJaUGh2MnJQTVVzRm85OG50a0dDT2JEWDZZMVNwa3Ftb1RicnNiR0ZzVEcyREx4bnZyNEdkTjFCU3IwVXUvS1YzYWRqNDdXa1hWUGVNWVF0aS9iUW14UUI4dFJGaHJ3ODBxYWtUTFV6cmVPOTZXemxCQk10WT08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48L2RzOlNpZ25hdHVyZT48c2FtbHA6U3RhdHVzPjxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWxwOlN0YXR1cz48c2FtbDpBc3NlcnRpb24geG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgSUQ9ImlkLTQ1ZTcyMTkyNjU4NmNkZGUzNDQ2NmI0MzQ5NDg4YjA5MDZhNTU3OGIiIElzc3VlSW5zdGFudD0iMjAyMy0wOS0yMVQxMzo0OToyMy45NDFaIiBWZXJzaW9uPSIyLjAiPjxzYW1sOklzc3VlciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI+aHR0cDovL2xvY2FsaG9zdDo4MDAwL21ldGFkYXRhPC9zYW1sOklzc3Vlcj48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiLz48ZHM6UmVmZXJlbmNlIFVSST0iI2lkLTQ1ZTcyMTkyNjU4NmNkZGUzNDQ2NmI0MzQ5NDg4YjA5MDZhNTU3OGIiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIi8+PGRzOkRpZ2VzdFZhbHVlPmVHeTMzcWpjZjYrT3R4YlVpVm5DUjFNdnlaaz08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+cDBEekU3Q0lTVTVNQjNvclpReGtUWHFsQXJRMjlFb0tXOUZuVWx5aUhYWGtmK2lXNGZ5SW9wYjcrTUk1VUk5TjVTQVdiVzV4U0R3NFJMMWNDaVNxdWJyU29pRi83MXdiM29naWlQOHhyYmJiajY3RHZMcUU3OVJDQXdySDlEU0FlZFlReVBOQ0tFQ0U0L3NvdnFEeUg5OTAwZEI4aTQ3VHdQRkhIclBlWE8wUGVoR0NWNTVEeTZJdC92Ull1VFRqU0tiVTczV014c1A5Mk9yVEdqamN1Smx1bFdSclBxNDk0aEpNMFJxV3gwN2RoWHJEbzlJY1JpK2RCOVhRN3UwbGJicEthQ0p6R2RiUG9JanJ1ZDhaWnh2djdiaDFtV1lEeGFodExvd2I1eGtDWlQrNFMybklrSWgwNEoxUURsZm1WSVdlRWljVW5odXpIcVBkU1RldklnPT08L2RzOlNpZ25hdHVyZVZhbHVlPjxkczpLZXlJbmZvPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSURCekNDQWUrZ0F3SUJBZ0lKQVByL01ybGM4RUdoTUEwR0NTcUdTSWIzRFFFQkJRVUFNQm94R0RBV0JnTlZCQU1NRDNkM2R5NWxlR0Z0Y0d4bExtTnZiVEFlRncweE5URXlNamd4T1RFNU5EVmFGdzB5TlRFeU1qVXhPVEU1TkRWYU1Cb3hHREFXQmdOVkJBTU1EM2QzZHk1bGVHRnRjR3hsTG1OdmJUQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQU5Eb1d6TG9zNExXeFRuOEd5dTJsRWJsNFdjZWxVYmdMTjV6WW00cm9uOEFocytydmNzdTJ6a2REL3M2amRHSkk4V3FKS2hZSzJ1NjF5Z25YZ0FacUM2Z2d0RlBuQnBpemNEempnTkQyZythdWNTb1VPREh0NjdmMGZRdUFtdXBOL3pwNU1aeXNKNklITEpuWUxOcGZKWWs5NmxSejlPRG5PMU1wcXRyOVBXeG0rcHo3bnpxNUYwdlJlcGtncGNSeHY2dWZRQmpsckZ5dGNjeUVWZFhydkZ0a2pYY25oVlZOU1I0a0h1T09NUzZEN3BlYlNKMW1yQ21zaGJENVNYMWpYUEJLRlBBam96WVg2UHhxTHhVeDFZNGZhRkVmNE1CQlZjSW55QjRvVVJOQjJzNTloRUVpMmpxOWl6TkU3RWJFSzZCWTVzRWhvQ1BsOW0zMnpFNmxqa0NBd0VBQWFOUU1FNHdIUVlEVlIwT0JCWUVGQjlaa2xDMU9yazJ6bDU2emcwOGVpN3NzLytpTUI4R0ExVWRJd1FZTUJhQUZCOVprbEMxT3JrMnpsNTZ6ZzA4ZWk3c3MvK2lNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ2dFQkFBVm9UU1E1cEFpcnc4T1I5RloxYlJTdVREaFk5dXh6bC9PTDdsVW1zdjJjTU5lQ0IzQlJacW0zbUZ0K2N3TjhHc0g2ZjN1dk5PTkloZ0ZwVEdONUxFY1hRejg5ekpFekIrcWFIcW1iRnBIUWwvc3gyQjhlek5nVC84ODJIMklIMDBkWEVTRWZ5LysxZ0hnMnB4akduaFJCTjZlbC9nU2FEaXlTSU1LYmlsRHJmZnV2eGlDZmJwUE4wTlJSaVBKaGQyYXk5S3VML1J4UVJsMWdsOWNIYVdpb3VXV2JhMWJTQmIyWlBodjJyUE1Vc0ZvOThudGtHQ09iRFg2WTFTcGtxbW9UYnJzYkdGc1RHMkRMeG52cjRHZE4xQlNyMFV1L0tWM2FkajQ3V2tYVlBlTVlRdGkvYlFteFFCOHRSRmhydzgwcWFrVExVenJlTzk2V3psQkJNdFk9PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiIE5hbWVRdWFsaWZpZXI9Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMC9tZXRhZGF0YSIgU1BOYW1lUXVhbGlmaWVyPSJodHRwOi8vbG9jYWxob3N0OjgwODAvaWRwcy8yMjg5Njg3OTIzNzIyODE3MDgvc2FtbC9tZXRhZGF0YSI+YWxpY2VAZXhhbXBsZS5jb208L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBBZGRyZXNzPSJbOjoxXTo1OTMzNCIgSW5SZXNwb25zZVRvPSJpZC1iMjJjOTBkYjg4YmYwMWQ4MmZmYjBhN2I2ZmUyNWFjOWZjYjJjNjc5IiBOb3RPbk9yQWZ0ZXI9IjIwMjMtMDktMjFUMTM6NTA6NTMuOTM4WiIgUmVjaXBpZW50PSJodHRwOi8vbG9jYWxob3N0OjgwODAvaWRwcy8yMjg5Njg3OTIzNzIyODE3MDgvc2FtbC9hY3MiLz48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAyMy0wOS0yMVQxMzo0OToxNC4yOThaIiBOb3RPbk9yQWZ0ZXI9IjIwMjMtMDktMjFUMTM6NTA6NDQuMjk4WiI+PHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDpBdWRpZW5jZT5odHRwOi8vbG9jYWxob3N0OjgwODAvaWRwcy8yMjg5Njg3OTIzNzIyODE3MDgvc2FtbC9tZXRhZGF0YTwvc2FtbDpBdWRpZW5jZT48L3NhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48L3NhbWw6Q29uZGl0aW9ucz48c2FtbDpBdXRoblN0YXRlbWVudCBBdXRobkluc3RhbnQ9IjIwMjMtMDktMjFUMTM6NDc6MzUuMTAzWiIgU2Vzc2lvbkluZGV4PSI0YzM5YjE5NTQyYzdjZTFjMzllOWMwNWJlMTdhNzJhNmQ4OGU1NWE3ZGFiYWRhZWQ3ODYxMDBiOWUzODBmYTA4Ij48c2FtbDpTdWJqZWN0TG9jYWxpdHkgQWRkcmVzcz0iWzo6MV06NTkzMzQiLz48c2FtbDpBdXRobkNvbnRleHQ+PHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sOkF1dGhuQ29udGV4dD48L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+PHNhbWw6QXR0cmlidXRlU3RhdGVtZW50PjxzYW1sOkF0dHJpYnV0ZSBGcmllbmRseU5hbWU9InVpZCIgTmFtZT0idXJuOm9pZDowLjkuMjM0Mi4xOTIwMDMwMC4xMDAuMS4xIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+YWxpY2U8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJlZHVQZXJzb25QcmluY2lwYWxOYW1lIiBOYW1lPSJ1cm46b2lkOjEuMy42LjEuNC4xLjU5MjMuMS4xLjEuNiIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTp0eXBlPSJ4czpzdHJpbmciPmFsaWNlQGV4YW1wbGUuY29tPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0ic24iIE5hbWU9InVybjpvaWQ6Mi41LjQuNCIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTp0eXBlPSJ4czpzdHJpbmciPlNtaXRoPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0iZ2l2ZW5OYW1lIiBOYW1lPSJ1cm46b2lkOjIuNS40LjQyIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+QWxpY2U8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJjbiIgTmFtZT0idXJuOm9pZDoyLjUuNC4zIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+QWxpY2UgU21pdGg8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJlZHVQZXJzb25BZmZpbGlhdGlvbiIgTmFtZT0idXJuOm9pZDoxLjMuNi4xLjQuMS41OTIzLjEuMS4xLjEiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj5BZG1pbmlzdHJhdG9yczwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48c2FtbDpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj5Vc2Vyczwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjwvc2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+PC9zYW1sOkFzc2VydGlvbj48L3NhbWxwOlJlc3BvbnNlPg==", + ), + requestID: "id-b22c90db88bf01d82ffb0a7b6fe25ac9fcb2c679", + }, + want: want{ + id: "alice", + attributes: map[string][]string{ + "urn:oid:0.9.2342.19200300.100.1.1": {"alice"}, + "urn:oid:1.3.6.1.4.1.5923.1.1.1.6": {"alice@example.com"}, + "urn:oid:2.5.4.4": {"Smith"}, + "urn:oid:2.5.4.42": {"Alice"}, + "urn:oid:2.5.4.3": {"Alice Smith"}, + "urn:oid:1.3.6.1.4.1.5923.1.1.1.1": {"Administrators", "Users"}, + }, + }, + }, + { + name: "post with user param (transient with wrong existing custom mapping)", + fields: fields{ + name: "saml", + key: []byte("-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAxHd087RoEm9ywVWZ/H+tDWxQsmVvhfRz4jAq/RfU+OWXNH4J\njMMSHdFs0Q+WP98nNXRyc7fgbMb8NdmlB2yD4qLYapN5SDaBc5dh/3EnyFt53oSs\njTlKnQUPAeJr2qh/NY046CfyUyQMM4JR5OiQFo4TssfWnqdcgamGt0AEnk2lvbMZ\nKQdAqNS9lDzYbjMGavEQPTZE35mFXFQXjaooZXq+TIa7hbaq7/idH7cHNbLcPLgj\nfPQA8q+DYvnvhXlmq0LPQZH3Oiixf+SF2vRwrBzT2mqGD2OiOkUmhuPwyqEiiBHt\nfxklRtRU6WfLa1Gcb1PsV0uoBGpV3KybIl/GlwIDAQABAoIBAEQjDduLgOCL6Gem\n0X3hpdnW6/HC/jed/Sa//9jBECq2LYeWAqff64ON40hqOHi0YvvGA/+gEOSI6mWe\nsv5tIxxRz+6+cLybsq+tG96kluCE4TJMHy/nY7orS/YiWbd+4odnEApr+D3fbZ/b\nnZ1fDsHTyn8hkYx6jLmnWsJpIHDp7zxD76y7k2Bbg6DZrCGiVxngiLJk23dvz79W\np03lHLM7XE92aFwXQmhfxHGxrbuoB/9eY4ai5IHp36H4fw0vL6NXdNQAo/bhe0p9\nAYB7y0ZumF8Hg0Z/BmMeEzLy6HrYB+VE8cO93pNjhSyH+p2yDB/BlUyTiRLQAoM0\nVTmOZXECgYEA7NGlzpKNhyQEJihVqt0MW0LhKIO/xbBn+XgYfX6GpqPa/ucnMx5/\nVezpl3gK8IU4wPUhAyXXAHJiqNBcEeyxrw0MXLujDVMJgYaLysCLJdvMVgoY08mS\nK5IQivpbozpf4+0y3mOnA+Sy1kbfxv2X8xiWLODRQW3f3q/xoklwOR8CgYEA1GEe\nfaibOFTQAYcIVj77KXtBfYZsX3EGAyfAN9O7cKHq5oaxVstwnF47WxpuVtoKZxCZ\nbNm9D5WvQ9b+Ztpioe42tzwE7Bff/Osj868GcDdRPK7nFlh9N2yVn/D514dOYVwR\n4MBr1KrJzgRWt4QqS4H+to1GzudDTSNlG7gnK4kCgYBUi6AbOHzoYzZL/RhgcJwp\ntJ23nhmH1Su5h2OO4e3mbhcP66w19sxU+8iFN+kH5zfUw26utgKk+TE5vXExQQRK\nT2k7bg2PAzcgk80ybD0BHhA8I0yrx4m0nmfjhe/TPVLgh10iwgbtP+eM0i6v1vc5\nZWyvxu9N4ZEL6lpkqr0y1wKBgG/NAIQd8jhhTW7Aav8cAJQBsqQl038avJOEpYe+\nCnpsgoAAf/K0/f8TDCQVceh+t+MxtdK7fO9rWOxZjWsPo8Si5mLnUaAHoX4/OpnZ\nlYYVWMqdOEFnK+O1Yb7k2GFBdV2DXlX2dc1qavntBsls5ecB89id3pyk2aUN8Pf6\npYQhAoGAMGtrHFely9wyaxI0RTCyfmJbWZHGVGkv6ELK8wneJjdjl82XOBUGCg5q\naRCrTZ3dPitKwrUa6ibJCIFCIziiriBmjDvTHzkMvoJEap2TVxYNDR6IfINVsQ57\nlOsiC4A2uGq4Lbfld+gjoplJ5GX6qXtTgZ6m7eo0y7U6zm2tkN0=\n-----END RSA PRIVATE KEY-----\n"), + certificate: []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"), + metadata: []byte("\n \n \n \n \n MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=\n \n \n \n \n \n \n MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=\n \n \n \n \n \n \n \n urn:oasis:names:tc:SAML:2.0:nameid-format:transient\n \n \n \n"), + options: []ProviderOpts{ + WithLinkingAllowed(), + WithCreationAllowed(), + WithAutoCreation(), + WithAutoUpdate(), + WithBinding(saml.HTTPRedirectBinding), + WithSignedRequest(), + WithCustomRequestTracker(&requesttracker.RequestTracker{}), + WithTransientMappingAttributeName("customAttribute"), + }, + rootURL: "http://localhost:8080/idps/228968792372281708/", + }, + args: args{ + request: httpPostFormRequest(t, + "http://localhost:8080/idps/228968792372281708/saml/acs", + "232881438356144492", + "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgSUQ9ImlkLTA4ZTA3MTFhYzYwZjE2Mzc2MTdhYjZhNDZkZDk0ZTZkMWQ3MDgzMWQiIEluUmVzcG9uc2VUbz0iaWQtYjIyYzkwZGI4OGJmMDFkODJmZmIwYTdiNmZlMjVhYzlmY2IyYzY3OSIgVmVyc2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMjMtMDktMjFUMTM6NDk6MjMuOTM4WiIgRGVzdGluYXRpb249Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9pZHBzLzIyODk2ODc5MjM3MjI4MTcwOC9zYW1sL2FjcyI+PHNhbWw6SXNzdWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5odHRwOi8vbG9jYWxob3N0OjgwMDAvbWV0YWRhdGE8L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNyc2Etc2hhMSIvPjxkczpSZWZlcmVuY2UgVVJJPSIjaWQtMDhlMDcxMWFjNjBmMTYzNzYxN2FiNmE0NmRkOTRlNmQxZDcwODMxZCI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiLz48ZHM6RGlnZXN0VmFsdWU+OWF2ektOOWhpazE4ZkFRdnZNZzJBZFoyYm9VPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5VMkFJOFNzMng5TDAwV3RkaVFlbldCSVFCcGJLNnU4ZU9XVGE2WExKR0lWMWg4d3VOdURqM2luVGpMVUhITkNUSHhTdTFXSE9OSW1CL3QwWlE1Z3EvYXlkcVVqaEVkNG50LysyaXBKelZjZHVHUG5nYjlMWjJ5R1Rsd1JiQkcyMzd4eCtlRWhUMUcrTUFGa3BtbnUrei9RN09vUjdQWHVZOWt6NTRCb0tVM1htK1UyWm9GVy9pVjhId01kYTJMajVLT0pjcnppSWVtNHF0dHlIZXBqcjI3NUhPM2hybzgvVW0xMm8wdk10OUhwaHJua0RNVzgzM3Q5c0k2aW5GRndiOUJkdm5ORkVxYkhCZ2RsemR5T0NqaWdreVNlTzZQNzhQQlhUTWlhM3RVaGxEL0dlZ2hmbTJ4NVI1Q2QrOXJ5RktjYlBKLzlUaFhwbTlIYUJ4R1RZNEE9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJREJ6Q0NBZStnQXdJQkFnSUpBUHIvTXJsYzhFR2hNQTBHQ1NxR1NJYjNEUUVCQlFVQU1Cb3hHREFXQmdOVkJBTU1EM2QzZHk1bGVHRnRjR3hsTG1OdmJUQWVGdzB4TlRFeU1qZ3hPVEU1TkRWYUZ3MHlOVEV5TWpVeE9URTVORFZhTUJveEdEQVdCZ05WQkFNTUQzZDNkeTVsZUdGdGNHeGxMbU52YlRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTkRvV3pMb3M0TFd4VG44R3l1MmxFYmw0V2NlbFViZ0xONXpZbTRyb244QWhzK3J2Y3N1MnprZEQvczZqZEdKSThXcUpLaFlLMnU2MXlnblhnQVpxQzZnZ3RGUG5CcGl6Y0R6amdORDJnK2F1Y1NvVU9ESHQ2N2YwZlF1QW11cE4venA1TVp5c0o2SUhMSm5ZTE5wZkpZazk2bFJ6OU9Ebk8xTXBxdHI5UFd4bStwejduenE1RjB2UmVwa2dwY1J4djZ1ZlFCamxyRnl0Y2N5RVZkWHJ2RnRralhjbmhWVk5TUjRrSHVPT01TNkQ3cGViU0oxbXJDbXNoYkQ1U1gxalhQQktGUEFqb3pZWDZQeHFMeFV4MVk0ZmFGRWY0TUJCVmNJbnlCNG9VUk5CMnM1OWhFRWkyanE5aXpORTdFYkVLNkJZNXNFaG9DUGw5bTMyekU2bGprQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZCOVprbEMxT3JrMnpsNTZ6ZzA4ZWk3c3MvK2lNQjhHQTFVZEl3UVlNQmFBRkI5WmtsQzFPcmsyemw1NnpnMDhlaTdzcy8raU1Bd0dBMVVkRXdRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFRkJRQURnZ0VCQUFWb1RTUTVwQWlydzhPUjlGWjFiUlN1VERoWTl1eHpsL09MN2xVbXN2MmNNTmVDQjNCUlpxbTNtRnQrY3dOOEdzSDZmM3V2Tk9OSWhnRnBUR041TEVjWFF6ODl6SkV6QitxYUhxbWJGcEhRbC9zeDJCOGV6TmdULzg4MkgySUgwMGRYRVNFZnkvKzFnSGcycHhqR25oUkJONmVsL2dTYURpeVNJTUtiaWxEcmZmdXZ4aUNmYnBQTjBOUlJpUEpoZDJheTlLdUwvUnhRUmwxZ2w5Y0hhV2lvdVdXYmExYlNCYjJaUGh2MnJQTVVzRm85OG50a0dDT2JEWDZZMVNwa3Ftb1RicnNiR0ZzVEcyREx4bnZyNEdkTjFCU3IwVXUvS1YzYWRqNDdXa1hWUGVNWVF0aS9iUW14UUI4dFJGaHJ3ODBxYWtUTFV6cmVPOTZXemxCQk10WT08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48L2RzOlNpZ25hdHVyZT48c2FtbHA6U3RhdHVzPjxzYW1scDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWxwOlN0YXR1cz48c2FtbDpBc3NlcnRpb24geG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgSUQ9ImlkLTQ1ZTcyMTkyNjU4NmNkZGUzNDQ2NmI0MzQ5NDg4YjA5MDZhNTU3OGIiIElzc3VlSW5zdGFudD0iMjAyMy0wOS0yMVQxMzo0OToyMy45NDFaIiBWZXJzaW9uPSIyLjAiPjxzYW1sOklzc3VlciBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI+aHR0cDovL2xvY2FsaG9zdDo4MDAwL21ldGFkYXRhPC9zYW1sOklzc3Vlcj48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiLz48ZHM6UmVmZXJlbmNlIFVSST0iI2lkLTQ1ZTcyMTkyNjU4NmNkZGUzNDQ2NmI0MzQ5NDg4YjA5MDZhNTU3OGIiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIi8+PGRzOkRpZ2VzdFZhbHVlPmVHeTMzcWpjZjYrT3R4YlVpVm5DUjFNdnlaaz08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+cDBEekU3Q0lTVTVNQjNvclpReGtUWHFsQXJRMjlFb0tXOUZuVWx5aUhYWGtmK2lXNGZ5SW9wYjcrTUk1VUk5TjVTQVdiVzV4U0R3NFJMMWNDaVNxdWJyU29pRi83MXdiM29naWlQOHhyYmJiajY3RHZMcUU3OVJDQXdySDlEU0FlZFlReVBOQ0tFQ0U0L3NvdnFEeUg5OTAwZEI4aTQ3VHdQRkhIclBlWE8wUGVoR0NWNTVEeTZJdC92Ull1VFRqU0tiVTczV014c1A5Mk9yVEdqamN1Smx1bFdSclBxNDk0aEpNMFJxV3gwN2RoWHJEbzlJY1JpK2RCOVhRN3UwbGJicEthQ0p6R2RiUG9JanJ1ZDhaWnh2djdiaDFtV1lEeGFodExvd2I1eGtDWlQrNFMybklrSWgwNEoxUURsZm1WSVdlRWljVW5odXpIcVBkU1RldklnPT08L2RzOlNpZ25hdHVyZVZhbHVlPjxkczpLZXlJbmZvPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSURCekNDQWUrZ0F3SUJBZ0lKQVByL01ybGM4RUdoTUEwR0NTcUdTSWIzRFFFQkJRVUFNQm94R0RBV0JnTlZCQU1NRDNkM2R5NWxlR0Z0Y0d4bExtTnZiVEFlRncweE5URXlNamd4T1RFNU5EVmFGdzB5TlRFeU1qVXhPVEU1TkRWYU1Cb3hHREFXQmdOVkJBTU1EM2QzZHk1bGVHRnRjR3hsTG1OdmJUQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQU5Eb1d6TG9zNExXeFRuOEd5dTJsRWJsNFdjZWxVYmdMTjV6WW00cm9uOEFocytydmNzdTJ6a2REL3M2amRHSkk4V3FKS2hZSzJ1NjF5Z25YZ0FacUM2Z2d0RlBuQnBpemNEempnTkQyZythdWNTb1VPREh0NjdmMGZRdUFtdXBOL3pwNU1aeXNKNklITEpuWUxOcGZKWWs5NmxSejlPRG5PMU1wcXRyOVBXeG0rcHo3bnpxNUYwdlJlcGtncGNSeHY2dWZRQmpsckZ5dGNjeUVWZFhydkZ0a2pYY25oVlZOU1I0a0h1T09NUzZEN3BlYlNKMW1yQ21zaGJENVNYMWpYUEJLRlBBam96WVg2UHhxTHhVeDFZNGZhRkVmNE1CQlZjSW55QjRvVVJOQjJzNTloRUVpMmpxOWl6TkU3RWJFSzZCWTVzRWhvQ1BsOW0zMnpFNmxqa0NBd0VBQWFOUU1FNHdIUVlEVlIwT0JCWUVGQjlaa2xDMU9yazJ6bDU2emcwOGVpN3NzLytpTUI4R0ExVWRJd1FZTUJhQUZCOVprbEMxT3JrMnpsNTZ6ZzA4ZWk3c3MvK2lNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ2dFQkFBVm9UU1E1cEFpcnc4T1I5RloxYlJTdVREaFk5dXh6bC9PTDdsVW1zdjJjTU5lQ0IzQlJacW0zbUZ0K2N3TjhHc0g2ZjN1dk5PTkloZ0ZwVEdONUxFY1hRejg5ekpFekIrcWFIcW1iRnBIUWwvc3gyQjhlek5nVC84ODJIMklIMDBkWEVTRWZ5LysxZ0hnMnB4akduaFJCTjZlbC9nU2FEaXlTSU1LYmlsRHJmZnV2eGlDZmJwUE4wTlJSaVBKaGQyYXk5S3VML1J4UVJsMWdsOWNIYVdpb3VXV2JhMWJTQmIyWlBodjJyUE1Vc0ZvOThudGtHQ09iRFg2WTFTcGtxbW9UYnJzYkdGc1RHMkRMeG52cjRHZE4xQlNyMFV1L0tWM2FkajQ3V2tYVlBlTVlRdGkvYlFteFFCOHRSRmhydzgwcWFrVExVenJlTzk2V3psQkJNdFk9PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWw6U3ViamVjdD48c2FtbDpOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiIE5hbWVRdWFsaWZpZXI9Imh0dHA6Ly9sb2NhbGhvc3Q6ODAwMC9tZXRhZGF0YSIgU1BOYW1lUXVhbGlmaWVyPSJodHRwOi8vbG9jYWxob3N0OjgwODAvaWRwcy8yMjg5Njg3OTIzNzIyODE3MDgvc2FtbC9tZXRhZGF0YSI+YWxpY2VAZXhhbXBsZS5jb208L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBBZGRyZXNzPSJbOjoxXTo1OTMzNCIgSW5SZXNwb25zZVRvPSJpZC1iMjJjOTBkYjg4YmYwMWQ4MmZmYjBhN2I2ZmUyNWFjOWZjYjJjNjc5IiBOb3RPbk9yQWZ0ZXI9IjIwMjMtMDktMjFUMTM6NTA6NTMuOTM4WiIgUmVjaXBpZW50PSJodHRwOi8vbG9jYWxob3N0OjgwODAvaWRwcy8yMjg5Njg3OTIzNzIyODE3MDgvc2FtbC9hY3MiLz48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAyMy0wOS0yMVQxMzo0OToxNC4yOThaIiBOb3RPbk9yQWZ0ZXI9IjIwMjMtMDktMjFUMTM6NTA6NDQuMjk4WiI+PHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDpBdWRpZW5jZT5odHRwOi8vbG9jYWxob3N0OjgwODAvaWRwcy8yMjg5Njg3OTIzNzIyODE3MDgvc2FtbC9tZXRhZGF0YTwvc2FtbDpBdWRpZW5jZT48L3NhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48L3NhbWw6Q29uZGl0aW9ucz48c2FtbDpBdXRoblN0YXRlbWVudCBBdXRobkluc3RhbnQ9IjIwMjMtMDktMjFUMTM6NDc6MzUuMTAzWiIgU2Vzc2lvbkluZGV4PSI0YzM5YjE5NTQyYzdjZTFjMzllOWMwNWJlMTdhNzJhNmQ4OGU1NWE3ZGFiYWRhZWQ3ODYxMDBiOWUzODBmYTA4Ij48c2FtbDpTdWJqZWN0TG9jYWxpdHkgQWRkcmVzcz0iWzo6MV06NTkzMzQiLz48c2FtbDpBdXRobkNvbnRleHQ+PHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sOkF1dGhuQ29udGV4dD48L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+PHNhbWw6QXR0cmlidXRlU3RhdGVtZW50PjxzYW1sOkF0dHJpYnV0ZSBGcmllbmRseU5hbWU9InVpZCIgTmFtZT0idXJuOm9pZDowLjkuMjM0Mi4xOTIwMDMwMC4xMDAuMS4xIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+YWxpY2U8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJlZHVQZXJzb25QcmluY2lwYWxOYW1lIiBOYW1lPSJ1cm46b2lkOjEuMy42LjEuNC4xLjU5MjMuMS4xLjEuNiIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTp0eXBlPSJ4czpzdHJpbmciPmFsaWNlQGV4YW1wbGUuY29tPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0ic24iIE5hbWU9InVybjpvaWQ6Mi41LjQuNCIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTp0eXBlPSJ4czpzdHJpbmciPlNtaXRoPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PHNhbWw6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0iZ2l2ZW5OYW1lIiBOYW1lPSJ1cm46b2lkOjIuNS40LjQyIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+QWxpY2U8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJjbiIgTmFtZT0idXJuOm9pZDoyLjUuNC4zIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+QWxpY2UgU21pdGg8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJlZHVQZXJzb25BZmZpbGlhdGlvbiIgTmFtZT0idXJuOm9pZDoxLjMuNi4xLjQuMS41OTIzLjEuMS4xLjEiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj5BZG1pbmlzdHJhdG9yczwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48c2FtbDpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj5Vc2Vyczwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjwvc2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+PC9zYW1sOkFzc2VydGlvbj48L3NhbWxwOlJlc3BvbnNlPg==", + ), + requestID: "id-b22c90db88bf01d82ffb0a7b6fe25ac9fcb2c679", + }, + want: want{ + err: zerrors.ThrowInvalidArgument(nil, "SAML-swwg2", "Errors.Intent.MissingSingleMappingAttribute"), + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -174,15 +244,9 @@ func TestSession_FetchUser(t *testing.T) { provider, err := New(tt.fields.name, tt.fields.rootURL, tt.fields.metadata, tt.fields.certificate, tt.fields.key, tt.fields.options...) require.NoError(t, err) - sp, err := provider.GetSP() + session, err := NewSession(provider, tt.args.requestID, tt.args.request) require.NoError(t, err) - session := &Session{ - ServiceProvider: sp, - state: tt.args.intentID, - RequestID: tt.args.requestID, - Request: tt.args.request, - } // set to time of response for validation saml.TimeNow = func() time.Time { time, _ := time.Parse(time.RFC3339, "2023-09-21T13:47:40.0Z") diff --git a/internal/integration/client.go b/internal/integration/client.go index 21410bec9..72f50e998 100644 --- a/internal/integration/client.go +++ b/internal/integration/client.go @@ -380,12 +380,13 @@ func (s *Tester) AddSAMLProvider(t *testing.T, ctx context.Context) string { return id } -func (s *Tester) AddSAMLRedirectProvider(t *testing.T, ctx context.Context) string { +func (s *Tester) AddSAMLRedirectProvider(t *testing.T, ctx context.Context, transientMappingAttributeName string) string { ctx = authz.WithInstance(ctx, s.Instance) id, _, err := s.Server.Commands.AddInstanceSAMLProvider(ctx, command.SAMLProvider{ - Name: "saml-idp-redirect", - Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", - Metadata: []byte("\n \n \n \n \n MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=\n \n \n \n \n \n \n MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=\n \n \n \n \n \n \n \n urn:oasis:names:tc:SAML:2.0:nameid-format:transient\n \n \n"), + Name: "saml-idp-redirect", + Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", + Metadata: []byte("\n \n \n \n \n MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=\n \n \n \n \n \n \n MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=\n \n \n \n \n \n \n \n urn:oasis:names:tc:SAML:2.0:nameid-format:transient\n \n \n"), + TransientMappingAttributeName: transientMappingAttributeName, IDPOptions: idp.Options{ IsLinkingAllowed: true, IsCreationAllowed: true, diff --git a/internal/query/idp_template.go b/internal/query/idp_template.go index 361389f99..2b835f0e6 100644 --- a/internal/query/idp_template.go +++ b/internal/query/idp_template.go @@ -155,12 +155,14 @@ type AppleIDPTemplate struct { } type SAMLIDPTemplate struct { - IDPID string - Metadata []byte - Key *crypto.CryptoValue - Certificate []byte - Binding string - WithSignedRequest bool + IDPID string + Metadata []byte + Key *crypto.CryptoValue + Certificate []byte + Binding string + WithSignedRequest bool + NameIDFormat sql.Null[domain.SAMLNameIDFormat] + TransientMappingAttributeName string } var ( @@ -700,6 +702,14 @@ var ( name: projection.SAMLWithSignedRequestCol, table: samlIdpTemplateTable, } + SAMLNameIDFormatCol = Column{ + name: projection.SAMLNameIDFormatCol, + table: samlIdpTemplateTable, + } + SAMLTransientMappingAttributeNameCol = Column{ + name: projection.SAMLTransientMappingAttributeName, + table: samlIdpTemplateTable, + } ) // IDPTemplateByID searches for the requested id @@ -883,6 +893,8 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se SAMLCertificateCol.identifier(), SAMLBindingCol.identifier(), SAMLWithSignedRequestCol.identifier(), + SAMLNameIDFormatCol.identifier(), + SAMLTransientMappingAttributeNameCol.identifier(), // ldap LDAPIDCol.identifier(), LDAPServersCol.identifier(), @@ -997,6 +1009,8 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se var samlCertificate []byte samlBinding := sql.NullString{} samlWithSignedRequest := sql.NullBool{} + samlNameIDFormat := sql.Null[domain.SAMLNameIDFormat]{} + samlTransientMappingAttributeName := sql.NullString{} ldapID := sql.NullString{} ldapServers := database.TextArray[string]{} @@ -1109,6 +1123,8 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se &samlCertificate, &samlBinding, &samlWithSignedRequest, + &samlNameIDFormat, + &samlTransientMappingAttributeName, // ldap &ldapID, &ldapServers, @@ -1237,12 +1253,14 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se } if samlID.Valid { idpTemplate.SAMLIDPTemplate = &SAMLIDPTemplate{ - IDPID: samlID.String, - Metadata: samlMetadata, - Key: samlKey, - Certificate: samlCertificate, - Binding: samlBinding.String, - WithSignedRequest: samlWithSignedRequest.Bool, + IDPID: samlID.String, + Metadata: samlMetadata, + Key: samlKey, + Certificate: samlCertificate, + Binding: samlBinding.String, + WithSignedRequest: samlWithSignedRequest.Bool, + NameIDFormat: samlNameIDFormat, + TransientMappingAttributeName: samlTransientMappingAttributeName.String, } } if ldapID.Valid { @@ -1370,6 +1388,8 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec SAMLCertificateCol.identifier(), SAMLBindingCol.identifier(), SAMLWithSignedRequestCol.identifier(), + SAMLNameIDFormatCol.identifier(), + SAMLTransientMappingAttributeNameCol.identifier(), // ldap LDAPIDCol.identifier(), LDAPServersCol.identifier(), @@ -1489,6 +1509,8 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec var samlCertificate []byte samlBinding := sql.NullString{} samlWithSignedRequest := sql.NullBool{} + samlNameIDFormat := sql.Null[domain.SAMLNameIDFormat]{} + samlTransientMappingAttributeName := sql.NullString{} ldapID := sql.NullString{} ldapServers := database.TextArray[string]{} @@ -1601,6 +1623,8 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec &samlCertificate, &samlBinding, &samlWithSignedRequest, + &samlNameIDFormat, + &samlTransientMappingAttributeName, // ldap &ldapID, &ldapServers, @@ -1728,12 +1752,14 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec } if samlID.Valid { idpTemplate.SAMLIDPTemplate = &SAMLIDPTemplate{ - IDPID: samlID.String, - Metadata: samlMetadata, - Key: samlKey, - Certificate: samlCertificate, - Binding: samlBinding.String, - WithSignedRequest: samlWithSignedRequest.Bool, + IDPID: samlID.String, + Metadata: samlMetadata, + Key: samlKey, + Certificate: samlCertificate, + Binding: samlBinding.String, + WithSignedRequest: samlWithSignedRequest.Bool, + NameIDFormat: samlNameIDFormat, + TransientMappingAttributeName: samlTransientMappingAttributeName.String, } } if ldapID.Valid { diff --git a/internal/query/idp_template_test.go b/internal/query/idp_template_test.go index 72e5d9f8c..c5bee3a00 100644 --- a/internal/query/idp_template_test.go +++ b/internal/query/idp_template_test.go @@ -95,6 +95,8 @@ var ( ` projections.idp_templates6_saml.certificate,` + ` projections.idp_templates6_saml.binding,` + ` projections.idp_templates6_saml.with_signed_request,` + + ` projections.idp_templates6_saml.name_id_format,` + + ` projections.idp_templates6_saml.transient_mapping_attribute_name,` + // ldap ` projections.idp_templates6_ldap2.idp_id,` + ` projections.idp_templates6_ldap2.servers,` + @@ -220,6 +222,8 @@ var ( "certificate", "binding", "with_signed_request", + "name_id_format", + "transient_mapping_attribute_name", // ldap config "idp_id", "servers", @@ -331,6 +335,8 @@ var ( ` projections.idp_templates6_saml.certificate,` + ` projections.idp_templates6_saml.binding,` + ` projections.idp_templates6_saml.with_signed_request,` + + ` projections.idp_templates6_saml.name_id_format,` + + ` projections.idp_templates6_saml.transient_mapping_attribute_name,` + // ldap ` projections.idp_templates6_ldap2.idp_id,` + ` projections.idp_templates6_ldap2.servers,` + @@ -457,6 +463,8 @@ var ( "certificate", "binding", "with_signed_request", + "name_id_format", + "transient_mapping_attribute_name", // ldap config "idp_id", "servers", @@ -608,6 +616,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -756,6 +766,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -902,6 +914,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -1047,6 +1061,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -1191,6 +1207,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -1335,6 +1353,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -1480,6 +1500,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -1624,6 +1646,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, "binding", false, + domain.SAMLNameIDFormatTransient, + "customAttribute", // ldap config nil, nil, @@ -1674,12 +1698,14 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { IsAutoUpdate: true, AutoLinking: domain.AutoLinkingOptionUsername, SAMLIDPTemplate: &SAMLIDPTemplate{ - IDPID: "idp-id", - Metadata: []byte("metadata"), - Key: nil, - Certificate: nil, - Binding: "binding", - WithSignedRequest: false, + IDPID: "idp-id", + Metadata: []byte("metadata"), + Key: nil, + Certificate: nil, + Binding: "binding", + WithSignedRequest: false, + NameIDFormat: sql.Null[domain.SAMLNameIDFormat]{V: domain.SAMLNameIDFormatTransient, Valid: true}, + TransientMappingAttributeName: "customAttribute", }, }, }, @@ -1770,6 +1796,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config "idp-id", database.TextArray[string]{"server"}, @@ -1934,6 +1962,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -2080,6 +2110,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -2254,6 +2286,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config "idp-id", database.TextArray[string]{"server"}, @@ -2427,6 +2461,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -2574,6 +2610,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config "idp-id-ldap", database.TextArray[string]{"server"}, @@ -2686,6 +2724,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, "binding", false, + domain.SAMLNameIDFormatTransient, + "customAttribute", // ldap config nil, nil, @@ -2798,6 +2838,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -2910,6 +2952,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -3022,6 +3066,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -3134,6 +3180,8 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { nil, nil, nil, + nil, + nil, // ldap config nil, nil, @@ -3232,12 +3280,14 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) { IsAutoUpdate: true, AutoLinking: domain.AutoLinkingOptionUsername, SAMLIDPTemplate: &SAMLIDPTemplate{ - IDPID: "idp-id-saml", - Metadata: []byte("metadata"), - Key: nil, - Certificate: nil, - Binding: "binding", - WithSignedRequest: false, + IDPID: "idp-id-saml", + Metadata: []byte("metadata"), + Key: nil, + Certificate: nil, + Binding: "binding", + WithSignedRequest: false, + NameIDFormat: sql.Null[domain.SAMLNameIDFormat]{V: domain.SAMLNameIDFormatTransient, Valid: true}, + TransientMappingAttributeName: "customAttribute", }, }, { diff --git a/internal/query/projection/idp_template.go b/internal/query/projection/idp_template.go index 1ecd9d654..a9d38cfeb 100644 --- a/internal/query/projection/idp_template.go +++ b/internal/query/projection/idp_template.go @@ -161,13 +161,15 @@ const ( ApplePrivateKeyCol = "private_key" AppleScopesCol = "scopes" - SAMLIDCol = "idp_id" - SAMLInstanceIDCol = "instance_id" - SAMLMetadataCol = "metadata" - SAMLKeyCol = "key" - SAMLCertificateCol = "certificate" - SAMLBindingCol = "binding" - SAMLWithSignedRequestCol = "with_signed_request" + SAMLIDCol = "idp_id" + SAMLInstanceIDCol = "instance_id" + SAMLMetadataCol = "metadata" + SAMLKeyCol = "key" + SAMLCertificateCol = "certificate" + SAMLBindingCol = "binding" + SAMLWithSignedRequestCol = "with_signed_request" + SAMLNameIDFormatCol = "name_id_format" + SAMLTransientMappingAttributeName = "transient_mapping_attribute_name" ) type idpTemplateProjection struct{} @@ -367,6 +369,8 @@ 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(SAMLNameIDFormatCol, handler.ColumnTypeEnum, handler.Nullable()), + handler.NewColumn(SAMLTransientMappingAttributeName, handler.ColumnTypeText, handler.Nullable()), }, handler.NewPrimaryKey(SAMLInstanceIDCol, SAMLIDCol), IDPTemplateSAMLSuffix, @@ -1967,6 +1971,20 @@ func (p *idpTemplateProjection) reduceSAMLIDPAdded(event eventstore.Event) (*han return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-9s02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.SAMLIDPAddedEventType, instance.SAMLIDPAddedEventType}) } + columns := []handler.Column{ + handler.NewCol(SAMLIDCol, idpEvent.ID), + handler.NewCol(SAMLInstanceIDCol, idpEvent.Aggregate().InstanceID), + handler.NewCol(SAMLMetadataCol, idpEvent.Metadata), + handler.NewCol(SAMLKeyCol, idpEvent.Key), + handler.NewCol(SAMLCertificateCol, idpEvent.Certificate), + handler.NewCol(SAMLBindingCol, idpEvent.Binding), + handler.NewCol(SAMLWithSignedRequestCol, idpEvent.WithSignedRequest), + handler.NewCol(SAMLTransientMappingAttributeName, idpEvent.TransientMappingAttributeName), + } + if idpEvent.NameIDFormat != nil { + columns = append(columns, handler.NewCol(SAMLNameIDFormatCol, *idpEvent.NameIDFormat)) + } + return handler.NewMultiStatement( &idpEvent, handler.AddCreateStatement( @@ -1989,15 +2007,7 @@ func (p *idpTemplateProjection) reduceSAMLIDPAdded(event eventstore.Event) (*han }, ), handler.AddCreateStatement( - []handler.Column{ - handler.NewCol(SAMLIDCol, idpEvent.ID), - handler.NewCol(SAMLInstanceIDCol, idpEvent.Aggregate().InstanceID), - handler.NewCol(SAMLMetadataCol, idpEvent.Metadata), - handler.NewCol(SAMLKeyCol, idpEvent.Key), - handler.NewCol(SAMLCertificateCol, idpEvent.Certificate), - handler.NewCol(SAMLBindingCol, idpEvent.Binding), - handler.NewCol(SAMLWithSignedRequestCol, idpEvent.WithSignedRequest), - }, + columns, handler.WithTableSuffix(IDPTemplateSAMLSuffix), ), ), nil @@ -2490,5 +2500,11 @@ func reduceSAMLIDPChangedColumns(idpEvent idp.SAMLIDPChangedEvent) []handler.Col if idpEvent.WithSignedRequest != nil { SAMLCols = append(SAMLCols, handler.NewCol(SAMLWithSignedRequestCol, *idpEvent.WithSignedRequest)) } + if idpEvent.NameIDFormat != nil { + SAMLCols = append(SAMLCols, handler.NewCol(SAMLNameIDFormatCol, *idpEvent.NameIDFormat)) + } + if idpEvent.TransientMappingAttributeName != nil { + SAMLCols = append(SAMLCols, handler.NewCol(SAMLTransientMappingAttributeName, *idpEvent.TransientMappingAttributeName)) + } return SAMLCols } diff --git a/internal/query/projection/idp_template_test.go b/internal/query/projection/idp_template_test.go index d463054af..6f096a94c 100644 --- a/internal/query/projection/idp_template_test.go +++ b/internal/query/projection/idp_template_test.go @@ -2774,6 +2774,8 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) { }, "certificate": `+stringToJSONByte("certificate")+`, "binding": "binding", + "nameIDFormat": 3, + "transientMappingAttributeName": "customAttribute", "withSignedRequest": true, "isCreationAllowed": true, "isLinkingAllowed": true, @@ -2810,7 +2812,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) VALUES ($1, $2, $3, $4, $5, $6, $7)", + expectedStmt: "INSERT INTO projections.idp_templates6_saml (idp_id, instance_id, metadata, key, certificate, binding, with_signed_request, transient_mapping_attribute_name, name_id_format) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -2819,6 +2821,8 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) { anyArg{}, "binding", true, + "customAttribute", + domain.SAMLNameIDFormatTransient, }, }, }, @@ -2842,6 +2846,8 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) { }, "certificate": `+stringToJSONByte("certificate")+`, "binding": "binding", + "nameIDFormat": 3, + "transientMappingAttributeName": "customAttribute", "withSignedRequest": true, "isCreationAllowed": true, "isLinkingAllowed": true, @@ -2878,7 +2884,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) VALUES ($1, $2, $3, $4, $5, $6, $7)", + expectedStmt: "INSERT INTO projections.idp_templates6_saml (idp_id, instance_id, metadata, key, certificate, binding, with_signed_request, transient_mapping_attribute_name, name_id_format) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", expectedArgs: []interface{}{ "idp-id", "instance-id", @@ -2887,6 +2893,8 @@ func TestIDPTemplateProjection_reducesSAML(t *testing.T) { anyArg{}, "binding", true, + "customAttribute", + domain.SAMLNameIDFormatTransient, }, }, }, diff --git a/internal/repository/idp/saml.go b/internal/repository/idp/saml.go index 37534da20..da6a52b1b 100644 --- a/internal/repository/idp/saml.go +++ b/internal/repository/idp/saml.go @@ -2,6 +2,7 @@ package idp import ( "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/zerrors" ) @@ -9,13 +10,15 @@ import ( type SAMLIDPAddedEvent struct { eventstore.BaseEvent `json:"-"` - ID string `json:"id"` - Name string `json:"name,omitempty"` - Metadata []byte `json:"metadata,omitempty"` - Key *crypto.CryptoValue `json:"key,omitempty"` - Certificate []byte `json:"certificate,omitempty"` - Binding string `json:"binding,omitempty"` - WithSignedRequest bool `json:"withSignedRequest,omitempty"` + ID string `json:"id"` + Name string `json:"name,omitempty"` + Metadata []byte `json:"metadata,omitempty"` + Key *crypto.CryptoValue `json:"key,omitempty"` + Certificate []byte `json:"certificate,omitempty"` + Binding string `json:"binding,omitempty"` + WithSignedRequest bool `json:"withSignedRequest,omitempty"` + NameIDFormat *domain.SAMLNameIDFormat `json:"nameIDFormat,omitempty"` + TransientMappingAttributeName string `json:"transientMappingAttributeName,omitempty"` Options } @@ -28,18 +31,22 @@ func NewSAMLIDPAddedEvent( certificate []byte, binding string, withSignedRequest bool, + nameIDFormat *domain.SAMLNameIDFormat, + transientMappingAttributeName string, options Options, ) *SAMLIDPAddedEvent { return &SAMLIDPAddedEvent{ - BaseEvent: *base, - ID: id, - Name: name, - Metadata: metadata, - Key: key, - Certificate: certificate, - Binding: binding, - WithSignedRequest: withSignedRequest, - Options: options, + BaseEvent: *base, + ID: id, + Name: name, + Metadata: metadata, + Key: key, + Certificate: certificate, + Binding: binding, + WithSignedRequest: withSignedRequest, + NameIDFormat: nameIDFormat, + TransientMappingAttributeName: transientMappingAttributeName, + Options: options, } } @@ -67,13 +74,15 @@ func SAMLIDPAddedEventMapper(event eventstore.Event) (eventstore.Event, error) { type SAMLIDPChangedEvent struct { eventstore.BaseEvent `json:"-"` - ID string `json:"id"` - Name *string `json:"name,omitempty"` - Metadata []byte `json:"metadata,omitempty"` - Key *crypto.CryptoValue `json:"key,omitempty"` - Certificate []byte `json:"certificate,omitempty"` - Binding *string `json:"binding,omitempty"` - WithSignedRequest *bool `json:"withSignedRequest,omitempty"` + ID string `json:"id"` + Name *string `json:"name,omitempty"` + Metadata []byte `json:"metadata,omitempty"` + Key *crypto.CryptoValue `json:"key,omitempty"` + Certificate []byte `json:"certificate,omitempty"` + Binding *string `json:"binding,omitempty"` + WithSignedRequest *bool `json:"withSignedRequest,omitempty"` + NameIDFormat *domain.SAMLNameIDFormat `json:"nameIDFormat,omitempty"` + TransientMappingAttributeName *string `json:"transientMappingAttributeName,omitempty"` OptionChanges } @@ -133,6 +142,18 @@ func ChangeSAMLWithSignedRequest(withSignedRequest bool) func(*SAMLIDPChangedEve } } +func ChangeSAMLNameIDFormat(nameIDFormat *domain.SAMLNameIDFormat) func(*SAMLIDPChangedEvent) { + return func(e *SAMLIDPChangedEvent) { + e.NameIDFormat = nameIDFormat + } +} + +func ChangeSAMLTransientMappingAttributeName(name string) func(*SAMLIDPChangedEvent) { + return func(e *SAMLIDPChangedEvent) { + e.TransientMappingAttributeName = &name + } +} + func ChangeSAMLOptions(options OptionChanges) func(*SAMLIDPChangedEvent) { return func(e *SAMLIDPChangedEvent) { e.OptionChanges = options diff --git a/internal/repository/instance/idp.go b/internal/repository/instance/idp.go index 3bda1542d..d2f90ab4e 100644 --- a/internal/repository/instance/idp.go +++ b/internal/repository/instance/idp.go @@ -5,6 +5,7 @@ import ( "time" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/idp" ) @@ -1016,6 +1017,8 @@ func NewSAMLIDPAddedEvent( certificate []byte, binding string, withSignedRequest bool, + nameIDFormat *domain.SAMLNameIDFormat, + transientMappingAttributeName string, options idp.Options, ) *SAMLIDPAddedEvent { return &SAMLIDPAddedEvent{ @@ -1032,6 +1035,8 @@ func NewSAMLIDPAddedEvent( certificate, binding, withSignedRequest, + nameIDFormat, + transientMappingAttributeName, options, ), } diff --git a/internal/repository/org/idp.go b/internal/repository/org/idp.go index 5f28d4481..a2bc5c7ab 100644 --- a/internal/repository/org/idp.go +++ b/internal/repository/org/idp.go @@ -5,6 +5,7 @@ import ( "time" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/idp" ) @@ -1017,6 +1018,8 @@ func NewSAMLIDPAddedEvent( certificate []byte, binding string, withSignedRequest bool, + nameIDFormat *domain.SAMLNameIDFormat, + transientMappingAttributeName string, options idp.Options, ) *SAMLIDPAddedEvent { @@ -1034,6 +1037,8 @@ func NewSAMLIDPAddedEvent( certificate, binding, withSignedRequest, + nameIDFormat, + transientMappingAttributeName, options, ), } diff --git a/internal/static/i18n/bg.yaml b/internal/static/i18n/bg.yaml index 91085035d..175775e73 100644 --- a/internal/static/i18n/bg.yaml +++ b/internal/static/i18n/bg.yaml @@ -534,6 +534,7 @@ Errors: IDPMissing: IDP липсва в заявката IDPInvalid: IDP невалиден за заявката ResponseInvalid: Отговорът на IDP е невалиден + MissingSingleMappingAttribute: Не съдържа атрибута за съпоставяне или има повече от една стойност SuccessURLMissing: В заявката липсва URL адрес за успех FailureURLMissing: В заявката липсва URL адрес за грешка StateMissing: В заявката липсва параметър състояние diff --git a/internal/static/i18n/cs.yaml b/internal/static/i18n/cs.yaml index 6a375443b..9f737b814 100644 --- a/internal/static/i18n/cs.yaml +++ b/internal/static/i18n/cs.yaml @@ -514,6 +514,7 @@ Errors: IDPMissing: V požadavku chybí IDP ID IDPInvalid: IDP je pro požadavek neplatné ResponseInvalid: Odpověď IDP je neplatná + MissingSingleMappingAttribute: Neobsahuje atribut mapování nebo má více než jednu hodnotu SuccessURLMissing: V požadavku chybí úspěšná URL FailureURLMissing: V požadavku chybí URL selhání StateMissing: V požadavku chybí parametr stavu diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 0a1aae5d4..74f159ec2 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -516,6 +516,7 @@ Errors: IDPMissing: IDP ID fehlt im Request IDPInvalid: IDP ungültig für die Anfrage ResponseInvalid: IDP-Antwort ist ungültig + MissingSingleMappingAttribute: Enthält das Zuordnungsattribut nicht oder hat mehr als einen Wert SuccessURLMissing: Success URL fehlt im Request FailureURLMissing: Failure URL fehlt im Request StateMissing: State parameter fehlt im Request diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 12a7151c9..1c3d14108 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -516,6 +516,7 @@ Errors: IDPMissing: IDP ID is missing in the request IDPInvalid: IDP invalid for the request ResponseInvalid: IDP response is invalid + MissingSingleMappingAttribute: IDP response does not contain the mapping attribute or has more than one value SuccessURLMissing: Success URL is missing in the request FailureURLMissing: Failure URL is missing in the request StateMissing: State parameter is missing in the request diff --git a/internal/static/i18n/es.yaml b/internal/static/i18n/es.yaml index 5fc15409b..3ffb229d7 100644 --- a/internal/static/i18n/es.yaml +++ b/internal/static/i18n/es.yaml @@ -516,6 +516,7 @@ Errors: IDPMissing: Falta IDP en la solicitud IDPInvalid: IDP no válido para la solicitud ResponseInvalid: La respuesta del IDP no es válida + MissingSingleMappingAttribute: No contiene el atributo de asignación o tiene más de un valor SuccessURLMissing: Falta la URL de éxito en la solicitud FailureURLMissing: Falta la URL de error en la solicitud StateMissing: Falta un parámetro de estado en la solicitud diff --git a/internal/static/i18n/fr.yaml b/internal/static/i18n/fr.yaml index 6d0592111..41d10dbc2 100644 --- a/internal/static/i18n/fr.yaml +++ b/internal/static/i18n/fr.yaml @@ -516,6 +516,7 @@ Errors: IDPMissing: IDP manquant dans la requête IDPInvalid: IDP non valide pour la demande ResponseInvalid: La réponse de l'IDP n'est pas valide + MissingSingleMappingAttribute: Ne contient pas l'attribut de mappage ou a plus d'une valeur SuccessURLMissing: Success URL absent de la requête FailureURLMissing: Failure URL absent de la requête StateMissing: Paramètre d'état manquant dans la requête diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml index 0a1e8e76a..9e5541b13 100644 --- a/internal/static/i18n/it.yaml +++ b/internal/static/i18n/it.yaml @@ -516,6 +516,7 @@ Errors: IDPMissing: IDP mancante nella richiesta IDPInvalid: IDP non valido per la richiesta ResponseInvalid: La risposta dell'IDP non è valida + MissingSingleMappingAttribute: Non contiene l'attributo di mapping o ha più di un valore SuccessURLMissing: URL di successo mancante nella richiesta FailureURLMissing: URL di errore mancante nella richiesta StateMissing: parametro di stato mancante nella richiesta diff --git a/internal/static/i18n/ja.yaml b/internal/static/i18n/ja.yaml index be42786b0..ed922e481 100644 --- a/internal/static/i18n/ja.yaml +++ b/internal/static/i18n/ja.yaml @@ -505,6 +505,7 @@ Errors: IDPMissing: リクエストにIDP IDが含まれていません IDPInvalid: リクエストのIDPが無効 ResponseInvalid: IDPの回答は無効 + MissingSingleMappingAttribute: マッピング属性が含まれていない、または複数の値がある SuccessURLMissing: リクエストに成功時の URL がありません FailureURLMissing: リクエストに失敗の URL がありません StateMissing: リクエストに State パラメータがありません diff --git a/internal/static/i18n/mk.yaml b/internal/static/i18n/mk.yaml index 826b4cc4e..db2d29dd1 100644 --- a/internal/static/i18n/mk.yaml +++ b/internal/static/i18n/mk.yaml @@ -515,6 +515,7 @@ Errors: IDPMissing: ID на IDP недостасува во барањето6bg IDPInvalid: ВРЛ неважечки за барањето ResponseInvalid: Одговорот на ВРЛ е неважечки + MissingSingleMappingAttribute: не го содржи атрибутот за мапирање или има повеќе од една вредност SuccessURLMissing: URL за успех недостасува во барањето FailureURLMissing: URL за неуспех недостасува во барањето StateMissing: Параметарот State недостасува во барањето diff --git a/internal/static/i18n/nl.yaml b/internal/static/i18n/nl.yaml index fa7c20203..3ef228c85 100644 --- a/internal/static/i18n/nl.yaml +++ b/internal/static/i18n/nl.yaml @@ -515,6 +515,7 @@ Errors: IDPMissing: IDP ID ontbreekt in het verzoek IDPInvalid: IDP ongeldig voor het verzoek ResponseInvalid: IDP respons is ongeldig + MissingSingleMappingAttribute: Bevat kenmerk toewijzing niet of heeft meer dan één waarde SuccessURLMissing: Success URL ontbreekt in het verzoek FailureURLMissing: Failure URL ontbreekt in het verzoek StateMissing: Staat parameter ontbreekt in het verzoek diff --git a/internal/static/i18n/pl.yaml b/internal/static/i18n/pl.yaml index 35f73fbec..69abd71e8 100644 --- a/internal/static/i18n/pl.yaml +++ b/internal/static/i18n/pl.yaml @@ -516,6 +516,7 @@ Errors: IDPMissing: Brak identyfikatora IDP w żądaniu IDPInvalid: IDP nieprawidłowe dla żądania ResponseInvalid: Odpowiedź IDP jest nieprawidłowa + MissingSingleMappingAttribute: Nie zawiera atrybutu mapowania lub ma więcej niż jedną wartość SuccessURLMissing: Brak adresu URL powodzenia w żądaniu FailureURLMissing: Brak adresu URL niepowodzenia w żądaniu StateMissing: Brak parametru stanu w żądaniu diff --git a/internal/static/i18n/pt.yaml b/internal/static/i18n/pt.yaml index a9e3f4c1f..da5a6a761 100644 --- a/internal/static/i18n/pt.yaml +++ b/internal/static/i18n/pt.yaml @@ -515,6 +515,7 @@ Errors: IDPMissing: O ID do IDP está faltando na solicitação IDPInvalid: IDP inválido para o pedido ResponseInvalid: A resposta da PDI é inválida + MissingSingleMappingAttribute: Não contém o atributo de mapeamento ou tem mais de um valor SuccessURLMissing: A URL de sucesso está faltando na solicitação FailureURLMissing: A URL de falha está faltando na solicitação StateMissing: O parâmetro de estado está faltando na solicitação diff --git a/internal/static/i18n/ru.yaml b/internal/static/i18n/ru.yaml index 53b95ea36..9be827e3b 100644 --- a/internal/static/i18n/ru.yaml +++ b/internal/static/i18n/ru.yaml @@ -505,6 +505,7 @@ Errors: NoChallenge: Сеанс без вызова WebAuthN Intent: IDPMissing: В запросе отсутствует идентификатор IDP + MissingSingleMappingAttribute: Не содержит атрибут сопоставления или имеет более одного значения SuccessURLMissing: В запросе отсутствует URL-адрес успешного выполнения FailureURLMissing: В запросе отсутствует URL-адрес ошибки StateMissing: В запросе отсутствует параметр State diff --git a/internal/static/i18n/zh.yaml b/internal/static/i18n/zh.yaml index fd9ed9ed1..409fb9ce7 100644 --- a/internal/static/i18n/zh.yaml +++ b/internal/static/i18n/zh.yaml @@ -516,6 +516,7 @@ Errors: IDPMissing: 请求中缺少IDP ID IDPInvalid: 请求的 IDP 无效 ResponseInvalid: IDP 响应无效 + MissingSingleMappingAttribute: 不包含映射属性或具有多个值 SuccessURLMissing: 请求中缺少成功URL FailureURLMissing: 请求中缺少失败的URL StateMissing: 请求中缺少状态参数 diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto index 374ad3c88..e05d74b43 100644 --- a/proto/zitadel/admin.proto +++ b/proto/zitadel/admin.proto @@ -6028,31 +6028,28 @@ message AddSAMLProviderRequest { string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; oneof metadata { option (validate.required) = true; + // Metadata of the SAML identity provider. bytes metadata_xml = 2 [ - (validate.rules).bytes.max_len = 500000, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Metadata of the SAML identity provider"; - } + (validate.rules).bytes.max_len = 500000 ]; + // Url to the metadata of the SAML identity provider. string metadata_url = 3 [ (validate.rules).string.max_len = 200, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"https://test.com/saml/metadata\"" - description: "Url to the metadata of the SAML identity provider"; } ]; } - zitadel.idp.v1.SAMLBinding binding = 4 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Binding which defines the type of communication with the identity provider"; - } - ]; - bool with_signed_request = 5 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Boolean which defines if the authentication requests are signed"; - } - ]; + // Binding which defines the type of communication with the identity provider. + zitadel.idp.v1.SAMLBinding binding = 4; + // Boolean which defines if the authentication requests are signed. + bool with_signed_request = 5; zitadel.idp.v1.Options provider_options = 6; + // Optionally specify the `nameid-format` requested. + optional zitadel.idp.v1.SAMLNameIDFormat name_id_format = 7; + // Optionally specify the 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 = 8; } message AddSAMLProviderResponse { @@ -6063,33 +6060,30 @@ message AddSAMLProviderResponse { message UpdateSAMLProviderRequest { string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}]; + // Metadata of the SAML identity provider. oneof metadata { option (validate.required) = true; bytes metadata_xml = 3 [ - (validate.rules).bytes.max_len = 500000, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Metadata of the SAML identity provider"; - } + (validate.rules).bytes.max_len = 500000 ]; + // Url to the metadata of the SAML identity provider string metadata_url = 4 [ (validate.rules).string.max_len = 200, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"https://test.com/saml/metadata\"" - description: "Url to the metadata of the SAML identity provider"; } ]; } - zitadel.idp.v1.SAMLBinding binding = 5 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Binding which defines the type of communication with the identity provider"; - } - ]; - bool with_signed_request = 6 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Boolean which defines if the authentication requests are signed"; - } - ]; + // Binding which defines the type of communication with the identity provider. + zitadel.idp.v1.SAMLBinding binding = 5; + // Boolean which defines if the authentication requests are signed + bool with_signed_request = 6; zitadel.idp.v1.Options provider_options = 7; + // Optionally specify the `nameid-format` requested. + optional zitadel.idp.v1.SAMLNameIDFormat name_id_format = 8; + // Optionally specify the 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 = 9; } message UpdateSAMLProviderResponse { diff --git a/proto/zitadel/idp.proto b/proto/zitadel/idp.proto index 1beab90a5..2f434f50c 100644 --- a/proto/zitadel/idp.proto +++ b/proto/zitadel/idp.proto @@ -276,6 +276,13 @@ enum SAMLBinding { SAML_BINDING_ARTIFACT = 3; } +enum SAMLNameIDFormat { + SAML_NAME_ID_FORMAT_UNSPECIFIED = 0; + SAML_NAME_ID_FORMAT_EMAIL_ADDRESS = 1; + SAML_NAME_ID_FORMAT_PERSISTENT = 2; + SAML_NAME_ID_FORMAT_TRANSIENT = 3; +} + message ProviderConfig { Options options = 1; oneof config { @@ -452,21 +459,17 @@ message LDAPConfig { } message SAMLConfig { - bytes metadata_xml = 1 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Metadata of the SAML identity provider"; - } - ]; - zitadel.idp.v1.SAMLBinding binding = 2 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Binding which defines the type of communication with the identity provider"; - } - ]; - bool with_signed_request = 3 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Boolean which defines if the authentication requests are signed"; - } - ]; + // Metadata of the SAML identity provider. + bytes metadata_xml = 1; + // Binding which defines the type of communication with the identity provider. + zitadel.idp.v1.SAMLBinding binding = 2; + // Boolean which defines if the authentication requests are signed. + bool with_signed_request = 3; + // `nameid-format` for the SAML Request. + zitadel.idp.v1.SAMLNameIDFormat name_id_format = 4; + // 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; } message AzureADConfig { diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto index 9b59f13be..560b37a09 100644 --- a/proto/zitadel/management.proto +++ b/proto/zitadel/management.proto @@ -12767,31 +12767,28 @@ message AddSAMLProviderRequest { string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; oneof metadata { option (validate.required) = true; + // Metadata of the SAML identity provider. bytes metadata_xml = 2 [ - (validate.rules).bytes.max_len = 500000, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Metadata of the SAML identity provider"; - } + (validate.rules).bytes.max_len = 500000 ]; + // Url to the metadata of the SAML identity provider. string metadata_url = 3 [ (validate.rules).string.max_len = 200, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"https://test.com/saml/metadata\"" - description: "Url to the metadata of the SAML identity provider"; } ]; } - zitadel.idp.v1.SAMLBinding binding = 4 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Binding which defines the type of communication with the identity provider"; - } - ]; - bool with_signed_request = 5 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Boolean which defines if the authentication requests are signed"; - } - ]; + // Binding which defines the type of communication with the identity provider. + zitadel.idp.v1.SAMLBinding binding = 4; + // Boolean which defines if the authentication requests are signed. + bool with_signed_request = 5; zitadel.idp.v1.Options provider_options = 6; + // Optionally specify the `nameid-format` requested. + optional zitadel.idp.v1.SAMLNameIDFormat name_id_format = 7; + // Optionally specify the 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 = 8; } message AddSAMLProviderResponse { @@ -12802,33 +12799,30 @@ message AddSAMLProviderResponse { message UpdateSAMLProviderRequest { string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}]; + // Metadata of the SAML identity provider. oneof metadata { option (validate.required) = true; bytes metadata_xml = 3 [ - (validate.rules).bytes.max_len = 500000, - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Metadata of the SAML identity provider"; - } + (validate.rules).bytes.max_len = 500000 ]; + // Url to the metadata of the SAML identity provider. string metadata_url = 4 [ (validate.rules).string.max_len = 200, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"https://test.com/saml/metadata\"" - description: "Url to the metadata of the SAML identity provider"; } ]; } - zitadel.idp.v1.SAMLBinding binding = 5 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Binding which defines the type of communication with the identity provider"; - } - ]; - bool with_signed_request = 6 [ - (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Boolean which defines if the authentication requests are signed"; - } - ]; + // Binding which defines the type of communication with the identity provider. + zitadel.idp.v1.SAMLBinding binding = 5; + // Boolean which defines if the authentication requests are signed. + bool with_signed_request = 6; zitadel.idp.v1.Options provider_options = 7; + // Optionally specify the `nameid-format` requested. + optional zitadel.idp.v1.SAMLNameIDFormat name_id_format = 8; + // Optionally specify the 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 = 9; } message UpdateSAMLProviderResponse {