From 1102ad256c8d356e1e0815ed751b9d61ad5fd392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anderson=20Val=C3=A9rio?= Date: Wed, 7 May 2025 08:09:50 -0300 Subject: [PATCH] revoke access token on logout --- oauthproxy.go | 16 ++++++++++++++-- pics_oauthproxy.go | 22 +++++++++++++++++++++- pkg/apis/options/legacy_options.go | 3 +++ pkg/apis/options/providers.go | 3 +++ providers/provider_data.go | 1 + providers/providers.go | 1 + 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/oauthproxy.go b/oauthproxy.go index 5efbd4cf..1b76b18a 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -798,7 +798,6 @@ func (p *OAuthProxy) backendLogout(rw http.ResponseWriter, req *http.Request, si } providerData := p.provider.Data() - var resp *http.Response if signOutAllSessions { if providerData.BackendLogoutAllSessionsURL == "" { return @@ -815,6 +814,19 @@ func (p *OAuthProxy) backendLogout(rw http.ResponseWriter, req *http.Request, si } p.picsAuditClient.CreateSuccessfulLogoutAuditEntry(session, req.RequestURI, req.Header.Get("edisp-org-id")) } else { + if providerData.BackendRevokeAccessTokenURL != "" { + resp, err := PicsRevokeAcessToken(providerData.BackendRevokeAccessTokenURL, session.AccessToken, providerData.ClientID, providerData.ClientSecret) + if err != nil { + logger.Errorf("error while calling backend revoke access token: %v", err) + return + } + + if resp.StatusCode() != 200 { + logger.Errorf("error while calling backend revoke acess token url, returned error code %v", resp.StatusCode()) + } + p.picsAuditClient.CreateSuccessfulLogoutAuditEntry(session, req.RequestURI, req.Header.Get("edisp-org-id")) + } + if providerData.BackendLogoutURL == "" { return } @@ -822,7 +834,7 @@ func (p *OAuthProxy) backendLogout(rw http.ResponseWriter, req *http.Request, si backendLogoutURL := strings.ReplaceAll(providerData.BackendLogoutURL, "{id_token}", session.IDToken) // security exception because URL is dynamic ({id_token} replacement) but // base is not end-user provided but comes from configuration somewhat secure - resp, err = http.Get(backendLogoutURL) // #nosec G107 + resp, err := http.Get(backendLogoutURL) // #nosec G107 if err != nil { logger.Errorf("error while calling backend logout: %v", err) return diff --git a/pics_oauthproxy.go b/pics_oauthproxy.go index 2b39e834..9d9d9b78 100644 --- a/pics_oauthproxy.go +++ b/pics_oauthproxy.go @@ -29,12 +29,32 @@ func PicsSignOutAllSessions(backendLogoutAllSessionsURL string, introspectClaims Do() if resp.Error() != nil { - return nil, fmt.Errorf("error logging out from IAM: %v", err) + return nil, fmt.Errorf("error logging out from IAM: %v", resp.Error()) } return resp, err } +func PicsRevokeAcessToken(backendRevokeURL string, accessToken string, clientID string, clientSecret string) (resp requests.Result, err error) { + authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(clientID+":"+clientSecret)) + body := "token=" + accessToken + + resp = requests.New(backendRevokeURL). + WithMethod("POST"). + SetHeader("Authorization", authHeader). + SetHeader("api-version", "2"). + SetHeader("Content-Type", "application/x-www-form-urlencoded"). + SetHeader("Accept", "application/json"). + WithBody(strings.NewReader(body)). + Do() + + if resp.Error() != nil { + return nil, fmt.Errorf("error revoking access token: %v", resp.Error()) + } + + return resp, nil +} + func getUserID(introspectClaims string) (string, error) { decodedClaims, err := base64.StdEncoding.DecodeString(introspectClaims) if err != nil { diff --git a/pkg/apis/options/legacy_options.go b/pkg/apis/options/legacy_options.go index 8fc5110e..854bda8a 100644 --- a/pkg/apis/options/legacy_options.go +++ b/pkg/apis/options/legacy_options.go @@ -546,6 +546,7 @@ type LegacyProvider struct { BackendLogoutURL string `flag:"backend-logout-url" cfg:"backend_logout_url"` BackendLogoutAllSessionsURL string `flag:"backend-logout-all-sessions-url" cfg:"backend_logout_all_sessions_url"` + BackendRevokeAccessTokenURL string `flag:"backend-revoke-access-token-url" cfg:"backend_revoke_access_token_url"` AcrValues string `flag:"acr-values" cfg:"acr_values"` JWTKey string `flag:"jwt-key" cfg:"jwt_key"` @@ -616,6 +617,7 @@ func legacyProviderFlagSet() *pflag.FlagSet { flagSet.StringSlice("allowed-role", []string{}, "(keycloak-oidc) restrict logins to members of these roles (may be given multiple times)") flagSet.String("backend-logout-url", "", "url to perform a backend logout, {id_token} can be used as placeholder for the id_token") flagSet.String("backend-logout-all-sessions-url", "", "url to perform a backend logout, {user_id} can be used as placeholder for the user_id") + flagSet.String("backend-revoke-access-token-url", "", "url to perform a backend revoke access token") return flagSet } @@ -698,6 +700,7 @@ func (l *LegacyProvider) convert() (Providers, error) { BackendLogoutURL: l.BackendLogoutURL, BackendLogoutAllSessionsURL: l.BackendLogoutAllSessionsURL, + BackendRevokeAccessTokenURL: l.BackendRevokeAccessTokenURL, } // This part is out of the switch section for all providers that support OIDC diff --git a/pkg/apis/options/providers.go b/pkg/apis/options/providers.go index aefd3cc2..7fddf28c 100644 --- a/pkg/apis/options/providers.go +++ b/pkg/apis/options/providers.go @@ -91,6 +91,9 @@ type Provider struct { // URL to call to perform backend logout, `{user_id}` would be replaced by the actual `user_id` if available in the session IntrospectClaims BackendLogoutAllSessionsURL string `json:"backendLogoutAllSessionsURL"` + + // URL to call to perform backend revoke token + BackendRevokeAccessTokenURL string `json:"backendRevokeAccessTokenURL"` } // ProviderType is used to enumerate the different provider type options diff --git a/providers/provider_data.go b/providers/provider_data.go index 4744f674..68eb9027 100644 --- a/providers/provider_data.go +++ b/providers/provider_data.go @@ -62,6 +62,7 @@ type ProviderData struct { BackendLogoutURL string BackendLogoutAllSessionsURL string + BackendRevokeAccessTokenURL string } // Data returns the ProviderData diff --git a/providers/providers.go b/providers/providers.go index 1c950aaf..12fcfed6 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -164,6 +164,7 @@ func newProviderDataFromConfig(providerConfig options.Provider) (*ProviderData, p.BackendLogoutURL = providerConfig.BackendLogoutURL p.BackendLogoutAllSessionsURL = providerConfig.BackendLogoutAllSessionsURL + p.BackendRevokeAccessTokenURL = providerConfig.BackendRevokeAccessTokenURL return p, nil }