Flush al sessions in logout all
This commit is contained in:
parent
5a1d721a60
commit
c454e8d4d9
|
|
@ -564,6 +564,10 @@ func (p *OAuthProxy) ClearSessionCookie(rw http.ResponseWriter, req *http.Reques
|
|||
return p.sessionStore.Clear(rw, req)
|
||||
}
|
||||
|
||||
func (p *OAuthProxy) ClearAllSessions(req *http.Request, session *sessionsapi.SessionState) error {
|
||||
return p.sessionStore.ClearAll(req, session)
|
||||
}
|
||||
|
||||
// LoadCookiedSession reads the user's authentication details from the request
|
||||
func (p *OAuthProxy) LoadCookiedSession(req *http.Request) (*sessionsapi.SessionState, error) {
|
||||
return p.sessionStore.Load(req)
|
||||
|
|
@ -774,7 +778,14 @@ func (p *OAuthProxy) SignOut(rw http.ResponseWriter, req *http.Request, signOutA
|
|||
p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
session, err := p.getAuthenticatedSession(rw, req)
|
||||
if err != nil {
|
||||
logger.Errorf("Error clearing all sessions cookie: %v", err)
|
||||
}
|
||||
err = p.ClearSessionCookie(rw, req)
|
||||
if signOutAllSessions {
|
||||
err = p.ClearAllSessions(req, session)
|
||||
}
|
||||
if err != nil {
|
||||
logger.Errorf("Error clearing session cookie: %v", err)
|
||||
p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ type SessionStore interface {
|
|||
Save(rw http.ResponseWriter, req *http.Request, s *SessionState) error
|
||||
Load(req *http.Request) (*SessionState, error)
|
||||
Clear(rw http.ResponseWriter, req *http.Request) error
|
||||
ClearAll(req *http.Request, session *SessionState) error
|
||||
VerifyConnection(ctx context.Context) error
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,14 @@ func GenerateRandomASCIIString(length int) (string, error) {
|
|||
return string(b), nil
|
||||
}
|
||||
|
||||
// Encrypts a string with a secret using HMAC-SHA256 and returns a base64-encoded string.
|
||||
func EncryptStringWithSecret(input, secret string) string {
|
||||
mac := hmac.New(sha256.New, []byte(secret))
|
||||
mac.Write([]byte(input))
|
||||
sum := mac.Sum(nil)
|
||||
return base64.RawURLEncoding.EncodeToString(sum)
|
||||
}
|
||||
|
||||
func GenerateCodeChallenge(method, codeVerifier string) (string, error) {
|
||||
switch method {
|
||||
case CodeChallengeMethodPlain:
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ type SessionStore struct {
|
|||
Minimal bool
|
||||
}
|
||||
|
||||
// ClearAll implements sessions.SessionStore.
|
||||
func (s *SessionStore) ClearAll(req *http.Request, session *sessions.SessionState) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Save takes a sessions.SessionState and stores the information from it
|
||||
// within Cookies set on the HTTP response writer
|
||||
func (s *SessionStore) Save(rw http.ResponseWriter, req *http.Request, ss *sessions.SessionState) error {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ import (
|
|||
type Store interface {
|
||||
Save(context.Context, string, []byte, time.Duration) error
|
||||
Load(context.Context, string) ([]byte, error)
|
||||
LoadList(ctx context.Context, key string) ([]string, error)
|
||||
Clear(context.Context, string) error
|
||||
Lock(key string) sessions.Lock
|
||||
RPush(context.Context, string, string, time.Duration) error
|
||||
VerifyConnection(context.Context) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||
)
|
||||
|
||||
// Manager wraps a Store and handles the implementation details of the
|
||||
|
|
@ -42,9 +43,14 @@ func (m *Manager) Save(rw http.ResponseWriter, req *http.Request, s *sessions.Se
|
|||
}
|
||||
}
|
||||
|
||||
err = tckt.saveSession(s, func(key string, val []byte, exp time.Duration) error {
|
||||
return m.Store.Save(req.Context(), key, val, exp)
|
||||
})
|
||||
err = tckt.saveSession(
|
||||
s,
|
||||
func(key string, val []byte, exp time.Duration, s *sessions.SessionState) error {
|
||||
return m.Store.Save(req.Context(), key, val, exp)
|
||||
},
|
||||
func(key string, val string, exp time.Duration) error {
|
||||
return m.Store.RPush(req.Context(), key, val, exp)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -68,6 +74,30 @@ func (m *Manager) Load(req *http.Request) (*sessions.SessionState, error) {
|
|||
)
|
||||
}
|
||||
|
||||
// ClearAll implements sessions.SessionStore.
|
||||
func (m *Manager) ClearAll(req *http.Request, session *sessions.SessionState) error {
|
||||
ticket, _ := decodeTicketFromRequest(req, m.Options)
|
||||
sessionKey := encryption.EncryptStringWithSecret(session.User+session.Email, ticket.options.Secret)
|
||||
keys, err := m.Store.LoadList(req.Context(), sessionKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error decoding ticket to clear session: %v", err)
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
err = m.Store.Clear(req.Context(), key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error clearing session for key: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = m.Store.Clear(req.Context(), sessionKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error clearing sessions keys: %v", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Clear clears any saved session information for a given ticket cookie.
|
||||
// Then it clears all session data for that ticket in the Store.
|
||||
func (m *Manager) Clear(rw http.ResponseWriter, req *http.Request) error {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ import (
|
|||
|
||||
// saveFunc performs a persistent store's save functionality using
|
||||
// a key string, value []byte & (optional) expiration time.Duration
|
||||
type saveFunc func(string, []byte, time.Duration) error
|
||||
type saveFunc func(string, []byte, time.Duration, *sessions.SessionState) error
|
||||
|
||||
// saveUserStateFunc performs a persistent store's save functionality using
|
||||
// a key string, value []byte & (optional) expiration time.Duration
|
||||
type saverUserMapSessionFunc func(string, string, time.Duration) error
|
||||
|
||||
// loadFunc performs a load from a persistent store using a
|
||||
// string key and returning the stored value as []byte
|
||||
|
|
@ -157,7 +161,7 @@ func decodeTicketFromRequest(req *http.Request, cookieOpts *options.Cookie) (*ti
|
|||
|
||||
// saveSession encodes the SessionState with the ticket's secret and persists
|
||||
// it to disk via the passed saveFunc.
|
||||
func (t *ticket) saveSession(s *sessions.SessionState, saver saveFunc) error {
|
||||
func (t *ticket) saveSession(s *sessions.SessionState, saver saveFunc, saverUserMapSession saverUserMapSessionFunc) error {
|
||||
c, err := t.makeCipher()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -166,7 +170,10 @@ func (t *ticket) saveSession(s *sessions.SessionState, saver saveFunc) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to encode the session state with the ticket: %v", err)
|
||||
}
|
||||
return saver(t.id, ciphertext, t.options.Expire)
|
||||
|
||||
encodedUserState := encryption.EncryptStringWithSecret(s.User+s.Email, t.options.Secret)
|
||||
saverUserMapSession(encodedUserState, t.id, 2*time.Hour)
|
||||
return saver(t.id, ciphertext, t.options.Expire, s)
|
||||
}
|
||||
|
||||
// loadSession loads a session from the disk store via the passed loadFunc
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ import (
|
|||
type Client interface {
|
||||
Get(ctx context.Context, key string) ([]byte, error)
|
||||
Lock(key string) sessions.Lock
|
||||
Expire(ctx context.Context, key string, expiration time.Duration) error
|
||||
RPush(ctx context.Context, key string, value string) error
|
||||
LRange(ctx context.Context, key string) ([]string, error)
|
||||
Set(ctx context.Context, key string, value []byte, expiration time.Duration) error
|
||||
Del(ctx context.Context, key string) error
|
||||
Ping(ctx context.Context) error
|
||||
|
|
@ -29,6 +32,18 @@ func newClient(c *redis.Client) Client {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *client) Expire(ctx context.Context, key string, expiration time.Duration) error {
|
||||
return c.Client.Expire(ctx, key, expiration).Err()
|
||||
}
|
||||
|
||||
func (c *client) LRange(ctx context.Context, key string) ([]string, error) {
|
||||
return c.Client.LRange(ctx, key, 0, -1).Result()
|
||||
}
|
||||
|
||||
func (c *client) RPush(ctx context.Context, key string, value string) error {
|
||||
return c.Client.RPush(ctx, key, value).Err()
|
||||
}
|
||||
|
||||
func (c *client) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
return c.Client.Get(ctx, key).Bytes()
|
||||
}
|
||||
|
|
@ -61,6 +76,12 @@ func newClusterClient(c *redis.ClusterClient) Client {
|
|||
}
|
||||
}
|
||||
|
||||
// Expire implements Client.
|
||||
// Subtle: this method shadows the method (*ClusterClient).Expire of clusterClient.ClusterClient.
|
||||
func (c *clusterClient) Expire(ctx context.Context, key string, expiration time.Duration) error {
|
||||
return c.ClusterClient.Expire(ctx, key, expiration).Err()
|
||||
}
|
||||
|
||||
func (c *clusterClient) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
return c.ClusterClient.Get(ctx, key).Bytes()
|
||||
}
|
||||
|
|
@ -69,6 +90,14 @@ func (c *clusterClient) Set(ctx context.Context, key string, value []byte, expir
|
|||
return c.ClusterClient.Set(ctx, key, value, expiration).Err()
|
||||
}
|
||||
|
||||
func (c *clusterClient) RPush(ctx context.Context, key string, value string) error {
|
||||
return c.ClusterClient.RPush(ctx, key, value).Err()
|
||||
}
|
||||
|
||||
func (c *clusterClient) LRange(ctx context.Context, key string) ([]string, error) {
|
||||
return c.ClusterClient.LRange(ctx, key, 0, -1).Result()
|
||||
}
|
||||
|
||||
func (c *clusterClient) Del(ctx context.Context, key string) error {
|
||||
return c.ClusterClient.Del(ctx, key).Err()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,31 @@ func (store *SessionStore) Save(ctx context.Context, key string, value []byte, e
|
|||
return nil
|
||||
}
|
||||
|
||||
// Save takes a sessions.SessionState and stores the information from it
|
||||
// to redis, and adds a new persistence cookie on the HTTP response writer
|
||||
func (store *SessionStore) RPush(ctx context.Context, key string, value string, exp time.Duration) error {
|
||||
err := store.Client.RPush(ctx, key, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error appending redis session: %v", err)
|
||||
}
|
||||
|
||||
if exp > 0 {
|
||||
if err := store.Client.Expire(ctx, key, exp); err != nil {
|
||||
return fmt.Errorf("error settings expiration time on appending redis session: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadList reads a list of strings from Redis at the given key and returns.
|
||||
func (store *SessionStore) LoadList(ctx context.Context, key string) ([]string, error) {
|
||||
values, err := store.Client.LRange(ctx, key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading redis list: %v", err)
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// Load reads sessions.SessionState information from a persistence
|
||||
// cookie within the HTTP request object
|
||||
func (store *SessionStore) Load(ctx context.Context, key string) ([]byte, error) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue