git.iko.soy/typeable/oauth2-proxy
on master help sign in
Drop support for pre v3.1 cookies (#535)

Co-authored-by: Henry Jenkins <henry@henryjenkins.name>

commitde280824de5e9025d7e319e6e0c77f30a84c2b96 authorJoel Speed <Joel.speed@hotmail.co.uk> dateSun 10 May 2020, 10:09 (6 years ago) parent24cdfa6
3 files changed+20−119
CHANGELOG.md+4 pkg/apis/sessions/session_state.go+16−74 pkg/apis/sessions/session_state_test.go−45
CHANGELOG.md+4
@@ -22,9 +22,13 @@
2222- [#487](https://github.com/oauth2-proxy/oauth2-proxy/pull/487) Switch flags to StringSlice instead of StringArray
2323 - Options that take multiple arguments now split strings on commas if present
2424 - Eg `--foo=a,b,c,d` would result in the values `a`, `b`, `c` and `d` instead of a single `a,b,c,d` value as before
25+- [#535](https://github.com/oauth2-proxy/oauth2-proxy/pull/535) Drop support for pre v3.1 cookies
26+ - The encoding for session cookies was changed starting in v3.1.0, support for the previous encoding is now dropped
27+ - If you are upgrading from a version earlier than this, please upgrade via a version between v3.1.0 and v5.1.1
2528
2629## Changes since v5.1.1
2730
31+- [#535](https://github.com/oauth2-proxy/oauth2-proxy/pull/535) Drop support for pre v3.1 cookies (@JoelSpeed)
2832- [#533](https://github.com/oauth2-proxy/oauth2-proxy/pull/487) Set up code coverage within Travis for Code Climate (@JoelSpeed)
2933- [#514](https://github.com/oauth2-proxy/oauth2-proxy/pull/514) Add basic string functions to templates
3034- [#524](https://github.com/oauth2-proxy/oauth2-proxy/pull/524) Sign cookies with SHA256 (@NickMeves)
pkg/apis/sessions/session_state.go+16−74
@@ -2,9 +2,8 @@ package sessions
22
33import (
44 "encoding/json"
5+ "errors"
56 "fmt"
6− "strconv"
7− "strings"
87 "time"
98
109 "github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
@@ -126,84 +125,27 @@ func (s *SessionState) EncodeSessionState(c *encryption.Cipher) (string, error)
126125 return string(b), err
127126}
128127
129−// legacyDecodeSessionStatePlain decodes older plain session state string
130−func legacyDecodeSessionStatePlain(v string) (*SessionState, error) {
131− chunks := strings.Split(v, " ")
132− if len(chunks) != 2 {
133− return nil, fmt.Errorf("invalid session state (legacy: expected 2 chunks for user/email got %d)", len(chunks))
134− }
135−
136− user := strings.TrimPrefix(chunks[1], "user:")
137− email := strings.TrimPrefix(chunks[0], "email:")
138−
139− return &SessionState{User: user, Email: email}, nil
140−}
141−
142−// legacyDecodeSessionState attempts to decode the session state string
143−// generated by v3.1.0 or older
144−func legacyDecodeSessionState(v string, c *encryption.Cipher) (*SessionState, error) {
145− chunks := strings.Split(v, "|")
146−
147− if c == nil {
148− if len(chunks) != 1 {
149− return nil, fmt.Errorf("invalid session state (legacy: expected 1 chunk for plain got %d)", len(chunks))
150− }
151− return legacyDecodeSessionStatePlain(chunks[0])
152− }
153−
154− if len(chunks) != 4 && len(chunks) != 5 {
155− return nil, fmt.Errorf("invalid session state (legacy: expected 4 or 5 chunks for full got %d)", len(chunks))
156− }
157−
158− i := 0
159− ss, err := legacyDecodeSessionStatePlain(chunks[i])
160− if err != nil {
161− return nil, err
162− }
163−
164− i++
165− ss.AccessToken = chunks[i]
166−
167− if len(chunks) == 5 {
168− // SessionState with IDToken in v3.1.0
169− i++
170− ss.IDToken = chunks[i]
171− }
172−
173− i++
174− ts, err := strconv.Atoi(chunks[i])
175− if err != nil {
176− return nil, fmt.Errorf("invalid session state (legacy: wrong expiration time: %s)", err)
177− }
178− ss.ExpiresOn = time.Unix(int64(ts), 0)
179−
180− i++
181− ss.RefreshToken = chunks[i]
182−
183− return ss, nil
184−}
185−
186128// DecodeSessionState decodes the session cookie string into a SessionState
187129func DecodeSessionState(v string, c *encryption.Cipher) (*SessionState, error) {
188130 var ssj SessionStateJSON
189131 var ss *SessionState
190132 err := json.Unmarshal([]byte(v), &ssj)
191− if err == nil && ssj.SessionState != nil {
192− // Extract SessionState and CreatedAt,ExpiresOn value from SessionStateJSON
193− ss = ssj.SessionState
194− if ssj.CreatedAt != nil {
195− ss.CreatedAt = *ssj.CreatedAt
196− }
197− if ssj.ExpiresOn != nil {
198− ss.ExpiresOn = *ssj.ExpiresOn
199− }
200− } else {
201− // Try to decode a legacy string when json.Unmarshal failed
202− ss, err = legacyDecodeSessionState(v, c)
203− if err != nil {
204− return nil, err
205− }
133+ if err != nil {
134+ return nil, fmt.Errorf("error unmarshalling session: %w", err)
135+ }
136+ if ssj.SessionState == nil {
137+ return nil, errors.New("expected session state to not be nil")
206138 }
139+
140+ // Extract SessionState and CreatedAt,ExpiresOn value from SessionStateJSON
141+ ss = ssj.SessionState
142+ if ssj.CreatedAt != nil {
143+ ss.CreatedAt = *ssj.CreatedAt
144+ }
145+ if ssj.ExpiresOn != nil {
146+ ss.ExpiresOn = *ssj.ExpiresOn
147+ }
148+
207149 if c == nil {
208150 // Load only Email and User when cipher is unavailable
209151 ss = &SessionState{
pkg/apis/sessions/session_state_test.go−45
@@ -211,7 +211,6 @@ func TestDecodeSessionState(t *testing.T) {
211211 e := time.Now().Add(time.Duration(1) * time.Hour)
212212 eJSON, _ := e.MarshalJSON()
213213 eString := string(eJSON)
214− eUnix := e.Unix()
215214
216215 c, err := encryption.NewCipher([]byte(secret))
217216 assert.NoError(t, err)
@@ -275,50 +274,6 @@ func TestDecodeSessionState(t *testing.T) {
275274 Cipher: c,
276275 Error: true,
277276 },
278− {
279− SessionState: sessions.SessionState{
280− User: "just-user",
281− Email: "user@domain.com",
282− },
283− Encoded: "email:user@domain.com user:just-user",
284− },
285− {
286− Encoded: "email:user@domain.com user:just-user||||",
287− Error: true,
288− },
289− {
290− Encoded: "email:user@domain.com user:just-user",
291− Cipher: c,
292− Error: true,
293− },
294− {
295− Encoded: "email:user@domain.com user:just-user|||99999999999999999999|",
296− Cipher: c,
297− Error: true,
298− },
299− {
300− SessionState: sessions.SessionState{
301− Email: "user@domain.com",
302− User: "just-user",
303− AccessToken: "token1234",
304− ExpiresOn: e,
305− RefreshToken: "refresh4321",
306− },
307− Encoded: fmt.Sprintf("email:user@domain.com user:just-user|I6s+ml+/MldBMgHIiC35BTKTh57skGX24w==|%d|qEX0x6RmASxo4dhlBG6YuRs9Syn/e9sHu/+K", eUnix),
308− Cipher: c,
309− },
310− {
311− SessionState: sessions.SessionState{
312− Email: "user@domain.com",
313− User: "just-user",
314− AccessToken: "token1234",
315− IDToken: "rawtoken1234",
316− ExpiresOn: e,
317− RefreshToken: "refresh4321",
318− },
319− Encoded: fmt.Sprintf("email:user@domain.com user:just-user|I6s+ml+/MldBMgHIiC35BTKTh57skGX24w==|xojNdyyjB1HgYWh6XMtXY/Ph5eCVxa1cNsklJw==|%d|qEX0x6RmASxo4dhlBG6YuRs9Syn/e9sHu/+K", eUnix),
320− Cipher: c,
321− },
322277 }
323278
324279 for i, tc := range testCases {