1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2025-08-08 22:46:33 +02:00

Rename Cookie Options to remove extra 'Cookie'

This commit is contained in:
Joel Speed
2020-04-12 14:00:59 +01:00
parent 842d764a5f
commit 458710149c
12 changed files with 175 additions and 154 deletions

View File

@ -4,13 +4,13 @@ import "time"
// CookieOptions contains configuration options relating to Cookie configuration
type CookieOptions struct {
CookieName string `flag:"cookie-name" cfg:"cookie_name" env:"OAUTH2_PROXY_COOKIE_NAME"`
CookieSecret string `flag:"cookie-secret" cfg:"cookie_secret" env:"OAUTH2_PROXY_COOKIE_SECRET"`
CookieDomains []string `flag:"cookie-domain" cfg:"cookie_domain" env:"OAUTH2_PROXY_COOKIE_DOMAIN"`
CookiePath string `flag:"cookie-path" cfg:"cookie_path" env:"OAUTH2_PROXY_COOKIE_PATH"`
CookieExpire time.Duration `flag:"cookie-expire" cfg:"cookie_expire" env:"OAUTH2_PROXY_COOKIE_EXPIRE"`
CookieRefresh time.Duration `flag:"cookie-refresh" cfg:"cookie_refresh" env:"OAUTH2_PROXY_COOKIE_REFRESH"`
CookieSecure bool `flag:"cookie-secure" cfg:"cookie_secure" env:"OAUTH2_PROXY_COOKIE_SECURE"`
CookieHTTPOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly" env:"OAUTH2_PROXY_COOKIE_HTTPONLY"`
CookieSameSite string `flag:"cookie-samesite" cfg:"cookie_samesite" env:"OAUTH2_PROXY_COOKIE_SAMESITE"`
Name string `flag:"cookie-name" cfg:"cookie_name" env:"OAUTH2_PROXY_COOKIE_NAME"`
Secret string `flag:"cookie-secret" cfg:"cookie_secret" env:"OAUTH2_PROXY_COOKIE_SECRET"`
Domains []string `flag:"cookie-domain" cfg:"cookie_domain" env:"OAUTH2_PROXY_COOKIE_DOMAIN"`
Path string `flag:"cookie-path" cfg:"cookie_path" env:"OAUTH2_PROXY_COOKIE_PATH"`
Expire time.Duration `flag:"cookie-expire" cfg:"cookie_expire" env:"OAUTH2_PROXY_COOKIE_EXPIRE"`
Refresh time.Duration `flag:"cookie-refresh" cfg:"cookie_refresh" env:"OAUTH2_PROXY_COOKIE_REFRESH"`
Secure bool `flag:"cookie-secure" cfg:"cookie_secure" env:"OAUTH2_PROXY_COOKIE_SECURE"`
HTTPOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly" env:"OAUTH2_PROXY_COOKIE_HTTPONLY"`
SameSite string `flag:"cookie-samesite" cfg:"cookie_samesite" env:"OAUTH2_PROXY_COOKIE_SAMESITE"`
}

View File

