mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-12 04:04:26 +00:00
R55: blacklist session tokens on user logout
This commit is contained in:
+12
@@ -380,6 +380,8 @@ func (t *TraefikOidc) handleLogout(rw http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
idToken := session.GetIDToken()
|
idToken := session.GetIDToken()
|
||||||
|
accessToken := session.GetAccessToken()
|
||||||
|
refreshToken := session.GetRefreshToken()
|
||||||
|
|
||||||
if err := session.Clear(req, rw); err != nil {
|
if err := session.Clear(req, rw); err != nil {
|
||||||
t.logger.Errorf("Error clearing session: %v", err)
|
t.logger.Errorf("Error clearing session: %v", err)
|
||||||
@@ -387,6 +389,16 @@ func (t *TraefikOidc) handleLogout(rw http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Blacklist the session's tokens so a token captured before logout (e.g. a
|
||||||
|
// bearer mode access token) cannot be reused until its natural expiry.
|
||||||
|
// RevokeToken is a no-op-safe local blacklist (guards nil) and skips
|
||||||
|
// empty values.
|
||||||
|
for _, tok := range []string{accessToken, idToken, refreshToken} {
|
||||||
|
if tok != "" {
|
||||||
|
t.RevokeToken(tok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
host := utils.DetermineHost(req)
|
host := utils.DetermineHost(req)
|
||||||
scheme := utils.DetermineScheme(req, t.forceHTTPS)
|
scheme := utils.DetermineScheme(req, t.forceHTTPS)
|
||||||
baseURL := fmt.Sprintf("%s://%s", scheme, host)
|
baseURL := fmt.Sprintf("%s://%s", scheme, host)
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package traefikoidc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Review regression: RP user logout must blacklist the session's tokens so a
|
||||||
|
// token captured before logout (e.g. a bearer-mode access token) cannot be
|
||||||
|
// reused until its natural expiry. Registers the OIDC end-session endpoint
|
||||||
|
// so logout completes, then checks the token blacklist was populated.
|
||||||
|
func TestLogoutBlacklistsSessionTokens(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
logger := NewLogger("info")
|
||||||
|
sessionManager, _ := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", 0, logger)
|
||||||
|
tOidc := &TraefikOidc{
|
||||||
|
endSessionURL: "", // no provider end-session -> local redirect path
|
||||||
|
logger: logger,
|
||||||
|
tokenBlacklist: NewCache(), // generic cache used as the blacklist
|
||||||
|
httpClient: &http.Client{},
|
||||||
|
clientID: "test-client-id",
|
||||||
|
audience: "test-client-id",
|
||||||
|
clientSecret: "test-client-secret",
|
||||||
|
tokenCache: NewTokenCache(),
|
||||||
|
forceHTTPS: false,
|
||||||
|
sessionManager: sessionManager,
|
||||||
|
}
|
||||||
|
|
||||||
|
req := httptest.NewRequest("GET", "/logout", nil)
|
||||||
|
req.Header.Set("Host", "test-host")
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
|
||||||
|
session, err := sessionManager.GetSession(req)
|
||||||
|
require.NoError(err)
|
||||||
|
session.SetAuthenticated(true)
|
||||||
|
session.SetAccessToken(ValidAccessToken)
|
||||||
|
session.SetIDToken(ValidIDToken)
|
||||||
|
session.SetRefreshToken(ValidRefreshToken)
|
||||||
|
require.NoError(session.Save(req, rr))
|
||||||
|
for _, cookie := range rr.Result().Cookies() {
|
||||||
|
req.AddCookie(cookie)
|
||||||
|
}
|
||||||
|
rr = httptest.NewRecorder()
|
||||||
|
|
||||||
|
tOidc.handleLogout(rr, req)
|
||||||
|
require.Equal(http.StatusFound, rr.Code, "logout should redirect")
|
||||||
|
|
||||||
|
// The access token (and the others) must now be blacklisted so a captured
|
||||||
|
// copy cannot be reused after logout.
|
||||||
|
for _, tok := range []string{ValidAccessToken, ValidIDToken, ValidRefreshToken} {
|
||||||
|
if _, found := tOidc.tokenBlacklist.Get(tok); !found {
|
||||||
|
t.Errorf("token %q must be blacklisted after logout", tok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user