mirror of
https://github.com/netbirdio/dex.git
synced 2026-05-22 18:43:53 -07:00
Merge pull request #3056 from Oded-B/master
Composite claims in OIDC connector
This commit is contained in:
@@ -89,6 +89,27 @@ type Config struct {
|
||||
// Configurable key which contains the groups claims
|
||||
GroupsKey string `json:"groups"` // defaults to "groups"
|
||||
} `json:"claimMapping"`
|
||||
|
||||
// ClaimMutations holds all claim mutations options
|
||||
ClaimMutations struct {
|
||||
NewGroupFromClaims []NewGroupFromClaims `json:"newGroupFromClaims"`
|
||||
} `json:"claimModifications"`
|
||||
}
|
||||
|
||||
// NewGroupFromClaims creates a new group from a list of claims and appends it to the list of existing groups.
|
||||
type NewGroupFromClaims struct {
|
||||
// List of claim to join together
|
||||
Claims []string `json:"claims"`
|
||||
|
||||
// String to separate the claims
|
||||
Delimiter string `json:"delimiter"`
|
||||
|
||||
// Should Dex remove the Delimiter string from claim values
|
||||
// This is done to keep resulting claim structure in full control of the Dex operator
|
||||
ClearDelimiter bool `json:"clearDelimiter"`
|
||||
|
||||
// String to place before the first claim
|
||||
Prefix string `json:"prefix"`
|
||||
}
|
||||
|
||||
// Domains that don't support basic auth. golang.org/x/oauth2 has an internal
|
||||
@@ -192,6 +213,7 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e
|
||||
preferredUsernameKey: c.ClaimMapping.PreferredUsernameKey,
|
||||
emailKey: c.ClaimMapping.EmailKey,
|
||||
groupsKey: c.ClaimMapping.GroupsKey,
|
||||
newGroupFromClaims: c.ClaimMutations.NewGroupFromClaims,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -220,6 +242,7 @@ type oidcConnector struct {
|
||||
preferredUsernameKey string
|
||||
emailKey string
|
||||
groupsKey string
|
||||
newGroupFromClaims []NewGroupFromClaims
|
||||
}
|
||||
|
||||
func (c *oidcConnector) Close() error {
|
||||
@@ -443,6 +466,30 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
|
||||
}
|
||||
}
|
||||
|
||||
for _, config := range c.newGroupFromClaims {
|
||||
newGroupSegments := []string{
|
||||
config.Prefix,
|
||||
}
|
||||
for _, claimName := range config.Claims {
|
||||
claimValue, ok := claims[claimName].(string)
|
||||
if !ok { // Non string claim value are ignored, concatenating them doesn't really make any sense
|
||||
continue
|
||||
}
|
||||
|
||||
if config.ClearDelimiter {
|
||||
// Removing the delimiter string from the concatenated claim to ensure resulting claim structure
|
||||
// is in full control of Dex operator
|
||||
claimValue = strings.ReplaceAll(claimValue, config.Delimiter, "")
|
||||
}
|
||||
|
||||
newGroupSegments = append(newGroupSegments, claimValue)
|
||||
}
|
||||
|
||||
if len(newGroupSegments) > 1 {
|
||||
groups = append(groups, strings.Join(newGroupSegments, config.Delimiter))
|
||||
}
|
||||
}
|
||||
|
||||
cd := connectorData{
|
||||
RefreshToken: []byte(token.RefreshToken),
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ func TestHandleCallback(t *testing.T) {
|
||||
expectPreferredUsername string
|
||||
expectedEmailField string
|
||||
token map[string]interface{}
|
||||
newGroupFromClaims []NewGroupFromClaims
|
||||
}{
|
||||
{
|
||||
name: "simpleCase",
|
||||
@@ -288,6 +289,79 @@ func TestHandleCallback(t *testing.T) {
|
||||
"email_verified": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newGroupFromClaims",
|
||||
userIDKey: "", // not configured
|
||||
userNameKey: "", // not configured
|
||||
expectUserID: "subvalue",
|
||||
expectUserName: "namevalue",
|
||||
expectGroups: []string{"group1", "gh::acme::pipeline-one", "clr_delim-acme-foobar", "keep_delim-acme-foo-bar", "bk-emailvalue"},
|
||||
expectedEmailField: "emailvalue",
|
||||
newGroupFromClaims: []NewGroupFromClaims{
|
||||
{ // The basic functionality, should create "gh::acme::pipeline-one".
|
||||
Claims: []string{
|
||||
"organization",
|
||||
"pipeline",
|
||||
},
|
||||
Delimiter: "::",
|
||||
Prefix: "gh",
|
||||
},
|
||||
{ // Non existing claims, should not generate any any new group claim.
|
||||
Claims: []string{
|
||||
"non-existing1",
|
||||
"non-existing2",
|
||||
},
|
||||
Delimiter: "::",
|
||||
Prefix: "tfe",
|
||||
},
|
||||
{ // In this case the delimiter character("-") should be removed removed from "claim-with-delimiter" claim to ensure the resulting
|
||||
// claim structure is in full control of the Dex operator and not the person creating a new pipeline.
|
||||
// Should create "clr_delim-acme-foobar" and not "tfe-acme-foo-bar".
|
||||
Claims: []string{
|
||||
"organization",
|
||||
"claim-with-delimiter",
|
||||
},
|
||||
Delimiter: "-",
|
||||
ClearDelimiter: true,
|
||||
Prefix: "clr_delim",
|
||||
},
|
||||
{ // In this case the delimiter character("-") should be NOT removed from "claim-with-delimiter" claim.
|
||||
// Should create "keep_delim-acme-foo-bar".
|
||||
Claims: []string{
|
||||
"organization",
|
||||
"claim-with-delimiter",
|
||||
},
|
||||
Delimiter: "-",
|
||||
// ClearDelimiter: false,
|
||||
Prefix: "keep_delim",
|
||||
},
|
||||
{ // Ignore non string claims (like arrays), this should result in "bk-emailvalue".
|
||||
Claims: []string{
|
||||
"non-string-claim",
|
||||
"non-string-claim2",
|
||||
"email",
|
||||
},
|
||||
Delimiter: "-",
|
||||
Prefix: "bk",
|
||||
},
|
||||
},
|
||||
|
||||
token: map[string]interface{}{
|
||||
"sub": "subvalue",
|
||||
"name": "namevalue",
|
||||
"groups": "group1",
|
||||
"organization": "acme",
|
||||
"pipeline": "pipeline-one",
|
||||
"email": "emailvalue",
|
||||
"email_verified": true,
|
||||
"claim-with-delimiter": "foo-bar",
|
||||
"non-string-claim": []string{
|
||||
"element1",
|
||||
"element2",
|
||||
},
|
||||
"non-string-claim2": 666,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
@@ -323,6 +397,7 @@ func TestHandleCallback(t *testing.T) {
|
||||
config.ClaimMapping.PreferredUsernameKey = tc.preferredUsernameKey
|
||||
config.ClaimMapping.EmailKey = tc.emailKey
|
||||
config.ClaimMapping.GroupsKey = tc.groupsKey
|
||||
config.ClaimMutations.NewGroupFromClaims = tc.newGroupFromClaims
|
||||
|
||||
conn, err := newConnector(config)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user