Merge pull request #2233 from Happy2C0de/add-claimMapping-enforcement

Add claimMapping enforcement
This commit is contained in:
Márk Sági-Kazár 2022-01-19 15:30:29 +01:00 committed by GitHub
commit 73ce1eb110
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 3 deletions

View file

@ -56,6 +56,11 @@ type Config struct {
// PromptType will be used fot the prompt parameter (when offline_access, by default prompt=consent) // PromptType will be used fot the prompt parameter (when offline_access, by default prompt=consent)
PromptType string `json:"promptType"` PromptType string `json:"promptType"`
// OverrideClaimMapping will be used to override the options defined in claimMappings.
// i.e. if there are 'email' and `preferred_email` claims available, by default Dex will always use the `email` claim independent of the ClaimMapping.EmailKey.
// This setting allows you to override the default behavior of Dex and enforce the mappings defined in `claimMapping`.
OverrideClaimMapping bool `json:"overrideClaimMapping"` // defaults to false
ClaimMapping struct { ClaimMapping struct {
// Configurable key which contains the preferred username claims // Configurable key which contains the preferred username claims
PreferredUsernameKey string `json:"preferred_username"` // defaults to "preferred_username" PreferredUsernameKey string `json:"preferred_username"` // defaults to "preferred_username"
@ -153,6 +158,7 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e
promptType: c.PromptType, promptType: c.PromptType,
userIDKey: c.UserIDKey, userIDKey: c.UserIDKey,
userNameKey: c.UserNameKey, userNameKey: c.UserNameKey,
overrideClaimMapping: c.OverrideClaimMapping,
preferredUsernameKey: c.ClaimMapping.PreferredUsernameKey, preferredUsernameKey: c.ClaimMapping.PreferredUsernameKey,
emailKey: c.ClaimMapping.EmailKey, emailKey: c.ClaimMapping.EmailKey,
groupsKey: c.ClaimMapping.GroupsKey, groupsKey: c.ClaimMapping.GroupsKey,
@ -178,6 +184,7 @@ type oidcConnector struct {
promptType string promptType string
userIDKey string userIDKey string
userNameKey string userNameKey string
overrideClaimMapping bool
preferredUsernameKey string preferredUsernameKey string
emailKey string emailKey string
groupsKey string groupsKey string
@ -289,7 +296,7 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
} }
preferredUsername, found := claims["preferred_username"].(string) preferredUsername, found := claims["preferred_username"].(string)
if !found { if (!found || c.overrideClaimMapping) && c.preferredUsernameKey != "" {
preferredUsername, _ = claims[c.preferredUsernameKey].(string) preferredUsername, _ = claims[c.preferredUsernameKey].(string)
} }
@ -304,7 +311,7 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
var email string var email string
emailKey := "email" emailKey := "email"
email, found = claims[emailKey].(string) email, found = claims[emailKey].(string)
if !found && c.emailKey != "" { if (!found || c.overrideClaimMapping) && c.emailKey != "" {
emailKey = c.emailKey emailKey = c.emailKey
email, found = claims[emailKey].(string) email, found = claims[emailKey].(string)
} }
@ -326,7 +333,7 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
if c.insecureEnableGroups { if c.insecureEnableGroups {
groupsKey := "groups" groupsKey := "groups"
vs, found := claims[groupsKey].([]interface{}) vs, found := claims[groupsKey].([]interface{})
if !found { if (!found || c.overrideClaimMapping) && c.groupsKey != "" {
groupsKey = c.groupsKey groupsKey = c.groupsKey
vs, found = claims[groupsKey].([]interface{}) vs, found = claims[groupsKey].([]interface{})
} }

View file

@ -49,6 +49,7 @@ func TestHandleCallback(t *testing.T) {
name string name string
userIDKey string userIDKey string
userNameKey string userNameKey string
overrideClaimMapping bool
preferredUsernameKey string preferredUsernameKey string
emailKey string emailKey string
groupsKey string groupsKey string
@ -92,6 +93,23 @@ func TestHandleCallback(t *testing.T) {
"email_verified": true, "email_verified": true,
}, },
}, },
{
name: "overrideWithCustomEmailClaim",
userIDKey: "", // not configured
userNameKey: "", // not configured
overrideClaimMapping: true,
emailKey: "custommail",
expectUserID: "subvalue",
expectUserName: "namevalue",
expectedEmailField: "customemailvalue",
token: map[string]interface{}{
"sub": "subvalue",
"name": "namevalue",
"email": "emailvalue",
"custommail": "customemailvalue",
"email_verified": true,
},
},
{ {
name: "email_verified not in claims, configured to be skipped", name: "email_verified not in claims, configured to be skipped",
insecureSkipEmailVerified: true, insecureSkipEmailVerified: true,
@ -234,6 +252,25 @@ func TestHandleCallback(t *testing.T) {
"cognito:groups": []string{"group3", "group4"}, "cognito:groups": []string{"group3", "group4"},
}, },
}, },
{
name: "customGroupsKeyDespiteGroupsProvidedButOverride",
overrideClaimMapping: true,
groupsKey: "cognito:groups",
expectUserID: "subvalue",
expectUserName: "namevalue",
expectedEmailField: "emailvalue",
expectGroups: []string{"group3", "group4"},
scopes: []string{"groups"},
insecureSkipEmailVerified: true,
token: map[string]interface{}{
"sub": "subvalue",
"name": "namevalue",
"user_name": "username",
"email": "emailvalue",
"groups": []string{"group1", "group2"},
"cognito:groups": []string{"group3", "group4"},
},
},
} }
for _, tc := range tests { for _, tc := range tests {
@ -263,6 +300,7 @@ func TestHandleCallback(t *testing.T) {
InsecureSkipEmailVerified: tc.insecureSkipEmailVerified, InsecureSkipEmailVerified: tc.insecureSkipEmailVerified,
InsecureEnableGroups: true, InsecureEnableGroups: true,
BasicAuthUnsupported: &basicAuth, BasicAuthUnsupported: &basicAuth,
OverrideClaimMapping: tc.overrideClaimMapping,
} }
config.ClaimMapping.PreferredUsernameKey = tc.preferredUsernameKey config.ClaimMapping.PreferredUsernameKey = tc.preferredUsernameKey
config.ClaimMapping.EmailKey = tc.emailKey config.ClaimMapping.EmailKey = tc.emailKey