From 8b93966357ec4bd7d8f2db046a6ad2fcdb795a29 Mon Sep 17 00:00:00 2001
From: Melroy Dsouza <meldsza@gmail.com>
Date: Thu, 31 Oct 2024 15:35:22 +0530
Subject: [PATCH] Support for IssuerAlias and groups as maps (#3676)

Signed-off-by: Melroy Dsouza <meldsza@gmail.com>
---
 connector/oidc/oidc.go      | 18 ++++++++++++--
 connector/oidc/oidc_test.go | 49 +++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go
index 7d0cacb0..1ea0c1fc 100644
--- a/connector/oidc/oidc.go
+++ b/connector/oidc/oidc.go
@@ -23,7 +23,12 @@ import (
 
 // Config holds configuration options for OpenID Connect logins.
 type Config struct {
-	Issuer       string `json:"issuer"`
+	Issuer string `json:"issuer"`
+	// Some offspec providers like Azure, Oracle IDCS have oidc discovery url
+	// different from issuer url which causes issuerValidation to fail
+	// IssuerAlias provides a way to override the Issuer url
+	// from the .well-known/openid-configuration issuer
+	IssuerAlias  string `json:"issuerAlias"`
 	ClientID     string `json:"clientID"`
 	ClientSecret string `json:"clientSecret"`
 	RedirectURI  string `json:"redirectURI"`
@@ -226,7 +231,9 @@ func (c *Config) Open(id string, logger *slog.Logger) (conn connector.Connector,
 
 	bgctx, cancel := context.WithCancel(context.Background())
 	ctx := context.WithValue(bgctx, oauth2.HTTPClient, httpClient)
-
+	if c.IssuerAlias != "" {
+		ctx = oidc.InsecureIssuerURLContext(ctx, c.IssuerAlias)
+	}
 	provider, err := getProvider(ctx, c.Issuer, c.ProviderDiscoveryOverrides)
 	if err != nil {
 		cancel()
@@ -540,6 +547,13 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I
 						continue
 					}
 					groups = append(groups, s)
+				} else if groupMap, ok := v.(map[string]interface{}); ok {
+					if s, ok := groupMap["name"].(string); ok {
+						if c.groupsFilter != nil && !c.groupsFilter.MatchString(s) {
+							continue
+						}
+						groups = append(groups, s)
+					}
 				} else {
 					return identity, fmt.Errorf("malformed \"%v\" claim", groupsKey)
 				}
diff --git a/connector/oidc/oidc_test.go b/connector/oidc/oidc_test.go
index 66b35c3f..e31d4e0b 100644
--- a/connector/oidc/oidc_test.go
+++ b/connector/oidc/oidc_test.go
@@ -292,6 +292,38 @@ func TestHandleCallback(t *testing.T) {
 				"email_verified": true,
 			},
 		},
+		{
+			name:               "singularGroupResponseAsMap",
+			userIDKey:          "", // not configured
+			userNameKey:        "", // not configured
+			expectUserID:       "subvalue",
+			expectUserName:     "namevalue",
+			expectGroups:       []string{"group1"},
+			expectedEmailField: "emailvalue",
+			token: map[string]interface{}{
+				"sub":            "subvalue",
+				"name":           "namevalue",
+				"groups":         []map[string]string{{"name": "group1"}},
+				"email":          "emailvalue",
+				"email_verified": true,
+			},
+		},
+		{
+			name:               "multipleGroupResponseAsMap",
+			userIDKey:          "", // not configured
+			userNameKey:        "", // not configured
+			expectUserID:       "subvalue",
+			expectUserName:     "namevalue",
+			expectGroups:       []string{"group1", "group2"},
+			expectedEmailField: "emailvalue",
+			token: map[string]interface{}{
+				"sub":            "subvalue",
+				"name":           "namevalue",
+				"groups":         []map[string]string{{"name": "group1"}, {"name": "group2"}},
+				"email":          "emailvalue",
+				"email_verified": true,
+			},
+		},
 		{
 			name:               "newGroupFromClaims",
 			userIDKey:          "", // not configured
@@ -382,6 +414,23 @@ func TestHandleCallback(t *testing.T) {
 				"email_verified": true,
 			},
 		},
+		{
+			name:               "filterGroupClaimsMap",
+			userIDKey:          "", // not configured
+			userNameKey:        "", // not configured
+			groupsRegex:        `^.*\d$`,
+			expectUserID:       "subvalue",
+			expectUserName:     "namevalue",
+			expectGroups:       []string{"group1", "group2"},
+			expectedEmailField: "emailvalue",
+			token: map[string]interface{}{
+				"sub":            "subvalue",
+				"name":           "namevalue",
+				"groups":         []map[string]string{{"name": "group1"}, {"name": "group2"}, {"name": "groupA"}, {"name": "groupB"}},
+				"email":          "emailvalue",
+				"email_verified": true,
+			},
+		},
 	}
 
 	for _, tc := range tests {
-- 
GitLab