@@ -3,6 +3,8 @@ package sessions
33import (
44 "fmt"
55 "net/http"
6+ "os"
7+ "strings"
68 "sync"
79
810 gorilla "github.com/gorilla/sessions"
@@ -16,6 +18,16 @@ type CombinedSessionStore struct {
1618 sessionLock sync.Mutex
1719}
1820
21+ type session struct {
22+ sessionToken * gorilla.Session
23+ refreshToken * gorilla.Session
24+ }
25+
26+ func SessionCookieName () string {
27+ podName , _ := os .LookupEnv ("POD_NAME" )
28+ return OpenshiftAccessTokenCookieName + "-" + podName
29+ }
30+
1931func NewSessionStore (authnKey , encryptKey []byte , secureCookies bool , cookiePath string ) * CombinedSessionStore {
2032 clientStore := gorilla .NewCookieStore (authnKey , encryptKey )
2133 clientStore .Options .Secure = secureCookies
@@ -39,11 +51,32 @@ func (cs *CombinedSessionStore) AddSession(w http.ResponseWriter, r *http.Reques
3951 return fmt .Errorf ("failed to add session to server store: %w" , err )
4052 }
4153
42- clientSession , _ := cs .clientStore . Get ( r , OpenshiftAccessTokenCookieName )
43- clientSession .Values ["session-token" ] = ls .sessionToken
44- clientSession .Values ["refresh-token" ] = ls .refreshToken
54+ clientSession := cs .getCookieSession ( r )
55+ clientSession .sessionToken . Values ["session-token" ] = ls .sessionToken
56+ clientSession .refreshToken . Values ["refresh-token" ] = ls .refreshToken
4557
46- return clientSession .Save (r , w )
58+ return clientSession .save (r , w )
59+ }
60+
61+ func (cs * CombinedSessionStore ) getCookieSession (r * http.Request ) * session {
62+ clientSession , _ := cs .clientStore .Get (r , SessionCookieName ())
63+ refreshSession , _ := cs .clientStore .Get (r , openshiftRefreshTokenCookieName )
64+ return & session {
65+ sessionToken : clientSession ,
66+ refreshToken : refreshSession ,
67+ }
68+ }
69+
70+ func (s * session ) save (r * http.Request , w http.ResponseWriter ) error {
71+ if err := s .sessionToken .Save (r , w ); err != nil {
72+ return fmt .Errorf ("failed to save session token cookie: %w" , err )
73+ }
74+
75+ if err := s .refreshToken .Save (r , w ); err != nil {
76+ return fmt .Errorf ("failed to save refresh token cookie: %w" , err )
77+ }
78+
79+ return nil
4780}
4881
4982// GetSession returns a session identified by the cookie from the current request.
@@ -53,33 +86,23 @@ func (cs *CombinedSessionStore) GetSession(w http.ResponseWriter, r *http.Reques
5386 defer cs .sessionLock .Unlock ()
5487
5588 // Get always returns a session, even if empty.
56- clientSession , _ := cs .clientStore . Get ( r , OpenshiftAccessTokenCookieName )
89+ clientSession := cs .getCookieSession ( r )
5790
58- // TODO: what happens if session-token is set by another instance and we get here?
59- // Will we loop in redirects forever since it's set but we don't know anything about that session
60- // and so we redirect back to login, which sees session token exists?
6191 var sessionToken , refreshToken string
62- if sessionTokenIface , ok := clientSession .Values ["session-token" ]; ok { // FIXME: allow for multiple session tokens, add pruning
92+ if sessionTokenIface , ok := clientSession .sessionToken . Values ["session-token" ]; ok {
6393 sessionToken = sessionTokenIface .(string )
6494 }
65- if refreshTokenIface , ok := clientSession .Values ["refresh-token" ]; ok {
95+ if refreshTokenIface , ok := clientSession .refreshToken . Values ["refresh-token" ]; ok {
6696 refreshToken = refreshTokenIface .(string )
6797 }
6898
6999 loginState := cs .serverStore .GetSession (sessionToken , refreshToken )
70- if loginState == nil {
71- // // the session-token was created by someone else (or it was pruned), we need to get our own server session
72- // clientSession.Values["session-token"] = "" // FIXME: wrong for non-sticky sessions but should be ok for PoC
73- // clientSession.Save(r, w)
74- return nil , nil
75- }
76-
77100 return loginState , nil
78101}
79102
80103func (cs * CombinedSessionStore ) GetCookieRefreshToken (r * http.Request ) string {
81104 // Get always returns a session, even if empty.
82- clientSession , _ := cs .clientStore .Get (r , OpenshiftAccessTokenCookieName )
105+ clientSession , _ := cs .clientStore .Get (r , openshiftRefreshTokenCookieName )
83106 if refreshToken , ok := clientSession .Values ["refresh-token" ].(string ); ok {
84107 return refreshToken
85108 }
@@ -88,7 +111,7 @@ func (cs *CombinedSessionStore) GetCookieRefreshToken(r *http.Request) string {
88111
89112func (cs * CombinedSessionStore ) UpdateCookieRefreshToken (w http.ResponseWriter , r * http.Request , refreshToken string ) error {
90113 // no need to lock here since there shouldn't be any races around the client session
91- clientSession , _ := cs .clientStore .Get (r , OpenshiftAccessTokenCookieName )
114+ clientSession , _ := cs .clientStore .Get (r , openshiftRefreshTokenCookieName )
92115 clientSession .Values ["refresh-token" ] = refreshToken
93116 return clientSession .Save (r , w )
94117}
@@ -97,18 +120,18 @@ func (cs *CombinedSessionStore) UpdateTokens(w http.ResponseWriter, r *http.Requ
97120 cs .sessionLock .Lock ()
98121 defer cs .sessionLock .Unlock ()
99122
100- clientSession , _ := cs .clientStore . Get ( r , OpenshiftAccessTokenCookieName )
123+ clientSession := cs .getCookieSession ( r )
101124 var oldRefreshToken string
102- if oldToken , ok := clientSession .Values ["refresh-token" ]; ok {
125+ if oldToken , ok := clientSession .refreshToken . Values ["refresh-token" ]; ok {
103126 oldRefreshToken = oldToken .(string )
104127 }
105128
106129 refreshToken := tokenResponse .RefreshToken
107- clientSession .Values ["refresh-token" ] = refreshToken
130+ clientSession .refreshToken . Values ["refresh-token" ] = refreshToken
108131
109132 var loginState * LoginState
110- sessionToken , ok := clientSession .Values ["session-token" ]
111- if ok { // TODO: since we only have a single session token in the cookie, we need to check that the session was actually created by us or not
133+ sessionToken , ok := clientSession .sessionToken . Values ["session-token" ]
134+ if ok {
112135 loginState = cs .serverStore .GetSession (sessionToken .(string ), "" )
113136 }
114137 if loginState == nil {
@@ -122,7 +145,7 @@ func (cs *CombinedSessionStore) UpdateTokens(w http.ResponseWriter, r *http.Requ
122145 return nil , fmt .Errorf ("failed to add session to server store: %w" , err )
123146 }
124147 cs .serverStore .byRefreshToken [oldRefreshToken ] = loginState
125- clientSession .Values ["session-token" ] = loginState .sessionToken
148+ clientSession .sessionToken . Values ["session-token" ] = loginState .sessionToken
126149 } else {
127150 if err := loginState .UpdateTokens (tokenVerifier , tokenResponse ); err != nil {
128151 return nil , err
@@ -132,21 +155,23 @@ func (cs *CombinedSessionStore) UpdateTokens(w http.ResponseWriter, r *http.Requ
132155
133156 }
134157
135- return loginState , clientSession .Save (r , w )
136- }
137-
138- func (cs * CombinedSessionStore ) deleteSession (w http.ResponseWriter , r * http.Request , sessionToken string ) error {
139- clientSession , _ := cs .clientStore .Get (r , OpenshiftAccessTokenCookieName )
140- delete (clientSession .Values , "session-token" )
141- clientSession .Save (r , w )
142- return cs .serverStore .DeleteSession (sessionToken )
158+ return loginState , clientSession .save (r , w )
143159}
144160
145161func (cs * CombinedSessionStore ) DeleteSession (w http.ResponseWriter , r * http.Request , sessionToken string ) error {
146162 cs .sessionLock .Lock ()
147163 defer cs .sessionLock .Unlock ()
148164
149- return cs .deleteSession (w , r , sessionToken )
165+ for _ , cookie := range r .Cookies () {
166+ if strings .HasPrefix (cookie .Name , OpenshiftAccessTokenCookieName ) {
167+ cookie .MaxAge = - 1
168+ http .SetCookie (w , cookie )
169+ }
170+ }
171+
172+ refreshTokenCookie , _ := cs .clientStore .Get (r , openshiftRefreshTokenCookieName )
173+ refreshTokenCookie .Options .MaxAge = - 1
174+ return cs .clientStore .Save (r , w , refreshTokenCookie )
150175}
151176
152177// FIXME: do this regulary in a separate goroutine on background
0 commit comments