Browse Source

feat: support claim-based group name modification with separators

Introduce ValueOrClaim type to allow prefix/suffix to reference OIDC claims
with configurable separators. Separators are appended after prefix values
and prepended before suffix values.
pull/4511/head
lorissenneca 1 month ago committed by GitHub
parent
commit
8ca4787de8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 48
      connector/oidc/oidc.go
  2. 20
      connector/oidc/oidc_test.go

48
connector/oidc/oidc.go

@ -190,10 +190,19 @@ type FilterGroupClaims struct {
GroupsFilter string `json:"groupsFilter"`
}
// ValueOrClaim represents a value that can be either a literal string or a reference to a claim.
// If Claim is set, its value from the claims map will be used.
// Otherwise, Value (the literal string) will be used.
type ValueOrClaim struct {
Value string `json:"value,omitempty"`
Claim string `json:"claim,omitempty"`
Separator string `json:"separator,omitempty"`
}
// ModifyGroupNames allows to modify the group claims by adding a prefix and/or suffix to each group.
type ModifyGroupNames struct {
Prefix string `json:"prefix"`
Suffix string `json:"suffix"`
Prefix ValueOrClaim `json:"prefix"`
Suffix ValueOrClaim `json:"suffix"`
}
// Domains that don't support basic auth. golang.org/x/oauth2 has an internal
@ -314,8 +323,7 @@ func (c *Config) Open(id string, logger *slog.Logger) (conn connector.Connector,
groupsKey: c.ClaimMapping.GroupsKey,
newGroupFromClaims: c.ClaimMutations.NewGroupFromClaims,
groupsFilter: groupsFilter,
groupsPrefix: c.ClaimMutations.ModifyGroupNames.Prefix,
groupsSuffix: c.ClaimMutations.ModifyGroupNames.Suffix,
modifyGroupNames: c.ClaimMutations.ModifyGroupNames,
}, nil
}
@ -346,8 +354,7 @@ type oidcConnector struct {
groupsKey string
newGroupFromClaims []NewGroupFromClaims
groupsFilter *regexp.Regexp
groupsPrefix string
groupsSuffix string
modifyGroupNames ModifyGroupNames
}
func (c *oidcConnector) Close() error {
@ -441,6 +448,28 @@ func (c *oidcConnector) TokenIdentity(ctx context.Context, subjectTokenType, sub
return c.createIdentity(ctx, identity, token, exchangeCaller)
}
// resolveValueOrClaim resolves either a literal value or a claim reference.
// isPrefix indicates if this is for a prefix (true) or suffix (false).
func resolveValueOrClaim(v ValueOrClaim, claims map[string]interface{}, isPrefix bool) string {
var result string
if v.Claim != "" {
if s, ok := claims[v.Claim].(string); ok {
result = s
}
} else {
result = v.Value
}
if result != "" && v.Separator != "" {
if isPrefix {
result += v.Separator
} else {
result = v.Separator + result
}
}
return result
}
func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.Identity, token *oauth2.Token, caller caller) (connector.Identity, error) {
var claims map[string]interface{}
@ -588,9 +617,12 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
}
// add prefix/suffix to groups
if c.groupsPrefix != "" || c.groupsSuffix != "" {
if c.modifyGroupNames.Prefix.Value != "" || c.modifyGroupNames.Prefix.Claim != "" ||
c.modifyGroupNames.Suffix.Value != "" || c.modifyGroupNames.Suffix.Claim != "" {
for i, group := range groups {
groups[i] = c.groupsPrefix + group + c.groupsSuffix
prefix := resolveValueOrClaim(c.modifyGroupNames.Prefix, claims, true)
suffix := resolveValueOrClaim(c.modifyGroupNames.Suffix, claims, false)
groups[i] = prefix + group + suffix
}
}

20
connector/oidc/oidc_test.go

@ -65,8 +65,7 @@ func TestHandleCallback(t *testing.T) {
token map[string]interface{}
groupsRegex string
newGroupFromClaims []NewGroupFromClaims
groupsPrefix string
groupsSuffix string
modifyGroupNames ModifyGroupNames
}{
{
name: "simpleCase",
@ -406,7 +405,9 @@ func TestHandleCallback(t *testing.T) {
expectUserName: "namevalue",
expectGroups: []string{"prefix-group1", "prefix-group2", "prefix-groupA", "prefix-groupB"},
expectedEmailField: "emailvalue",
groupsPrefix: "prefix-",
modifyGroupNames: ModifyGroupNames{
Prefix: ValueOrClaim{Value: "prefix-"},
},
token: map[string]interface{}{
"sub": "subvalue",
"name": "namevalue",
@ -423,7 +424,9 @@ func TestHandleCallback(t *testing.T) {
expectUserName: "namevalue",
expectGroups: []string{"group1-suffix", "group2-suffix", "groupA-suffix", "groupB-suffix"},
expectedEmailField: "emailvalue",
groupsSuffix: "-suffix",
modifyGroupNames: ModifyGroupNames{
Suffix: ValueOrClaim{Value: "-suffix"},
},
token: map[string]interface{}{
"sub": "subvalue",
"name": "namevalue",
@ -440,8 +443,10 @@ func TestHandleCallback(t *testing.T) {
expectUserName: "namevalue",
expectGroups: []string{"prefix-group1-suffix", "prefix-group2-suffix", "prefix-groupA-suffix", "prefix-groupB-suffix"},
expectedEmailField: "emailvalue",
groupsPrefix: "prefix-",
groupsSuffix: "-suffix",
modifyGroupNames: ModifyGroupNames{
Prefix: ValueOrClaim{Value: "prefix-"},
Suffix: ValueOrClaim{Value: "-suffix"},
},
token: map[string]interface{}{
"sub": "subvalue",
"name": "namevalue",
@ -521,8 +526,7 @@ func TestHandleCallback(t *testing.T) {
config.ClaimMapping.GroupsKey = tc.groupsKey
config.ClaimMutations.NewGroupFromClaims = tc.newGroupFromClaims
config.ClaimMutations.FilterGroupClaims.GroupsFilter = tc.groupsRegex
config.ClaimMutations.ModifyGroupNames.Prefix = tc.groupsPrefix
config.ClaimMutations.ModifyGroupNames.Suffix = tc.groupsSuffix
config.ClaimMutations.ModifyGroupNames = tc.modifyGroupNames
conn, err := newConnector(config)
if err != nil {

Loading…
Cancel
Save