@ -38,19 +38,19 @@ func MakeCookie(req *http.Request, name string, value string, path string, domai
// MakeCookieFromOptions constructs a cookie based on the given *options.CookieOptions,
// value and creation time
func MakeCookieFromOptions(req *http.Request, name string, value string, opts *options.CookieOptions, expiration time.Duration, now time.Time) *http.Cookie {
domain := GetCookieDomain(req, opts.CookieDomains)
func MakeCookieFromOptions(req *http.Request, name string, value string, cookieOpts *options.CookieOptions, expiration time.Duration, now time.Time) *http.Cookie {
domain := GetCookieDomain(req, cookieOpts.Domains)
if domain != "" {
return MakeCookie(req, name, value, opts.CookiePath, domain, opts.CookieHTTPOnly, opts.CookieSecure, expiration, now, ParseSameSite(opts.CookieSameSite))
return MakeCookie(req, name, value, cookieOpts.Path, domain, cookieOpts.HTTPOnly, cookieOpts.Secure, expiration, now, ParseSameSite(cookieOpts.SameSite))
}
// If nothing matches, create the cookie with the shortest domain
logger.Printf("Warning: request host %q did not match any of the specific cookie domains of %q", GetRequestHost(req), strings.Join(opts.CookieDomains, ","))
logger.Printf("Warning: request host %q did not match any of the specific cookie domains of %q", GetRequestHost(req), strings.Join(cookieOpts.Domains, ","))
defaultDomain := ""
if len(opts.CookieDomains) > 0 {
defaultDomain = opts.CookieDomains[len(opts.CookieDomains)-1]
if len(cookieOpts.Domains) > 0 {
defaultDomain = cookieOpts.Domains[len(cookieOpts.Domains)-1]
}
return MakeCookie(req, name, value, opts.CookiePath, defaultDomain, opts.CookieHTTPOnly, opts.CookieSecure, expiration, now, ParseSameSite(opts.CookieSameSite))
return MakeCookie(req, name, value, cookieOpts.Path, defaultDomain, cookieOpts.HTTPOnly, cookieOpts.Secure, expiration, now, ParseSameSite(cookieOpts.SameSite))
}
// GetCookieDomain returns the correct cookie domain given a list of domains

View File

@ -49,12 +49,12 @@ func (s *SessionStore) Save(rw http.ResponseWriter, req *http.Request, ss *sessi
// Load reads sessions.SessionState information from Cookies within the
// HTTP request object
func (s *SessionStore) Load(req *http.Request) (*sessions.SessionState, error) {
c, err := loadCookie(req, s.CookieOptions.CookieName)
c, err := loadCookie(req, s.CookieOptions.Name)
if err != nil {
// always http.ErrNoCookie
return nil, fmt.Errorf("cookie %q not present", s.CookieOptions.CookieName)
return nil, fmt.Errorf("cookie %q not present", s.CookieOptions.Name)
}
val, _, ok := encryption.Validate(c, s.CookieOptions.CookieSecret, s.CookieOptions.CookieExpire)
val, _, ok := encryption.Validate(c, s.CookieOptions.Secret, s.CookieOptions.Expire)
if !ok {
return nil, errors.New("cookie signature not valid")
}
@ -70,7 +70,7 @@ func (s *SessionStore) Load(req *http.Request) (*sessions.SessionState, error) {
// clear the session
func (s *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) error {
// matches CookieName, CookieName_<number>
var cookieNameRegex = regexp.MustCompile(fmt.Sprintf("^%s(_\\d+)?$", s.CookieOptions.CookieName))
var cookieNameRegex = regexp.MustCompile(fmt.Sprintf("^%s(_\\d+)?$", s.CookieOptions.Name))
for _, c := range req.Cookies() {
if cookieNameRegex.MatchString(c.Name) {
@ -94,10 +94,10 @@ func (s *SessionStore) setSessionCookie(rw http.ResponseWriter, req *http.Reques
// authentication details
func (s *SessionStore) makeSessionCookie(req *http.Request, value string, now time.Time) []*http.Cookie {
if value != "" {
value = encryption.SignedValue(s.CookieOptions.CookieSecret, s.CookieOptions.CookieName, value, now)
value = encryption.SignedValue(s.CookieOptions.Secret, s.CookieOptions.Name, value, now)
}
c := s.makeCookie(req, s.CookieOptions.CookieName, value, s.CookieOptions.CookieExpire, now)
if len(c.Value) > 4096-len(s.CookieOptions.CookieName) {
c := s.makeCookie(req, s.CookieOptions.Name, value, s.CookieOptions.Expire, now)
if len(c.Value) > 4096-len(s.CookieOptions.Name) {
return splitCookie(c)
}
return []*http.Cookie{c}

View File

@ -117,13 +117,13 @@ func (store *SessionStore) Save(rw http.ResponseWriter, req *http.Request, s *se
// Old sessions that we are refreshing would have a request cookie
// New sessions don't, so we ignore the error. storeValue will check requestCookie
requestCookie, _ := req.Cookie(store.CookieOptions.CookieName)
requestCookie, _ := req.Cookie(store.CookieOptions.Name)
value, err := s.EncodeSessionState(store.CookieCipher)
if err != nil {
return err
}
ctx := req.Context()
ticketString, err := store.storeValue(ctx, value, store.CookieOptions.CookieExpire, requestCookie)
ticketString, err := store.storeValue(ctx, value, store.CookieOptions.Expire, requestCookie)
if err != nil {
return err
}
@ -131,7 +131,7 @@ func (store *SessionStore) Save(rw http.ResponseWriter, req *http.Request, s *se
ticketCookie := store.makeCookie(
req,
ticketString,
store.CookieOptions.CookieExpire,
store.CookieOptions.Expire,
s.CreatedAt,
)
@ -142,12 +142,12 @@ func (store *SessionStore) Save(rw http.ResponseWriter, req *http.Request, s *se
// Load reads sessions.SessionState information from a ticket
// cookie within the HTTP request object
func (store *SessionStore) Load(req *http.Request) (*sessions.SessionState, error) {
requestCookie, err := req.Cookie(store.CookieOptions.CookieName)
requestCookie, err := req.Cookie(store.CookieOptions.Name)
if err != nil {
return nil, fmt.Errorf("error loading session: %s", err)
}
val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.CookieSecret, store.CookieOptions.CookieExpire)
val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.Secret, store.CookieOptions.Expire)
if !ok {
return nil, fmt.Errorf("cookie signature not valid")
}
@ -161,12 +161,12 @@ func (store *SessionStore) Load(req *http.Request) (*sessions.SessionState, erro
// loadSessionFromString loads the session based on the ticket value
func (store *SessionStore) loadSessionFromString(ctx context.Context, value string) (*sessions.SessionState, error) {
ticket, err := decodeTicket(store.CookieOptions.CookieName, value)
ticket, err := decodeTicket(store.CookieOptions.Name, value)
if err != nil {
return nil, err
}
resultBytes, err := store.Client.Get(ctx, ticket.asHandle(store.CookieOptions.CookieName))
resultBytes, err := store.Client.Get(ctx, ticket.asHandle(store.CookieOptions.Name))
if err != nil {
return nil, err
}
@ -199,7 +199,7 @@ func (store *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) erro
http.SetCookie(rw, clearCookie)
// If there was an existing cookie we should clear the session in redis
requestCookie, err := req.Cookie(store.CookieOptions.CookieName)
requestCookie, err := req.Cookie(store.CookieOptions.Name)
if err != nil && err == http.ErrNoCookie {
// No existing cookie so can't clear redis
return nil
@ -207,17 +207,17 @@ func (store *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) erro
return fmt.Errorf("error retrieving cookie: %v", err)
}
val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.CookieSecret, store.CookieOptions.CookieExpire)
val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.Secret, store.CookieOptions.Expire)
if !ok {
return fmt.Errorf("cookie signature not valid")
}
// We only return an error if we had an issue with redis
// If there's an issue decoding the ticket, ignore it
ticket, _ := decodeTicket(store.CookieOptions.CookieName, val)
ticket, _ := decodeTicket(store.CookieOptions.Name, val)
if ticket != nil {
ctx := req.Context()
err := store.Client.Del(ctx, ticket.asHandle(store.CookieOptions.CookieName))
err := store.Client.Del(ctx, ticket.asHandle(store.CookieOptions.Name))
if err != nil {
return fmt.Errorf("error clearing cookie from redis: %s", err)
}
@ -228,11 +228,11 @@ func (store *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) erro
// makeCookie makes a cookie, signing the value if present
func (store *SessionStore) makeCookie(req *http.Request, value string, expires time.Duration, now time.Time) *http.Cookie {
if value != "" {
value = encryption.SignedValue(store.CookieOptions.CookieSecret, store.CookieOptions.CookieName, value, now)
value = encryption.SignedValue(store.CookieOptions.Secret, store.CookieOptions.Name, value, now)
}
return cookies.MakeCookieFromOptions(
req,
store.CookieOptions.CookieName,
store.CookieOptions.Name,
value,
store.CookieOptions,
expires,
@ -256,12 +256,12 @@ func (store *SessionStore) storeValue(ctx context.Context, value string, expirat
stream := cipher.NewCFBEncrypter(block, ticket.Secret)
stream.XORKeyStream(ciphertext, []byte(value))
handle := ticket.asHandle(store.CookieOptions.CookieName)
handle := ticket.asHandle(store.CookieOptions.Name)
err = store.Client.Set(ctx, handle, ciphertext, expiration)
if err != nil {
return "", err
}
return ticket.encodeTicket(store.CookieOptions.CookieName), nil
return ticket.encodeTicket(store.CookieOptions.Name), nil
}
// getTicket retrieves an existing ticket from the cookie if present,
@ -272,14 +272,14 @@ func (store *SessionStore) getTicket(requestCookie *http.Cookie) (*TicketData, e
}
// An existing cookie exists, try to retrieve the ticket
val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.CookieSecret, store.CookieOptions.CookieExpire)
val, _, ok := encryption.Validate(requestCookie, store.CookieOptions.Secret, store.CookieOptions.Expire)
if !ok {
// Cookie is invalid, create a new ticket
return newTicket()
}
// Valid cookie, decode the ticket
ticket, err := decodeTicket(store.CookieOptions.CookieName, val)
ticket, err := decodeTicket(store.CookieOptions.Name, val)
if err != nil {
// If we can't decode the ticket we have to create a new one
return newTicket()

View File

@ -47,25 +47,25 @@ var _ = Describe("NewSessionStore", func() {
It("have the correct name set", func() {
if len(cookies) == 1 {
Expect(cookies[0].Name).To(Equal(cookieOpts.CookieName))
Expect(cookies[0].Name).To(Equal(cookieOpts.Name))
} else {
for _, cookie := range cookies {
Expect(cookie.Name).To(ContainSubstring(cookieOpts.CookieName))
Expect(cookie.Name).To(ContainSubstring(cookieOpts.Name))
}
}
})
It("have the correct path set", func() {
for _, cookie := range cookies {
Expect(cookie.Path).To(Equal(cookieOpts.CookiePath))
Expect(cookie.Path).To(Equal(cookieOpts.Path))
}
})
It("have the correct domain set", func() {
for _, cookie := range cookies {
specifiedDomain := ""
if len(cookieOpts.CookieDomains) > 0 {
specifiedDomain = cookieOpts.CookieDomains[0]
if len(cookieOpts.Domains) > 0 {
specifiedDomain = cookieOpts.Domains[0]
}
Expect(cookie.Domain).To(Equal(specifiedDomain))
}
@ -73,19 +73,19 @@ var _ = Describe("NewSessionStore", func() {
It("have the correct HTTPOnly set", func() {
for _, cookie := range cookies {
Expect(cookie.HttpOnly).To(Equal(cookieOpts.CookieHTTPOnly))
Expect(cookie.HttpOnly).To(Equal(cookieOpts.HTTPOnly))
}
})
It("have the correct secure set", func() {
for _, cookie := range cookies {
Expect(cookie.Secure).To(Equal(cookieOpts.CookieSecure))
Expect(cookie.Secure).To(Equal(cookieOpts.Secure))
}
})
It("have the correct SameSite set", func() {
for _, cookie := range cookies {
Expect(cookie.SameSite).To(Equal(cookiesapi.ParseSameSite(cookieOpts.CookieSameSite)))
Expect(cookie.SameSite).To(Equal(cookiesapi.ParseSameSite(cookieOpts.SameSite)))
}
})
@ -168,8 +168,8 @@ var _ = Describe("NewSessionStore", func() {
BeforeEach(func() {
By("Using a valid cookie with a different providers session encoding")
broken := "BrokenSessionFromADifferentSessionImplementation"
value := encryption.SignedValue(cookieOpts.CookieSecret, cookieOpts.CookieName, broken, time.Now())
cookie := cookiesapi.MakeCookieFromOptions(request, cookieOpts.CookieName, value, cookieOpts, cookieOpts.CookieExpire, time.Now())
value := encryption.SignedValue(cookieOpts.Secret, cookieOpts.Name, broken, time.Now())
cookie := cookiesapi.MakeCookieFromOptions(request, cookieOpts.Name, value, cookieOpts, cookieOpts.Expire, time.Now())
request.AddCookie(cookie)
err := ss.Save(response, request, session)
@ -245,7 +245,7 @@ var _ = Describe("NewSessionStore", func() {
})
It("loads a session equal to the original session", func() {
if cookieOpts.CookieSecret == "" {
if cookieOpts.Secret == "" {
// Only Email and User stored in session when encrypted
Expect(loadedSession.Email).To(Equal(session.Email))
Expect(loadedSession.User).To(Equal(session.User))
@ -290,7 +290,7 @@ var _ = Describe("NewSessionStore", func() {
BeforeEach(func() {
switch ss.(type) {
case *redis.SessionStore:
mr.FastForward(cookieOpts.CookieRefresh + time.Minute)
mr.FastForward(cookieOpts.Refresh + time.Minute)
}
})
@ -304,7 +304,7 @@ var _ = Describe("NewSessionStore", func() {
BeforeEach(func() {
switch ss.(type) {
case *redis.SessionStore:
mr.FastForward(cookieOpts.CookieExpire + time.Minute)
mr.FastForward(cookieOpts.Expire + time.Minute)
}
loadedSession, err = ss.Load(request)
@ -341,14 +341,14 @@ var _ = Describe("NewSessionStore", func() {
Context("with non-default options", func() {
BeforeEach(func() {
cookieOpts = &options.CookieOptions{
CookieName: "_cookie_name",
CookiePath: "/path",
CookieExpire: time.Duration(72) * time.Hour,
CookieRefresh: time.Duration(2) * time.Hour,
CookieSecure: false,
CookieHTTPOnly: false,
CookieDomains: []string{"example.com"},
CookieSameSite: "strict",
Name: "_cookie_name",
Path: "/path",
Expire: time.Duration(72) * time.Hour,
Refresh: time.Duration(2) * time.Hour,
Secure: false,
HTTPOnly: false,
Domains: []string{"example.com"},
SameSite: "strict",
}
var err error
@ -364,8 +364,8 @@ var _ = Describe("NewSessionStore", func() {
secret := make([]byte, 32)
_, err := rand.Read(secret)
Expect(err).ToNot(HaveOccurred())
cookieOpts.CookieSecret = base64.URLEncoding.EncodeToString(secret)
cipher, err := encryption.NewCipher(utils.SecretBytes(cookieOpts.CookieSecret))
cookieOpts.Secret = base64.URLEncoding.EncodeToString(secret)
cipher, err := encryption.NewCipher(utils.SecretBytes(cookieOpts.Secret))
Expect(err).ToNot(HaveOccurred())
Expect(cipher).ToNot(BeNil())
opts.Cipher = cipher
@ -384,13 +384,13 @@ var _ = Describe("NewSessionStore", func() {
// Set default options in CookieOptions
cookieOpts = &options.CookieOptions{
CookieName: "_oauth2_proxy",
CookiePath: "/",
CookieExpire: time.Duration(168) * time.Hour,
CookieRefresh: time.Duration(1) * time.Hour,
CookieSecure: true,
CookieHTTPOnly: true,
CookieSameSite: "",
Name: "_oauth2_proxy",
Path: "/",
Expire: time.Duration(168) * time.Hour,
Refresh: time.Duration(1) * time.Hour,
Secure: true,
HTTPOnly: true,
SameSite: "",
}
session = &sessionsapi.SessionState{