From 012c155d2ad4d2911b264a5cda9b0c3c507afff3 Mon Sep 17 00:00:00 2001 From: SamTV12345 Date: Wed, 20 Nov 2024 08:46:14 +0100 Subject: [PATCH] Added validation of configured acr values (cherry picked from commit 0a5d74a7bb13554a41eaba3b7505d508fb53970a) --- pkg/apis/middleware/session.go | 2 ++ pkg/apis/options/legacy_options.go | 1 + pkg/apis/options/providers.go | 1 + pkg/apis/sessions/session_state.go | 3 +++ providers/keycloak.go | 1 + providers/keycloak_oidc.go | 1 + providers/provider_data.go | 10 ++++++++++ providers/provider_default.go | 11 +++++++++++ 8 files changed, 30 insertions(+) diff --git a/pkg/apis/middleware/session.go b/pkg/apis/middleware/session.go index 9fcd974b..4ef54b41 100644 --- a/pkg/apis/middleware/session.go +++ b/pkg/apis/middleware/session.go @@ -25,6 +25,7 @@ func CreateTokenToSessionFunc(verify VerifyFunc) TokenToSessionFunc { Verified *bool `json:"email_verified"` PreferredUsername string `json:"preferred_username"` Groups []string `json:"groups"` + Acr string `json:"acr"` } idToken, err := verify(ctx, token) @@ -49,6 +50,7 @@ func CreateTokenToSessionFunc(verify VerifyFunc) TokenToSessionFunc { User: claims.Subject, Groups: claims.Groups, PreferredUsername: claims.PreferredUsername, + Acr: claims.Acr, AccessToken: token, IDToken: token, RefreshToken: "", diff --git a/pkg/apis/options/legacy_options.go b/pkg/apis/options/legacy_options.go index 163aaa2c..8f539898 100644 --- a/pkg/apis/options/legacy_options.go +++ b/pkg/apis/options/legacy_options.go @@ -727,6 +727,7 @@ func (l *LegacyProvider) convert() (Providers, error) { provider.KeycloakConfig = KeycloakOptions{ Groups: l.KeycloakGroups, Roles: l.AllowedRoles, + ACRs: l.AcrValues, } case "keycloak": provider.KeycloakConfig = KeycloakOptions{ diff --git a/pkg/apis/options/providers.go b/pkg/apis/options/providers.go index 94c23ce1..11bbc2db 100644 --- a/pkg/apis/options/providers.go +++ b/pkg/apis/options/providers.go @@ -149,6 +149,7 @@ type KeycloakOptions struct { // Role enables to restrict login to users with role (only available when using the keycloak-oidc provider) Roles []string `json:"roles,omitempty"` + ACRs string `json:"acr,omitempty"` } type AzureOptions struct { diff --git a/pkg/apis/sessions/session_state.go b/pkg/apis/sessions/session_state.go index b5e4fc83..75c24a07 100644 --- a/pkg/apis/sessions/session_state.go +++ b/pkg/apis/sessions/session_state.go @@ -28,6 +28,7 @@ type SessionState struct { User string `msgpack:"u,omitempty"` Groups []string `msgpack:"g,omitempty"` PreferredUsername string `msgpack:"pu,omitempty"` + Acr string `msgpack:"acr,omitempty"` // Internal helpers, not serialized Clock clock.Clock `msgpack:"-"` @@ -148,6 +149,8 @@ func (s *SessionState) GetClaim(claim string) []string { return groups case "preferred_username": return []string{s.PreferredUsername} + case "acr": + return []string{s.Acr} default: return []string{} } diff --git a/providers/keycloak.go b/providers/keycloak.go index e36068c4..cc2f1bc9 100644 --- a/providers/keycloak.go +++ b/providers/keycloak.go @@ -61,6 +61,7 @@ func NewKeycloakProvider(p *ProviderData, opts options.KeycloakOptions) *Keycloa provider := &KeycloakProvider{ProviderData: p} provider.setAllowedGroups(opts.Groups) + provider.setAllowedACR(opts.ACRs) return provider } diff --git a/providers/keycloak_oidc.go b/providers/keycloak_oidc.go index ab613752..353d0748 100644 --- a/providers/keycloak_oidc.go +++ b/providers/keycloak_oidc.go @@ -26,6 +26,7 @@ func NewKeycloakOIDCProvider(p *ProviderData, opts options.Provider) *KeycloakOI } provider.addAllowedRoles(opts.KeycloakConfig.Roles) + provider.setAllowedACR(opts.KeycloakConfig.ACRs) return provider } diff --git a/providers/provider_data.go b/providers/provider_data.go index 3c59c6da..e6c3c126 100644 --- a/providers/provider_data.go +++ b/providers/provider_data.go @@ -53,6 +53,7 @@ type ProviderData struct { // Universal Group authorization data structure // any provider can set to consume AllowedGroups map[string]struct{} + AllowedACRs map[string]struct{} getAuthorizationHeaderFunc func(string) http.Header loginURLParameterDefaults url.Values @@ -181,6 +182,14 @@ func (p *ProviderData) setAllowedGroups(groups []string) { } } +func (p *ProviderData) setAllowedACR(acrs string) { + p.AllowedACRs = make(map[string]struct{}) + var resultingACRs = strings.Split(acrs, ",") + for _, acr := range resultingACRs { + p.AllowedACRs[acr] = struct{}{} + } +} + type providerDefaults struct { name string loginURL *url.URL @@ -258,6 +267,7 @@ func (p *ProviderData) buildSessionFromClaims(rawIDToken, accessToken string) (* {p.UserClaim, &ss.User}, {p.EmailClaim, &ss.Email}, {p.GroupsClaim, &ss.Groups}, + {"acr", &ss.Acr}, // TODO (@NickMeves) Deprecate for dynamic claim to session mapping {"preferred_username", &ss.PreferredUsername}, } { diff --git a/providers/provider_default.go b/providers/provider_default.go index 756b5f69..53008a33 100644 --- a/providers/provider_default.go +++ b/providers/provider_default.go @@ -3,6 +3,7 @@ package providers import ( "bytes" "context" + "encoding/json" "errors" "fmt" "net/url" @@ -116,6 +117,16 @@ func (p *ProviderData) EnrichSession(_ context.Context, _ *sessions.SessionState // Authorize performs global authorization on an authenticated session. // This is not used for fine-grained per route authorization rules. func (p *ProviderData) Authorize(_ context.Context, s *sessions.SessionState) (bool, error) { + println("ACR level is", s.Acr) + bs, _ := json.Marshal(p.AllowedACRs) + fmt.Println("Current configured acr is", string(bs)) + if len(p.AllowedACRs) > 0 { + var _, ok = p.AllowedACRs[s.Acr] + if !ok { + return false, nil + } + } + if len(p.AllowedGroups) == 0 { return true, nil }