security: GHSA-gq2m-77hf-vwgh (MODERATE) Session Fixation: Logout Fails to Invalidate Server-Side Session
This commit is contained in:
parent
235493e471
commit
d6a0abc375
|
|
@ -392,6 +392,8 @@ func (api *oliveTinAPI) ExecutionStatus(ctx ctx.Context, req *connect.Request[ap
|
||||||
func (api *oliveTinAPI) Logout(ctx ctx.Context, req *connect.Request[apiv1.LogoutRequest]) (*connect.Response[apiv1.LogoutResponse], error) {
|
func (api *oliveTinAPI) Logout(ctx ctx.Context, req *connect.Request[apiv1.LogoutRequest]) (*connect.Response[apiv1.LogoutResponse], error) {
|
||||||
user := auth.UserFromApiCall(ctx, req, api.cfg)
|
user := auth.UserFromApiCall(ctx, req, api.cfg)
|
||||||
|
|
||||||
|
auth.RevokeSessionForProvider(api.cfg, user.Provider, user.SID)
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"username": user.Username,
|
"username": user.Username,
|
||||||
"provider": user.Provider,
|
"provider": user.Provider,
|
||||||
|
|
|
||||||
|
|
@ -391,6 +391,12 @@ func (h *OAuth2Handler) lookupOAuth2UserByState(state string) (*authTypes.Authen
|
||||||
return user, true
|
return user, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *OAuth2Handler) RevokeSession(sid string) {
|
||||||
|
h.mu.Lock()
|
||||||
|
defer h.mu.Unlock()
|
||||||
|
delete(h.registeredStates, sid)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *OAuth2Handler) CheckUserFromOAuth2Cookie(context *authTypes.AuthCheckingContext) *authTypes.AuthenticatedUser {
|
func (h *OAuth2Handler) CheckUserFromOAuth2Cookie(context *authTypes.AuthCheckingContext) *authTypes.AuthenticatedUser {
|
||||||
cookie, err := context.Request.Cookie("olivetin-sid-oauth")
|
cookie, err := context.Request.Cookie("olivetin-sid-oauth")
|
||||||
if err != nil || cookie.Value == "" {
|
if err != nil || cookie.Value == "" {
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,9 @@ type SessionStorage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
sessionStorage *SessionStorage
|
sessionStorage *SessionStorage
|
||||||
sessionStorageMutex sync.RWMutex
|
sessionStorageMutex sync.RWMutex
|
||||||
|
oauth2SessionRevoker func(sid string)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -58,6 +59,38 @@ func RegisterUserSession(cfg *config.Config, provider string, sid string, userna
|
||||||
saveUserSessions(cfg)
|
saveUserSessions(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterOAuth2SessionRevoker registers a callback to revoke OAuth2 sessions on logout.
|
||||||
|
// OAuth2 uses its own session storage; the API calls this when provider is oauth2.
|
||||||
|
func RegisterOAuth2SessionRevoker(fn func(sid string)) {
|
||||||
|
oauth2SessionRevoker = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeSessionForProvider invalidates the session for the given provider and SID (e.g. on logout).
|
||||||
|
// Local auth uses shared SessionStorage; OAuth2 uses a separate storage and revoker.
|
||||||
|
func RevokeSessionForProvider(cfg *config.Config, provider string, sid string) {
|
||||||
|
if sid == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if provider == "oauth2" && oauth2SessionRevoker != nil {
|
||||||
|
oauth2SessionRevoker(sid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
RevokeUserSession(cfg, provider, sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeUserSession removes a session from storage so it can no longer be used (e.g. on logout).
|
||||||
|
func RevokeUserSession(cfg *config.Config, provider string, sid string) {
|
||||||
|
sessionStorageMutex.Lock()
|
||||||
|
defer sessionStorageMutex.Unlock()
|
||||||
|
|
||||||
|
if sessionStorage.Providers[provider] != nil {
|
||||||
|
delete(sessionStorage.Providers[provider].Sessions, sid)
|
||||||
|
if cfg != nil {
|
||||||
|
saveUserSessions(cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserSession retrieves a user session
|
// GetUserSession retrieves a user session
|
||||||
func GetUserSession(provider string, sid string) *UserSession {
|
func GetUserSession(provider string, sid string) *UserSession {
|
||||||
sessionStorageMutex.Lock()
|
sessionStorageMutex.Lock()
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ func StartFrontendMux(cfg *config.Config, ex *executor.Executor) {
|
||||||
|
|
||||||
oauth2handler := otoauth2.NewOAuth2Handler(cfg)
|
oauth2handler := otoauth2.NewOAuth2Handler(cfg)
|
||||||
auth.AddAuthChainFunction(oauth2handler.CheckUserFromOAuth2Cookie)
|
auth.AddAuthChainFunction(oauth2handler.CheckUserFromOAuth2Cookie)
|
||||||
|
auth.RegisterOAuth2SessionRevoker(oauth2handler.RevokeSession)
|
||||||
|
|
||||||
mux.HandleFunc("/oauth/login", oauth2handler.HandleOAuthLogin)
|
mux.HandleFunc("/oauth/login", oauth2handler.HandleOAuthLogin)
|
||||||
mux.HandleFunc("/oauth/callback", oauth2handler.HandleOAuthCallback)
|
mux.HandleFunc("/oauth/callback", oauth2handler.HandleOAuthCallback)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue