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 <max@caos.ch>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
This commit is contained in:
Livio Spring
2024-05-23 07:04:07 +02:00
committed by GitHub
parent 12be21a3ff
commit e57a9b57c8
58 changed files with 1306 additions and 720 deletions

View File

@@ -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",
},
},
{