@@ -10,15 +10,16 @@ import (
11 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
11 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
12 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
12 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
13− "github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
13+ pkgcookies "github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
14 "github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
14 "github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
15 "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
15 "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
19− // Cookies are limited to 4kb including the length of the cookie name,
19+ // Cookies are limited to 4kb for all parts
20− // the cookie name can be up to 256 bytes
20+ // including the cookie name, value, attributes; IE (http.cookie).String()
21+ // Most browsers' max is 4096 -- but we give ourselves some leeway
21− maxCookieLength = 3840
22+ maxCookieLength = 4000
24// Ensure CookieSessionStore implements the interface
25// Ensure CookieSessionStore implements the interface
@@ -107,14 +108,15 @@ func (s *SessionStore) makeSessionCookie(req *http.Request, value string, now ti
107 value = encryption.SignedValue(s.CookieOptions.Secret, s.CookieOptions.Name, []byte(value), now)
108 value = encryption.SignedValue(s.CookieOptions.Secret, s.CookieOptions.Name, []byte(value), now)
109 c := s.makeCookie(req, s.CookieOptions.Name, value, s.CookieOptions.Expire, now)
110 c := s.makeCookie(req, s.CookieOptions.Name, value, s.CookieOptions.Expire, now)
110− if len(c.Value) > 4096-len(s.CookieOptions.Name) {
111+
112+ if len(c.String()) > maxCookieLength {
111 return splitCookie(c)
113 return splitCookie(c)
113 return []*http.Cookie{c}
115 return []*http.Cookie{c}
116func (s *SessionStore) makeCookie(req *http.Request, name string, value string, expiration time.Duration, now time.Time) *http.Cookie {
118func (s *SessionStore) makeCookie(req *http.Request, name string, value string, expiration time.Duration, now time.Time) *http.Cookie {
117− return cookies.MakeCookieFromOptions(
119+ return pkgcookies.MakeCookieFromOptions(
@@ -142,23 +144,30 @@ func NewCookieSessionStore(opts *options.SessionOptions, cookieOpts *options.Coo
142// it into a slice of cookies which fit within the 4kb cookie limit indexing
144// it into a slice of cookies which fit within the 4kb cookie limit indexing
143// the cookies from 0
145// the cookies from 0
144func splitCookie(c *http.Cookie) []*http.Cookie {
146func splitCookie(c *http.Cookie) []*http.Cookie {
145− logger.Printf("WARNING: Multiple cookies are required for this session as it exceeds the 4kb cookie limit. Please use server side session storage (eg. Redis) instead.")
146− if len(c.Value) < maxCookieLength {
147+ if len(c.String()) < maxCookieLength {
147 return []*http.Cookie{c}
148 return []*http.Cookie{c}
151+ logger.Printf("WARNING: Multiple cookies are required for this session as it exceeds the 4kb cookie limit. Please use server side session storage (eg. Redis) instead.")
149 cookies := []*http.Cookie{}
153 cookies := []*http.Cookie{}
150 valueBytes := []byte(c.Value)
154 valueBytes := []byte(c.Value)
151 count := 0
155 count := 0
152 for len(valueBytes) > 0 {
156 for len(valueBytes) > 0 {
153 newCookie := copyCookie(c)
157 newCookie := copyCookie(c)
154− newCookie.Name = fmt.Sprintf("%s_%d", c.Name, count)
158+ newCookie.Name = splitCookieName(c.Name, count)
161+ newCookie.Value = string(valueBytes)
162+ cookieLength := len(newCookie.String())
156− if len(valueBytes) < maxCookieLength {
163+ if cookieLength <= maxCookieLength {
157− newCookie.Value = string(valueBytes)
158 valueBytes = []byte{}
164 valueBytes = []byte{}
166+ overflow := cookieLength - maxCookieLength
167+ valueSize := len(valueBytes) - overflow
160− newValue := valueBytes[:maxCookieLength]
169+ newValue := valueBytes[:valueSize]
161− valueBytes = valueBytes[maxCookieLength:]
170+ valueBytes = valueBytes[valueSize:]
162 newCookie.Value = string(newValue)
171 newCookie.Value = string(newValue)
164 cookies = append(cookies, newCookie)
173 cookies = append(cookies, newCookie)
@@ -166,6 +175,15 @@ func splitCookie(c *http.Cookie) []*http.Cookie {
166 return cookies
175 return cookies
178+func splitCookieName(name string, count int) string {
179+ splitName := fmt.Sprintf("%s_%d", name, count)
180+ overflow := len(splitName) - 256
182+ splitName = fmt.Sprintf("%s_%d", name[:len(name)-overflow], count)
169// loadCookie retreieves the sessions state cookie from the http request.
187// loadCookie retreieves the sessions state cookie from the http request.
170// If a single cookie is present this will be returned, otherwise it attempts
188// If a single cookie is present this will be returned, otherwise it attempts
171// to reconstruct a cookie split up by splitCookie
189// to reconstruct a cookie split up by splitCookie
@@ -179,7 +197,7 @@ func loadCookie(req *http.Request, cookieName string) (*http.Cookie, error) {
179 count := 0
197 count := 0
180 for err == nil {
198 for err == nil {
181 var c *http.Cookie
199 var c *http.Cookie
182− c, err = req.Cookie(fmt.Sprintf("%s_%d", cookieName, count))
200+ c, err = req.Cookie(splitCookieName(cookieName, count))
183 if err == nil {
201 if err == nil {
184 cookies = append(cookies, c)
202 cookies = append(cookies, c)