Repository: oauth2-proxy/oauth2-proxy
Pull request #1720 (2022-07-08 12:36:29)

Extract Keycloak roles while creating a session from token
<!--- Provide a general summary of your changes in the Title above -->

## Description
While creating a new Session from an AuthToken the Keycloak roles needs to be extracted. Otherwise they're not part of the session which will break the authentication. (AllowedGroups doesn't match givenGroups.. because it's empty). Since `CreateSessionFromToken` was already used from the OIDC provider, adding a single line shouldn't break anything.
<!--- Describe your changes in detail -->

## Motivation and Context
The main motivation is to fix https://github.com/oauth2-proxy/oauth2-proxy/issues/1457#. It blocks user's from authenticating via token in combination with role checks

## How Has This Been Tested?

Besides alot of manual testing I've also added a small unit test.

To reproduce the issue you need to create an Keycloak Client and a user. Create a auth token and try to authenticate against the proxy using the token.  Use the following settings for the proxy:
``
          "--client-id=xxxxx",
          "--client-secret=xxxx",
          "--upstream=xxxxx",
          "--oidc-issuer-url=xxxxxx",
          "--redeem-url=xxxxxx",
          "--redirect-url=xxxxxx",
          "--http-address=xxxxx",
          "--auth-logging=true",
          "--email-domain=*",
          "--cookie-secret=xxxx",
          "--standard-logging=true",
          "--auth-logging=true",
          "--request-logging=true",
          "--whitelist-domain=xxxxxxx",
          "--skip-provider-button=true",
          "--skip-jwt-bearer-tokens=true",
          "--pass-authorization-header=true",
          "--pass-access-token=true",
          "--pass-user-headers=true",
          "--allowed-role=realm-access-role",
          "--cookie-secure=false",
          "--scope=openid email profile",
          "--skip-auth-route=/health"``
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [x] My change requires a change to the documentation or CHANGELOG.
- [x] I have updated the documentation/CHANGELOG accordingly.
- [x] I have created a feature (non-master) branch for my PR.


DrPsychick: Any chance this can be reviewed and merged?
JoelSpeed: This looks reasonable, thanks! 

Could you fixup the changelog conflict and I'll get it merged

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e5a586db..028e0931 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,8 @@
 
 - [#1709](https://github.com/oauth2-proxy/oauth2-proxy/pull/1709) Show an alert message when basic auth credentials are invalid (@aiciobanu)
 
+- [#1720](https://github.com/oauth2-proxy/oauth2-proxy/pull/1720) Extract roles from authToken, to allow using allowed roles with Keycloak.
+
 # V7.3.0
 
 ## Release Highlights
diff --git a/providers/keycloak_oidc.go b/providers/keycloak_oidc.go
index e16b4383..28abae3a 100644
--- a/providers/keycloak_oidc.go
+++ b/providers/keycloak_oidc.go
@@ -43,6 +43,21 @@ func (p *KeycloakOIDCProvider) addAllowedRoles(roles []string) {
 	}
 }
 
+// CreateSessionFromToken converts Bearer IDTokens into sessions
+func (p *KeycloakOIDCProvider) CreateSessionFromToken(ctx context.Context, token string) (*sessions.SessionState, error) {
+	ss, err := p.OIDCProvider.CreateSessionFromToken(ctx, token)
+	if err != nil {
+		return nil, fmt.Errorf("could not create session from token: %v", err)
+	}
+
+	// Extract custom keycloak roles and enrich session
+	if err := p.extractRoles(ctx, ss); err != nil {
+		return nil, err
+	}
+
+	return ss, nil
+}
+
 // EnrichSession is called after Redeem to allow providers to enrich session fields
 // such as User, Email, Groups with provider specific API calls.
 func (p *KeycloakOIDCProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {


Test patch:
diff --git a/providers/keycloak_oidc_test.go b/providers/keycloak_oidc_test.go
index d1a50b2a..4f326f70 100644
--- a/providers/keycloak_oidc_test.go
+++ b/providers/keycloak_oidc_test.go
@@ -199,4 +199,22 @@ var _ = Describe("Keycloak OIDC Provider Tests", func() {
 			Expect(existingSession.Groups).To(BeEquivalentTo([]string{"role:write", "role:default:read"}))
 		})
 	})
+
+	Context("Create new session from token", func() {
+		It("should create a session and extract roles ", func() {
+			server, provider := newTestKeycloakOIDCSetup()
+			url, err := url.Parse(server.URL)
+			Expect(err).To(BeNil())
+			defer server.Close()
+
+			provider.ProfileURL = url
+
+			session, err := provider.CreateSessionFromToken(context.Background(), getAccessToken())
+			Expect(err).To(BeNil())
+			Expect(session.ExpiresOn).ToNot(BeNil())
+			Expect(session.CreatedAt).ToNot(BeNil())
+			Expect(session.Groups).To(BeEquivalentTo([]string{"role:write", "role:default:read"}))
+		})
+	})
+
 })