mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-03-23 21:50:48 +02:00
Rename Cookie Options to remove extra 'Cookie'
This commit is contained in:
parent
842d764a5f
commit
458710149c
@ -11,14 +11,18 @@
|
|||||||
- Migration from Pusher to independent org may have introduced breaking changes for your environment.
|
- Migration from Pusher to independent org may have introduced breaking changes for your environment.
|
||||||
- See the changes listed below for PR [#464](https://github.com/oauth2-proxy/oauth2-proxy/pull/464) for full details
|
- See the changes listed below for PR [#464](https://github.com/oauth2-proxy/oauth2-proxy/pull/464) for full details
|
||||||
- Binaries renamed from `oauth2_proxy` to `oauth2-proxy`
|
- Binaries renamed from `oauth2_proxy` to `oauth2-proxy`
|
||||||
|
|
||||||
- [#440](https://github.com/oauth2-proxy/oauth2-proxy/pull/440) Switch Azure AD Graph API to Microsoft Graph API (@johejo)
|
- [#440](https://github.com/oauth2-proxy/oauth2-proxy/pull/440) Switch Azure AD Graph API to Microsoft Graph API (@johejo)
|
||||||
- The Azure AD Graph API has been [deprecated](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api) and is being replaced by the Microsoft Graph API.
|
- The Azure AD Graph API has been [deprecated](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api) and is being replaced by the Microsoft Graph API.
|
||||||
If your application relies on the access token being passed to it to access the Azure AD Graph API, you should migrate your application to use the Microsoft Graph API.
|
If your application relies on the access token being passed to it to access the Azure AD Graph API, you should migrate your application to use the Microsoft Graph API.
|
||||||
Existing behaviour can be retained by setting `-resource=https://graph.windows.net`.
|
Existing behaviour can be retained by setting `-resource=https://graph.windows.net`.
|
||||||
|
- [#484](https://github.com/oauth2-proxy/oauth2-proxy/pull/484) Configuration loading has been replaced with Viper and PFlag
|
||||||
|
- Flags now require a `--` prefix before the option
|
||||||
|
- Previously flags allowed either `-` or `--` to prefix the option name
|
||||||
|
- Eg `-provider` must now be `--provider`
|
||||||
|
|
||||||
## Changes since v5.1.0
|
## Changes since v5.1.0
|
||||||
|
|
||||||
|
- [#484](https://github.com/oauth2-proxy/oauth2-proxy/pull/484) Replace configuration loading with Viper (@JoelSpeed)
|
||||||
- [#499](https://github.com/oauth2-proxy/oauth2-proxy/pull/469) Add `-user-id-claim` to support generic claims in addition to email
|
- [#499](https://github.com/oauth2-proxy/oauth2-proxy/pull/469) Add `-user-id-claim` to support generic claims in addition to email
|
||||||
- [#486](https://github.com/oauth2-proxy/oauth2-proxy/pull/486) Add new linters (@johejo)
|
- [#486](https://github.com/oauth2-proxy/oauth2-proxy/pull/486) Add new linters (@johejo)
|
||||||
- [#440](https://github.com/oauth2-proxy/oauth2-proxy/pull/440) Switch Azure AD Graph API to Microsoft Graph API (@johejo)
|
- [#440](https://github.com/oauth2-proxy/oauth2-proxy/pull/440) Switch Azure AD Graph API to Microsoft Graph API (@johejo)
|
||||||
|
@ -31,7 +31,7 @@ func (cfg EnvOptions) LoadEnvForStruct(options interface{}) {
|
|||||||
field := typ.Field(i)
|
field := typ.Field(i)
|
||||||
fieldV := reflect.Indirect(val).Field(i)
|
fieldV := reflect.Indirect(val).Field(i)
|
||||||
|
|
||||||
if field.Type.Kind() == reflect.Struct && field.Anonymous {
|
if field.Type.Kind() == reflect.Struct {
|
||||||
cfg.LoadEnvForStruct(fieldV.Interface())
|
cfg.LoadEnvForStruct(fieldV.Interface())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,17 @@ import (
|
|||||||
type EnvTest struct {
|
type EnvTest struct {
|
||||||
TestField string `cfg:"target_field" env:"TEST_ENV_FIELD"`
|
TestField string `cfg:"target_field" env:"TEST_ENV_FIELD"`
|
||||||
EnvTestEmbed
|
EnvTestEmbed
|
||||||
|
Named EnvTestNamed
|
||||||
}
|
}
|
||||||
|
|
||||||
type EnvTestEmbed struct {
|
type EnvTestEmbed struct {
|
||||||
TestFieldEmbed string `cfg:"target_field_embed" env:"TEST_ENV_FIELD_EMBED"`
|
TestFieldEmbed string `cfg:"target_field_embed" env:"TEST_ENV_FIELD_EMBED"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EnvTestNamed struct {
|
||||||
|
TestFieldNamed string `cfg:"target_field_named" env:"TEST_ENV_FIELD_NAMED"`
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadEnvForStruct(t *testing.T) {
|
func TestLoadEnvForStruct(t *testing.T) {
|
||||||
|
|
||||||
cfg := make(proxy.EnvOptions)
|
cfg := make(proxy.EnvOptions)
|
||||||
@ -44,3 +49,16 @@ func TestLoadEnvForStructWithEmbeddedFields(t *testing.T) {
|
|||||||
v := cfg["target_field_embed"]
|
v := cfg["target_field_embed"]
|
||||||
assert.Equal(t, v, "1234abcd")
|
assert.Equal(t, v, "1234abcd")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadEnvForStructWithNamedStructFields(t *testing.T) {
|
||||||
|
cfg := make(proxy.EnvOptions)
|
||||||
|
cfg.LoadEnvForStruct(&EnvTest{})
|
||||||
|
|
||||||
|
_, ok := cfg["target_field_named"]
|
||||||
|
assert.Equal(t, ok, false)
|
||||||
|
|
||||||
|
os.Setenv("TEST_ENV_FIELD_NAMED", "1234abcd")
|
||||||
|
cfg.LoadEnvForStruct(&EnvTest{})
|
||||||
|
v := cfg["target_field_named"]
|
||||||
|
assert.Equal(t, v, "1234abcd")
|
||||||
|
}
|
||||||
|
@ -264,23 +264,23 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
|
|||||||
|
|
||||||
logger.Printf("OAuthProxy configured for %s Client ID: %s", opts.provider.Data().ProviderName, opts.ClientID)
|
logger.Printf("OAuthProxy configured for %s Client ID: %s", opts.provider.Data().ProviderName, opts.ClientID)
|
||||||
refresh := "disabled"
|
refresh := "disabled"
|
||||||
if opts.CookieRefresh != time.Duration(0) {
|
if opts.Cookie.Refresh != time.Duration(0) {
|
||||||
refresh = fmt.Sprintf("after %s", opts.CookieRefresh)
|
refresh = fmt.Sprintf("after %s", opts.Cookie.Refresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Printf("Cookie settings: name:%s secure(https):%v httponly:%v expiry:%s domains:%s path:%s samesite:%s refresh:%s", opts.CookieName, opts.CookieSecure, opts.CookieHTTPOnly, opts.CookieExpire, strings.Join(opts.CookieDomains, ","), opts.CookiePath, opts.CookieSameSite, refresh)
|
logger.Printf("Cookie settings: name:%s secure(https):%v httponly:%v expiry:%s domains:%s path:%s samesite:%s refresh:%s", opts.Cookie.Name, opts.Cookie.Secure, opts.Cookie.HTTPOnly, opts.Cookie.Expire, strings.Join(opts.Cookie.Domains, ","), opts.Cookie.Path, opts.Cookie.SameSite, refresh)
|
||||||
|
|
||||||
return &OAuthProxy{
|
return &OAuthProxy{
|
||||||
CookieName: opts.CookieName,
|
CookieName: opts.Cookie.Name,
|
||||||
CSRFCookieName: fmt.Sprintf("%v_%v", opts.CookieName, "csrf"),
|
CSRFCookieName: fmt.Sprintf("%v_%v", opts.Cookie.Name, "csrf"),
|
||||||
CookieSeed: opts.CookieSecret,
|
CookieSeed: opts.Cookie.Secret,
|
||||||
CookieDomains: opts.CookieDomains,
|
CookieDomains: opts.Cookie.Domains,
|
||||||
CookiePath: opts.CookiePath,
|
CookiePath: opts.Cookie.Path,
|
||||||
CookieSecure: opts.CookieSecure,
|
CookieSecure: opts.Cookie.Secure,
|
||||||
CookieHTTPOnly: opts.CookieHTTPOnly,
|
CookieHTTPOnly: opts.Cookie.HTTPOnly,
|
||||||
CookieExpire: opts.CookieExpire,
|
CookieExpire: opts.Cookie.Expire,
|
||||||
CookieRefresh: opts.CookieRefresh,
|
CookieRefresh: opts.Cookie.Refresh,
|
||||||
CookieSameSite: opts.CookieSameSite,
|
CookieSameSite: opts.Cookie.SameSite,
|
||||||
Validator: validator,
|
Validator: validator,
|
||||||
|
|
||||||
RobotsPath: "/robots.txt",
|
RobotsPath: "/robots.txt",
|
||||||
|
@ -164,7 +164,7 @@ func TestRobotsTxt(t *testing.T) {
|
|||||||
opts := NewOptions()
|
opts := NewOptions()
|
||||||
opts.ClientID = "asdlkjx"
|
opts.ClientID = "asdlkjx"
|
||||||
opts.ClientSecret = "alkgks"
|
opts.ClientSecret = "alkgks"
|
||||||
opts.CookieSecret = "asdkugkj"
|
opts.Cookie.Secret = "asdkugkj"
|
||||||
opts.Validate()
|
opts.Validate()
|
||||||
|
|
||||||
proxy := NewOAuthProxy(opts, func(string) bool { return true })
|
proxy := NewOAuthProxy(opts, func(string) bool { return true })
|
||||||
@ -179,7 +179,7 @@ func TestIsValidRedirect(t *testing.T) {
|
|||||||
opts := NewOptions()
|
opts := NewOptions()
|
||||||
opts.ClientID = "skdlfj"
|
opts.ClientID = "skdlfj"
|
||||||
opts.ClientSecret = "fgkdsgj"
|
opts.ClientSecret = "fgkdsgj"
|
||||||
opts.CookieSecret = "ljgiogbj"
|
opts.Cookie.Secret = "ljgiogbj"
|
||||||
// Should match domains that are exactly foo.bar and any subdomain of bar.foo
|
// Should match domains that are exactly foo.bar and any subdomain of bar.foo
|
||||||
opts.WhitelistDomains = []string{
|
opts.WhitelistDomains = []string{
|
||||||
"foo.bar",
|
"foo.bar",
|
||||||
@ -398,10 +398,10 @@ func TestBasicAuthPassword(t *testing.T) {
|
|||||||
opts.Upstreams = append(opts.Upstreams, providerServer.URL)
|
opts.Upstreams = append(opts.Upstreams, providerServer.URL)
|
||||||
// The CookieSecret must be 32 bytes in order to create the AES
|
// The CookieSecret must be 32 bytes in order to create the AES
|
||||||
// cipher.
|
// cipher.
|
||||||
opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
|
opts.Cookie.Secret = "xyzzyplughxyzzyplughxyzzyplughxp"
|
||||||
opts.ClientID = "dlgkj"
|
opts.ClientID = "dlgkj"
|
||||||
opts.ClientSecret = "alkgret"
|
opts.ClientSecret = "alkgret"
|
||||||
opts.CookieSecure = false
|
opts.Cookie.Secure = false
|
||||||
opts.PassBasicAuth = true
|
opts.PassBasicAuth = true
|
||||||
opts.SetBasicAuth = true
|
opts.SetBasicAuth = true
|
||||||
opts.PassUserHeaders = true
|
opts.PassUserHeaders = true
|
||||||
@ -582,10 +582,10 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTes
|
|||||||
}
|
}
|
||||||
// The CookieSecret must be 32 bytes in order to create the AES
|
// The CookieSecret must be 32 bytes in order to create the AES
|
||||||
// cipher.
|
// cipher.
|
||||||
t.opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
|
t.opts.Cookie.Secret = "xyzzyplughxyzzyplughxyzzyplughxp"
|
||||||
t.opts.ClientID = "slgkj"
|
t.opts.ClientID = "slgkj"
|
||||||
t.opts.ClientSecret = "gfjgojl"
|
t.opts.ClientSecret = "gfjgojl"
|
||||||
t.opts.CookieSecure = false
|
t.opts.Cookie.Secure = false
|
||||||
t.opts.PassAccessToken = opts.PassAccessToken
|
t.opts.PassAccessToken = opts.PassAccessToken
|
||||||
t.opts.Validate()
|
t.opts.Validate()
|
||||||
|
|
||||||
@ -735,7 +735,7 @@ func NewSignInPageTest(skipProvider bool) *SignInPageTest {
|
|||||||
var sipTest SignInPageTest
|
var sipTest SignInPageTest
|
||||||
|
|
||||||
sipTest.opts = NewOptions()
|
sipTest.opts = NewOptions()
|
||||||
sipTest.opts.CookieSecret = "adklsj2"
|
sipTest.opts.Cookie.Secret = "adklsj2"
|
||||||
sipTest.opts.ClientID = "lkdgj"
|
sipTest.opts.ClientID = "lkdgj"
|
||||||
sipTest.opts.ClientSecret = "sgiufgoi"
|
sipTest.opts.ClientSecret = "sgiufgoi"
|
||||||
sipTest.opts.SkipProviderButton = skipProvider
|
sipTest.opts.SkipProviderButton = skipProvider
|
||||||
@ -841,10 +841,10 @@ func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifi
|
|||||||
}
|
}
|
||||||
pcTest.opts.ClientID = "asdfljk"
|
pcTest.opts.ClientID = "asdfljk"
|
||||||
pcTest.opts.ClientSecret = "lkjfdsig"
|
pcTest.opts.ClientSecret = "lkjfdsig"
|
||||||
pcTest.opts.CookieSecret = "0123456789abcdefabcd"
|
pcTest.opts.Cookie.Secret = "0123456789abcdefabcd"
|
||||||
// First, set the CookieRefresh option so proxy.AesCipher is created,
|
// First, set the CookieRefresh option so proxy.AesCipher is created,
|
||||||
// needed to encrypt the access_token.
|
// needed to encrypt the access_token.
|
||||||
pcTest.opts.CookieRefresh = time.Hour
|
pcTest.opts.Cookie.Refresh = time.Hour
|
||||||
pcTest.opts.Validate()
|
pcTest.opts.Validate()
|
||||||
|
|
||||||
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
||||||
@ -915,7 +915,7 @@ func TestProcessCookieNoCookieError(t *testing.T) {
|
|||||||
|
|
||||||
func TestProcessCookieRefreshNotSet(t *testing.T) {
|
func TestProcessCookieRefreshNotSet(t *testing.T) {
|
||||||
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
||||||
opts.CookieExpire = time.Duration(23) * time.Hour
|
opts.Cookie.Expire = time.Duration(23) * time.Hour
|
||||||
})
|
})
|
||||||
reference := time.Now().Add(time.Duration(-2) * time.Hour)
|
reference := time.Now().Add(time.Duration(-2) * time.Hour)
|
||||||
|
|
||||||
@ -932,7 +932,7 @@ func TestProcessCookieRefreshNotSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestProcessCookieFailIfCookieExpired(t *testing.T) {
|
func TestProcessCookieFailIfCookieExpired(t *testing.T) {
|
||||||
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
||||||
opts.CookieExpire = time.Duration(24) * time.Hour
|
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
||||||
})
|
})
|
||||||
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
||||||
startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
|
startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
|
||||||
@ -947,7 +947,7 @@ func TestProcessCookieFailIfCookieExpired(t *testing.T) {
|
|||||||
|
|
||||||
func TestProcessCookieFailIfRefreshSetAndCookieExpired(t *testing.T) {
|
func TestProcessCookieFailIfRefreshSetAndCookieExpired(t *testing.T) {
|
||||||
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
||||||
opts.CookieExpire = time.Duration(24) * time.Hour
|
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
||||||
})
|
})
|
||||||
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
||||||
startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
|
startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
|
||||||
@ -1017,7 +1017,7 @@ func TestAuthOnlyEndpointUnauthorizedOnNoCookieSetError(t *testing.T) {
|
|||||||
|
|
||||||
func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
|
func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
|
||||||
test := NewAuthOnlyEndpointTest(func(opts *Options) {
|
test := NewAuthOnlyEndpointTest(func(opts *Options) {
|
||||||
opts.CookieExpire = time.Duration(24) * time.Hour
|
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
||||||
})
|
})
|
||||||
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
||||||
startSession := &sessions.SessionState{
|
startSession := &sessions.SessionState{
|
||||||
@ -1149,7 +1149,7 @@ func TestAuthSkippedForPreflightRequests(t *testing.T) {
|
|||||||
opts.Upstreams = append(opts.Upstreams, upstream.URL)
|
opts.Upstreams = append(opts.Upstreams, upstream.URL)
|
||||||
opts.ClientID = "aljsal"
|
opts.ClientID = "aljsal"
|
||||||
opts.ClientSecret = "jglkfsdgj"
|
opts.ClientSecret = "jglkfsdgj"
|
||||||
opts.CookieSecret = "dkfjgdls"
|
opts.Cookie.Secret = "dkfjgdls"
|
||||||
opts.SkipAuthPreflight = true
|
opts.SkipAuthPreflight = true
|
||||||
opts.Validate()
|
opts.Validate()
|
||||||
|
|
||||||
@ -1196,7 +1196,7 @@ type SignatureTest struct {
|
|||||||
|
|
||||||
func NewSignatureTest() *SignatureTest {
|
func NewSignatureTest() *SignatureTest {
|
||||||
opts := NewOptions()
|
opts := NewOptions()
|
||||||
opts.CookieSecret = "cookie secret"
|
opts.Cookie.Secret = "cookie secret"
|
||||||
opts.ClientID = "client ID"
|
opts.ClientID = "client ID"
|
||||||
opts.ClientSecret = "client secret"
|
opts.ClientSecret = "client secret"
|
||||||
opts.EmailDomains = []string{"acm.org"}
|
opts.EmailDomains = []string{"acm.org"}
|
||||||
@ -1343,7 +1343,7 @@ type ajaxRequestTest struct {
|
|||||||
func newAjaxRequestTest() *ajaxRequestTest {
|
func newAjaxRequestTest() *ajaxRequestTest {
|
||||||
test := &ajaxRequestTest{}
|
test := &ajaxRequestTest{}
|
||||||
test.opts = NewOptions()
|
test.opts = NewOptions()
|
||||||
test.opts.CookieSecret = "sdflsw"
|
test.opts.Cookie.Secret = "sdflsw"
|
||||||
test.opts.ClientID = "gkljfdl"
|
test.opts.ClientID = "gkljfdl"
|
||||||
test.opts.ClientSecret = "sdflkjs"
|
test.opts.ClientSecret = "sdflkjs"
|
||||||
test.opts.Validate()
|
test.opts.Validate()
|
||||||
@ -1401,11 +1401,11 @@ func TestAjaxForbiddendRequest(t *testing.T) {
|
|||||||
|
|
||||||
func TestClearSplitCookie(t *testing.T) {
|
func TestClearSplitCookie(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := NewOptions()
|
||||||
opts.CookieName = "oauth2"
|
opts.Cookie.Name = "oauth2"
|
||||||
opts.CookieDomains = []string{"abc"}
|
opts.Cookie.Domains = []string{"abc"}
|
||||||
store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.CookieOptions)
|
store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.Cookie)
|
||||||
assert.Equal(t, err, nil)
|
assert.Equal(t, err, nil)
|
||||||
p := OAuthProxy{CookieName: opts.CookieName, CookieDomains: opts.CookieDomains, sessionStore: store}
|
p := OAuthProxy{CookieName: opts.Cookie.Name, CookieDomains: opts.Cookie.Domains, sessionStore: store}
|
||||||
var rw = httptest.NewRecorder()
|
var rw = httptest.NewRecorder()
|
||||||
req := httptest.NewRequest("get", "/", nil)
|
req := httptest.NewRequest("get", "/", nil)
|
||||||
|
|
||||||
@ -1430,11 +1430,11 @@ func TestClearSplitCookie(t *testing.T) {
|
|||||||
|
|
||||||
func TestClearSingleCookie(t *testing.T) {
|
func TestClearSingleCookie(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := NewOptions()
|
||||||
opts.CookieName = "oauth2"
|
opts.Cookie.Name = "oauth2"
|
||||||
opts.CookieDomains = []string{"abc"}
|
opts.Cookie.Domains = []string{"abc"}
|
||||||
store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.CookieOptions)
|
store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.Cookie)
|
||||||
assert.Equal(t, err, nil)
|
assert.Equal(t, err, nil)
|
||||||
p := OAuthProxy{CookieName: opts.CookieName, CookieDomains: opts.CookieDomains, sessionStore: store}
|
p := OAuthProxy{CookieName: opts.Cookie.Name, CookieDomains: opts.Cookie.Domains, sessionStore: store}
|
||||||
var rw = httptest.NewRecorder()
|
var rw = httptest.NewRecorder()
|
||||||
req := httptest.NewRequest("get", "/", nil)
|
req := httptest.NewRequest("get", "/", nil)
|
||||||
|
|
||||||
|
49
options.go
49
options.go
@ -64,8 +64,7 @@ type Options struct {
|
|||||||
Banner string `flag:"banner" cfg:"banner" env:"OAUTH2_PROXY_BANNER"`
|
Banner string `flag:"banner" cfg:"banner" env:"OAUTH2_PROXY_BANNER"`
|
||||||
Footer string `flag:"footer" cfg:"footer" env:"OAUTH2_PROXY_FOOTER"`
|
Footer string `flag:"footer" cfg:"footer" env:"OAUTH2_PROXY_FOOTER"`
|
||||||
|
|
||||||
// Embed CookieOptions
|
Cookie options.CookieOptions
|
||||||
options.CookieOptions
|
|
||||||
|
|
||||||
// Embed SessionOptions
|
// Embed SessionOptions
|
||||||
options.SessionOptions
|
options.SessionOptions
|
||||||
@ -158,12 +157,12 @@ func NewOptions() *Options {
|
|||||||
HTTPSAddress: ":443",
|
HTTPSAddress: ":443",
|
||||||
ForceHTTPS: false,
|
ForceHTTPS: false,
|
||||||
DisplayHtpasswdForm: true,
|
DisplayHtpasswdForm: true,
|
||||||
CookieOptions: options.CookieOptions{
|
Cookie: options.CookieOptions{
|
||||||
CookieName: "_oauth2_proxy",
|
Name: "_oauth2_proxy",
|
||||||
CookieSecure: true,
|
Secure: true,
|
||||||
CookieHTTPOnly: true,
|
HTTPOnly: true,
|
||||||
CookieExpire: time.Duration(168) * time.Hour,
|
Expire: time.Duration(168) * time.Hour,
|
||||||
CookieRefresh: time.Duration(0),
|
Refresh: time.Duration(0),
|
||||||
},
|
},
|
||||||
SessionOptions: options.SessionOptions{
|
SessionOptions: options.SessionOptions{
|
||||||
Type: "cookie",
|
Type: "cookie",
|
||||||
@ -227,7 +226,7 @@ func (o *Options) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
msgs := make([]string, 0)
|
msgs := make([]string, 0)
|
||||||
if o.CookieSecret == "" {
|
if o.Cookie.Secret == "" {
|
||||||
msgs = append(msgs, "missing setting: cookie-secret")
|
msgs = append(msgs, "missing setting: cookie-secret")
|
||||||
}
|
}
|
||||||
if o.ClientID == "" {
|
if o.ClientID == "" {
|
||||||
@ -382,31 +381,31 @@ func (o *Options) Validate() error {
|
|||||||
msgs = parseProviderInfo(o, msgs)
|
msgs = parseProviderInfo(o, msgs)
|
||||||
|
|
||||||
var cipher *encryption.Cipher
|
var cipher *encryption.Cipher
|
||||||
if o.PassAccessToken || o.SetAuthorization || o.PassAuthorization || (o.CookieRefresh != time.Duration(0)) {
|
if o.PassAccessToken || o.SetAuthorization || o.PassAuthorization || (o.Cookie.Refresh != time.Duration(0)) {
|
||||||
validCookieSecretSize := false
|
validCookieSecretSize := false
|
||||||
for _, i := range []int{16, 24, 32} {
|
for _, i := range []int{16, 24, 32} {
|
||||||
if len(secretBytes(o.CookieSecret)) == i {
|
if len(secretBytes(o.Cookie.Secret)) == i {
|
||||||
validCookieSecretSize = true
|
validCookieSecretSize = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var decoded bool
|
var decoded bool
|
||||||
if string(secretBytes(o.CookieSecret)) != o.CookieSecret {
|
if string(secretBytes(o.Cookie.Secret)) != o.Cookie.Secret {
|
||||||
decoded = true
|
decoded = true
|
||||||
}
|
}
|
||||||
if !validCookieSecretSize {
|
if !validCookieSecretSize {
|
||||||
var suffix string
|
var suffix string
|
||||||
if decoded {
|
if decoded {
|
||||||
suffix = fmt.Sprintf(" note: cookie secret was base64 decoded from %q", o.CookieSecret)
|
suffix = fmt.Sprintf(" note: cookie secret was base64 decoded from %q", o.Cookie.Secret)
|
||||||
}
|
}
|
||||||
msgs = append(msgs, fmt.Sprintf(
|
msgs = append(msgs, fmt.Sprintf(
|
||||||
"cookie_secret must be 16, 24, or 32 bytes "+
|
"cookie_secret must be 16, 24, or 32 bytes "+
|
||||||
"to create an AES cipher when "+
|
"to create an AES cipher when "+
|
||||||
"pass_access_token == true or "+
|
"pass_access_token == true or "+
|
||||||
"cookie_refresh != 0, but is %d bytes.%s",
|
"cookie_refresh != 0, but is %d bytes.%s",
|
||||||
len(secretBytes(o.CookieSecret)), suffix))
|
len(secretBytes(o.Cookie.Secret)), suffix))
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
cipher, err = encryption.NewCipher(secretBytes(o.CookieSecret))
|
cipher, err = encryption.NewCipher(secretBytes(o.Cookie.Secret))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msgs = append(msgs, fmt.Sprintf("cookie-secret error: %v", err))
|
msgs = append(msgs, fmt.Sprintf("cookie-secret error: %v", err))
|
||||||
}
|
}
|
||||||
@ -414,19 +413,19 @@ func (o *Options) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
o.SessionOptions.Cipher = cipher
|
o.SessionOptions.Cipher = cipher
|
||||||
sessionStore, err := sessions.NewSessionStore(&o.SessionOptions, &o.CookieOptions)
|
sessionStore, err := sessions.NewSessionStore(&o.SessionOptions, &o.Cookie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msgs = append(msgs, fmt.Sprintf("error initialising session storage: %v", err))
|
msgs = append(msgs, fmt.Sprintf("error initialising session storage: %v", err))
|
||||||
} else {
|
} else {
|
||||||
o.sessionStore = sessionStore
|
o.sessionStore = sessionStore
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.CookieRefresh >= o.CookieExpire {
|
if o.Cookie.Refresh >= o.Cookie.Expire {
|
||||||
msgs = append(msgs, fmt.Sprintf(
|
msgs = append(msgs, fmt.Sprintf(
|
||||||
"cookie_refresh (%s) must be less than "+
|
"cookie_refresh (%s) must be less than "+
|
||||||
"cookie_expire (%s)",
|
"cookie_expire (%s)",
|
||||||
o.CookieRefresh.String(),
|
o.Cookie.Refresh.String(),
|
||||||
o.CookieExpire.String()))
|
o.Cookie.Expire.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(o.GoogleGroups) > 0 || o.GoogleAdminEmail != "" || o.GoogleServiceAccountJSON != "" {
|
if len(o.GoogleGroups) > 0 || o.GoogleAdminEmail != "" || o.GoogleServiceAccountJSON != "" {
|
||||||
@ -441,16 +440,16 @@ func (o *Options) Validate() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch o.CookieSameSite {
|
switch o.Cookie.SameSite {
|
||||||
case "", "none", "lax", "strict":
|
case "", "none", "lax", "strict":
|
||||||
default:
|
default:
|
||||||
msgs = append(msgs, fmt.Sprintf("cookie_samesite (%s) must be one of ['', 'lax', 'strict', 'none']", o.CookieSameSite))
|
msgs = append(msgs, fmt.Sprintf("cookie_samesite (%s) must be one of ['', 'lax', 'strict', 'none']", o.Cookie.SameSite))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort cookie domains by length, so that we try longer (and more specific)
|
// Sort cookie domains by length, so that we try longer (and more specific)
|
||||||
// domains first
|
// domains first
|
||||||
sort.Slice(o.CookieDomains, func(i, j int) bool {
|
sort.Slice(o.Cookie.Domains, func(i, j int) bool {
|
||||||
return len(o.CookieDomains[i]) > len(o.CookieDomains[j])
|
return len(o.Cookie.Domains[i]) > len(o.Cookie.Domains[j])
|
||||||
})
|
})
|
||||||
|
|
||||||
msgs = parseSignatureKey(o, msgs)
|
msgs = parseSignatureKey(o, msgs)
|
||||||
@ -627,9 +626,9 @@ func newVerifierFromJwtIssuer(jwtIssuer jwtIssuer) (*oidc.IDTokenVerifier, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateCookieName(o *Options, msgs []string) []string {
|
func validateCookieName(o *Options, msgs []string) []string {
|
||||||
cookie := &http.Cookie{Name: o.CookieName}
|
cookie := &http.Cookie{Name: o.Cookie.Name}
|
||||||
if cookie.String() == "" {
|
if cookie.String() == "" {
|
||||||
return append(msgs, fmt.Sprintf("invalid cookie name: %q", o.CookieName))
|
return append(msgs, fmt.Sprintf("invalid cookie name: %q", o.Cookie.Name))
|
||||||
}
|
}
|
||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ const (
|
|||||||
func testOptions() *Options {
|
func testOptions() *Options {
|
||||||
o := NewOptions()
|
o := NewOptions()
|
||||||
o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8080/")
|
o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8080/")
|
||||||
o.CookieSecret = cookieSecret
|
o.Cookie.Secret = cookieSecret
|
||||||
o.ClientID = clientID
|
o.ClientID = clientID
|
||||||
o.ClientSecret = clientSecret
|
o.ClientSecret = clientSecret
|
||||||
o.EmailDomains = []string{"*"}
|
o.EmailDomains = []string{"*"}
|
||||||
@ -51,7 +51,7 @@ func TestNewOptions(t *testing.T) {
|
|||||||
|
|
||||||
func TestClientSecretFileOptionFails(t *testing.T) {
|
func TestClientSecretFileOptionFails(t *testing.T) {
|
||||||
o := NewOptions()
|
o := NewOptions()
|
||||||
o.CookieSecret = cookieSecret
|
o.Cookie.Secret = cookieSecret
|
||||||
o.ClientID = clientID
|
o.ClientID = clientID
|
||||||
o.ClientSecretFile = clientSecret
|
o.ClientSecretFile = clientSecret
|
||||||
o.EmailDomains = []string{"*"}
|
o.EmailDomains = []string{"*"}
|
||||||
@ -81,7 +81,7 @@ func TestClientSecretFileOption(t *testing.T) {
|
|||||||
defer os.Remove(clientSecretFileName)
|
defer os.Remove(clientSecretFileName)
|
||||||
|
|
||||||
o := NewOptions()
|
o := NewOptions()
|
||||||
o.CookieSecret = cookieSecret
|
o.Cookie.Secret = cookieSecret
|
||||||
o.ClientID = clientID
|
o.ClientID = clientID
|
||||||
o.ClientSecretFile = clientSecretFileName
|
o.ClientSecretFile = clientSecretFileName
|
||||||
o.EmailDomains = []string{"*"}
|
o.EmailDomains = []string{"*"}
|
||||||
@ -212,20 +212,20 @@ func TestPassAccessTokenRequiresSpecificCookieSecretLengths(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, false, o.PassAccessToken)
|
assert.Equal(t, false, o.PassAccessToken)
|
||||||
o.PassAccessToken = true
|
o.PassAccessToken = true
|
||||||
o.CookieSecret = "cookie of invalid length-"
|
o.Cookie.Secret = "cookie of invalid length-"
|
||||||
assert.NotEqual(t, nil, o.Validate())
|
assert.NotEqual(t, nil, o.Validate())
|
||||||
|
|
||||||
o.PassAccessToken = false
|
o.PassAccessToken = false
|
||||||
o.CookieRefresh = time.Duration(24) * time.Hour
|
o.Cookie.Refresh = time.Duration(24) * time.Hour
|
||||||
assert.NotEqual(t, nil, o.Validate())
|
assert.NotEqual(t, nil, o.Validate())
|
||||||
|
|
||||||
o.CookieSecret = "16 bytes AES-128"
|
o.Cookie.Secret = "16 bytes AES-128"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
|
|
||||||
o.CookieSecret = "24 byte secret AES-192--"
|
o.Cookie.Secret = "24 byte secret AES-192--"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
|
|
||||||
o.CookieSecret = "32 byte secret for AES-256------"
|
o.Cookie.Secret = "32 byte secret for AES-256------"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,11 +233,11 @@ func TestCookieRefreshMustBeLessThanCookieExpire(t *testing.T) {
|
|||||||
o := testOptions()
|
o := testOptions()
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
|
|
||||||
o.CookieSecret = "0123456789abcdefabcd"
|
o.Cookie.Secret = "0123456789abcdefabcd"
|
||||||
o.CookieRefresh = o.CookieExpire
|
o.Cookie.Refresh = o.Cookie.Expire
|
||||||
assert.NotEqual(t, nil, o.Validate())
|
assert.NotEqual(t, nil, o.Validate())
|
||||||
|
|
||||||
o.CookieRefresh -= time.Duration(1)
|
o.Cookie.Refresh -= time.Duration(1)
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,23 +246,23 @@ func TestBase64CookieSecret(t *testing.T) {
|
|||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
|
|
||||||
// 32 byte, base64 (urlsafe) encoded key
|
// 32 byte, base64 (urlsafe) encoded key
|
||||||
o.CookieSecret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ="
|
o.Cookie.Secret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ="
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
|
|
||||||
// 32 byte, base64 (urlsafe) encoded key, w/o padding
|
// 32 byte, base64 (urlsafe) encoded key, w/o padding
|
||||||
o.CookieSecret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ"
|
o.Cookie.Secret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
|
|
||||||
// 24 byte, base64 (urlsafe) encoded key
|
// 24 byte, base64 (urlsafe) encoded key
|
||||||
o.CookieSecret = "Kp33Gj-GQmYtz4zZUyUDdqQKx5_Hgkv3"
|
o.Cookie.Secret = "Kp33Gj-GQmYtz4zZUyUDdqQKx5_Hgkv3"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
|
|
||||||
// 16 byte, base64 (urlsafe) encoded key
|
// 16 byte, base64 (urlsafe) encoded key
|
||||||
o.CookieSecret = "LFEqZYvYUwKwzn0tEuTpLA=="
|
o.Cookie.Secret = "LFEqZYvYUwKwzn0tEuTpLA=="
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
|
|
||||||
// 16 byte, base64 (urlsafe) encoded key, w/o padding
|
// 16 byte, base64 (urlsafe) encoded key, w/o padding
|
||||||
o.CookieSecret = "LFEqZYvYUwKwzn0tEuTpLA"
|
o.Cookie.Secret = "LFEqZYvYUwKwzn0tEuTpLA"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,16 +292,16 @@ func TestValidateSignatureKeyUnsupportedAlgorithm(t *testing.T) {
|
|||||||
|
|
||||||
func TestValidateCookie(t *testing.T) {
|
func TestValidateCookie(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.CookieName = "_valid_cookie_name"
|
o.Cookie.Name = "_valid_cookie_name"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, o.Validate())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateCookieBadName(t *testing.T) {
|
func TestValidateCookieBadName(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.CookieName = "_bad_cookie_name{}"
|
o.Cookie.Name = "_bad_cookie_name{}"
|
||||||
err := o.Validate()
|
err := o.Validate()
|
||||||
assert.Equal(t, err.Error(), "invalid configuration:\n"+
|
assert.Equal(t, err.Error(), "invalid configuration:\n"+
|
||||||
fmt.Sprintf(" invalid cookie name: %q", o.CookieName))
|
fmt.Sprintf(" invalid cookie name: %q", o.Cookie.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSkipOIDCDiscovery(t *testing.T) {
|
func TestSkipOIDCDiscovery(t *testing.T) {
|
||||||
|
@ -4,13 +4,13 @@ import "time"
|
|||||||
|
|
||||||
// CookieOptions contains configuration options relating to Cookie configuration
|
// CookieOptions contains configuration options relating to Cookie configuration
|
||||||
type CookieOptions struct {
|
type CookieOptions struct {
|
||||||
CookieName string `flag:"cookie-name" cfg:"cookie_name" env:"OAUTH2_PROXY_COOKIE_NAME"`
|
Name 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"`
|
Secret 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"`
|
Domains []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"`
|
Path 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"`
|
Expire 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"`
|
Refresh 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"`
|
Secure 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"`
|
HTTPOnly 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"`
|
SameSite string `flag:"cookie-samesite" cfg:"cookie_samesite" env:"OAUTH2_PROXY_COOKIE_SAMESITE"`
|
||||||
}
|
}
|
||||||
|
@ -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,
|
// MakeCookieFromOptions constructs a cookie based on the given *options.CookieOptions,
|
||||||
// value and creation time
|
// value and creation time
|
||||||
func MakeCookieFromOptions(req *http.Request, name string, value string, opts *options.CookieOptions, expiration time.Duration, now time.Time) *http.Cookie {
|
func MakeCookieFromOptions(req *http.Request, name string, value string, cookieOpts *options.CookieOptions, expiration time.Duration, now time.Time) *http.Cookie {
|
||||||
domain := GetCookieDomain(req, opts.CookieDomains)
|
domain := GetCookieDomain(req, cookieOpts.Domains)
|
||||||
|
|
||||||
if domain != "" {
|
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
|
// 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 := ""
|
defaultDomain := ""
|
||||||
if len(opts.CookieDomains) > 0 {
|
if len(cookieOpts.Domains) > 0 {
|
||||||
defaultDomain = opts.CookieDomains[len(opts.CookieDomains)-1]
|
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
|
// GetCookieDomain returns the correct cookie domain given a list of domains
|
||||||
|
@ -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
|
// Load reads sessions.SessionState information from Cookies within the
|
||||||
// HTTP request object
|
// HTTP request object
|
||||||
func (s *SessionStore) Load(req *http.Request) (*sessions.SessionState, error) {
|
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 {
|
if err != nil {
|
||||||
// always http.ErrNoCookie
|
// 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 {
|
if !ok {
|
||||||
return nil, errors.New("cookie signature not valid")
|
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
|
// clear the session
|
||||||
func (s *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) error {
|
func (s *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) error {
|
||||||
// matches CookieName, CookieName_<number>
|
// 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() {
|
for _, c := range req.Cookies() {
|
||||||
if cookieNameRegex.MatchString(c.Name) {
|
if cookieNameRegex.MatchString(c.Name) {
|
||||||
@ -94,10 +94,10 @@ func (s *SessionStore) setSessionCookie(rw http.ResponseWriter, req *http.Reques
|
|||||||
// authentication details
|
// authentication details
|
||||||
func (s *SessionStore) makeSessionCookie(req *http.Request, value string, now time.Time) []*http.Cookie {
|
func (s *SessionStore) makeSessionCookie(req *http.Request, value string, now time.Time) []*http.Cookie {
|
||||||
if value != "" {
|
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)
|
c := s.makeCookie(req, s.CookieOptions.Name, value, s.CookieOptions.Expire, now)
|
||||||
if len(c.Value) > 4096-len(s.CookieOptions.CookieName) {
|
if len(c.Value) > 4096-len(s.CookieOptions.Name) {
|
||||||
return splitCookie(c)
|
return splitCookie(c)
|
||||||
}
|
}
|
||||||
return []*http.Cookie{c}
|
return []*http.Cookie{c}
|
||||||
|
@ -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
|
// Old sessions that we are refreshing would have a request cookie
|
||||||
// New sessions don't, so we ignore the error. storeValue will check requestCookie
|
// 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)
|
value, err := s.EncodeSessionState(store.CookieCipher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx := req.Context()
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ func (store *SessionStore) Save(rw http.ResponseWriter, req *http.Request, s *se
|
|||||||
ticketCookie := store.makeCookie(
|
ticketCookie := store.makeCookie(
|
||||||
req,
|
req,
|
||||||
ticketString,
|
ticketString,
|
||||||
store.CookieOptions.CookieExpire,
|
store.CookieOptions.Expire,
|
||||||
s.CreatedAt,
|
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
|
// Load reads sessions.SessionState information from a ticket
|
||||||
// cookie within the HTTP request object
|
// cookie within the HTTP request object
|
||||||
func (store *SessionStore) Load(req *http.Request) (*sessions.SessionState, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error loading session: %s", err)
|
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 {
|
if !ok {
|
||||||
return nil, fmt.Errorf("cookie signature not valid")
|
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
|
// loadSessionFromString loads the session based on the ticket value
|
||||||
func (store *SessionStore) loadSessionFromString(ctx context.Context, value string) (*sessions.SessionState, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -199,7 +199,7 @@ func (store *SessionStore) Clear(rw http.ResponseWriter, req *http.Request) erro
|
|||||||
http.SetCookie(rw, clearCookie)
|
http.SetCookie(rw, clearCookie)
|
||||||
|
|
||||||
// If there was an existing cookie we should clear the session in redis
|
// 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 {
|
if err != nil && err == http.ErrNoCookie {
|
||||||
// No existing cookie so can't clear redis
|
// No existing cookie so can't clear redis
|
||||||
return nil
|
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)
|
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 {
|
if !ok {
|
||||||
return fmt.Errorf("cookie signature not valid")
|
return fmt.Errorf("cookie signature not valid")
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only return an error if we had an issue with redis
|
// We only return an error if we had an issue with redis
|
||||||
// If there's an issue decoding the ticket, ignore it
|
// 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 {
|
if ticket != nil {
|
||||||
ctx := req.Context()
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("error clearing cookie from redis: %s", err)
|
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
|
// 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 {
|
func (store *SessionStore) makeCookie(req *http.Request, value string, expires time.Duration, now time.Time) *http.Cookie {
|
||||||
if value != "" {
|
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(
|
return cookies.MakeCookieFromOptions(
|
||||||
req,
|
req,
|
||||||
store.CookieOptions.CookieName,
|
store.CookieOptions.Name,
|
||||||
value,
|
value,
|
||||||
store.CookieOptions,
|
store.CookieOptions,
|
||||||
expires,
|
expires,
|
||||||
@ -256,12 +256,12 @@ func (store *SessionStore) storeValue(ctx context.Context, value string, expirat
|
|||||||
stream := cipher.NewCFBEncrypter(block, ticket.Secret)
|
stream := cipher.NewCFBEncrypter(block, ticket.Secret)
|
||||||
stream.XORKeyStream(ciphertext, []byte(value))
|
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)
|
err = store.Client.Set(ctx, handle, ciphertext, expiration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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,
|
// 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
|
// 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 {
|
if !ok {
|
||||||
// Cookie is invalid, create a new ticket
|
// Cookie is invalid, create a new ticket
|
||||||
return newTicket()
|
return newTicket()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid cookie, decode the ticket
|
// Valid cookie, decode the ticket
|
||||||
ticket, err := decodeTicket(store.CookieOptions.CookieName, val)
|
ticket, err := decodeTicket(store.CookieOptions.Name, val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If we can't decode the ticket we have to create a new one
|
// If we can't decode the ticket we have to create a new one
|
||||||
return newTicket()
|
return newTicket()
|
||||||
|
@ -47,25 +47,25 @@ var _ = Describe("NewSessionStore", func() {
|
|||||||
|
|
||||||
It("have the correct name set", func() {
|
It("have the correct name set", func() {
|
||||||
if len(cookies) == 1 {
|
if len(cookies) == 1 {
|
||||||
Expect(cookies[0].Name).To(Equal(cookieOpts.CookieName))
|
Expect(cookies[0].Name).To(Equal(cookieOpts.Name))
|
||||||
} else {
|
} else {
|
||||||
for _, cookie := range cookies {
|
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() {
|
It("have the correct path set", func() {
|
||||||
for _, cookie := range cookies {
|
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() {
|
It("have the correct domain set", func() {
|
||||||
for _, cookie := range cookies {
|
for _, cookie := range cookies {
|
||||||
specifiedDomain := ""
|
specifiedDomain := ""
|
||||||
if len(cookieOpts.CookieDomains) > 0 {
|
if len(cookieOpts.Domains) > 0 {
|
||||||
specifiedDomain = cookieOpts.CookieDomains[0]
|
specifiedDomain = cookieOpts.Domains[0]
|
||||||
}
|
}
|
||||||
Expect(cookie.Domain).To(Equal(specifiedDomain))
|
Expect(cookie.Domain).To(Equal(specifiedDomain))
|
||||||
}
|
}
|
||||||
@ -73,19 +73,19 @@ var _ = Describe("NewSessionStore", func() {
|
|||||||
|
|
||||||
It("have the correct HTTPOnly set", func() {
|
It("have the correct HTTPOnly set", func() {
|
||||||
for _, cookie := range cookies {
|
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() {
|
It("have the correct secure set", func() {
|
||||||
for _, cookie := range cookies {
|
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() {
|
It("have the correct SameSite set", func() {
|
||||||
for _, cookie := range cookies {
|
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() {
|
BeforeEach(func() {
|
||||||
By("Using a valid cookie with a different providers session encoding")
|
By("Using a valid cookie with a different providers session encoding")
|
||||||
broken := "BrokenSessionFromADifferentSessionImplementation"
|
broken := "BrokenSessionFromADifferentSessionImplementation"
|
||||||
value := encryption.SignedValue(cookieOpts.CookieSecret, cookieOpts.CookieName, broken, time.Now())
|
value := encryption.SignedValue(cookieOpts.Secret, cookieOpts.Name, broken, time.Now())
|
||||||
cookie := cookiesapi.MakeCookieFromOptions(request, cookieOpts.CookieName, value, cookieOpts, cookieOpts.CookieExpire, time.Now())
|
cookie := cookiesapi.MakeCookieFromOptions(request, cookieOpts.Name, value, cookieOpts, cookieOpts.Expire, time.Now())
|
||||||
request.AddCookie(cookie)
|
request.AddCookie(cookie)
|
||||||
|
|
||||||
err := ss.Save(response, request, session)
|
err := ss.Save(response, request, session)
|
||||||
@ -245,7 +245,7 @@ var _ = Describe("NewSessionStore", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("loads a session equal to the original session", 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
|
// Only Email and User stored in session when encrypted
|
||||||
Expect(loadedSession.Email).To(Equal(session.Email))
|
Expect(loadedSession.Email).To(Equal(session.Email))
|
||||||
Expect(loadedSession.User).To(Equal(session.User))
|
Expect(loadedSession.User).To(Equal(session.User))
|
||||||
@ -290,7 +290,7 @@ var _ = Describe("NewSessionStore", func() {
|
|||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
switch ss.(type) {
|
switch ss.(type) {
|
||||||
case *redis.SessionStore:
|
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() {
|
BeforeEach(func() {
|
||||||
switch ss.(type) {
|
switch ss.(type) {
|
||||||
case *redis.SessionStore:
|
case *redis.SessionStore:
|
||||||
mr.FastForward(cookieOpts.CookieExpire + time.Minute)
|
mr.FastForward(cookieOpts.Expire + time.Minute)
|
||||||
}
|
}
|
||||||
|
|
||||||
loadedSession, err = ss.Load(request)
|
loadedSession, err = ss.Load(request)
|
||||||
@ -341,14 +341,14 @@ var _ = Describe("NewSessionStore", func() {
|
|||||||
Context("with non-default options", func() {
|
Context("with non-default options", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
cookieOpts = &options.CookieOptions{
|
cookieOpts = &options.CookieOptions{
|
||||||
CookieName: "_cookie_name",
|
Name: "_cookie_name",
|
||||||
CookiePath: "/path",
|
Path: "/path",
|
||||||
CookieExpire: time.Duration(72) * time.Hour,
|
Expire: time.Duration(72) * time.Hour,
|
||||||
CookieRefresh: time.Duration(2) * time.Hour,
|
Refresh: time.Duration(2) * time.Hour,
|
||||||
CookieSecure: false,
|
Secure: false,
|
||||||
CookieHTTPOnly: false,
|
HTTPOnly: false,
|
||||||
CookieDomains: []string{"example.com"},
|
Domains: []string{"example.com"},
|
||||||
CookieSameSite: "strict",
|
SameSite: "strict",
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -364,8 +364,8 @@ var _ = Describe("NewSessionStore", func() {
|
|||||||
secret := make([]byte, 32)
|
secret := make([]byte, 32)
|
||||||
_, err := rand.Read(secret)
|
_, err := rand.Read(secret)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
cookieOpts.CookieSecret = base64.URLEncoding.EncodeToString(secret)
|
cookieOpts.Secret = base64.URLEncoding.EncodeToString(secret)
|
||||||
cipher, err := encryption.NewCipher(utils.SecretBytes(cookieOpts.CookieSecret))
|
cipher, err := encryption.NewCipher(utils.SecretBytes(cookieOpts.Secret))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(cipher).ToNot(BeNil())
|
Expect(cipher).ToNot(BeNil())
|
||||||
opts.Cipher = cipher
|
opts.Cipher = cipher
|
||||||
@ -384,13 +384,13 @@ var _ = Describe("NewSessionStore", func() {
|
|||||||
|
|
||||||
// Set default options in CookieOptions
|
// Set default options in CookieOptions
|
||||||
cookieOpts = &options.CookieOptions{
|
cookieOpts = &options.CookieOptions{
|
||||||
CookieName: "_oauth2_proxy",
|
Name: "_oauth2_proxy",
|
||||||
CookiePath: "/",
|
Path: "/",
|
||||||
CookieExpire: time.Duration(168) * time.Hour,
|
Expire: time.Duration(168) * time.Hour,
|
||||||
CookieRefresh: time.Duration(1) * time.Hour,
|
Refresh: time.Duration(1) * time.Hour,
|
||||||
CookieSecure: true,
|
Secure: true,
|
||||||
CookieHTTPOnly: true,
|
HTTPOnly: true,
|
||||||
CookieSameSite: "",
|
SameSite: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
session = &sessionsapi.SessionState{
|
session = &sessionsapi.SessionState{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user