mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:47:33 +00:00
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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user