mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-03 16:59:22 +02:00
config: allow dynamic configuration of cookie settings (#1267)
This commit is contained in:
parent
0c51ad0e66
commit
fbf5b403b9
17 changed files with 184 additions and 165 deletions
|
@ -33,18 +33,6 @@ const (
|
|||
MaxNumChunks = 5
|
||||
)
|
||||
|
||||
// Store implements the session store interface for session cookies.
|
||||
type Store struct {
|
||||
Name string
|
||||
Domain string
|
||||
Expire time.Duration
|
||||
HTTPOnly bool
|
||||
Secure bool
|
||||
|
||||
encoder encoding.Marshaler
|
||||
decoder encoding.Unmarshaler
|
||||
}
|
||||
|
||||
// Options holds options for Store
|
||||
type Options struct {
|
||||
Name string
|
||||
|
@ -54,10 +42,20 @@ type Options struct {
|
|||
Secure bool
|
||||
}
|
||||
|
||||
// A GetOptionsFunc is a getter for cookie options.
|
||||
type GetOptionsFunc func() Options
|
||||
|
||||
// Store implements the session store interface for session cookies.
|
||||
type Store struct {
|
||||
getOptions GetOptionsFunc
|
||||
encoder encoding.Marshaler
|
||||
decoder encoding.Unmarshaler
|
||||
}
|
||||
|
||||
// NewStore returns a new store that implements the SessionStore interface
|
||||
// using http cookies.
|
||||
func NewStore(opts *Options, encoder encoding.MarshalUnmarshaler) (sessions.SessionStore, error) {
|
||||
cs, err := NewCookieLoader(opts, encoder)
|
||||
func NewStore(getOptions GetOptionsFunc, encoder encoding.MarshalUnmarshaler) (sessions.SessionStore, error) {
|
||||
cs, err := NewCookieLoader(getOptions, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -67,41 +65,31 @@ func NewStore(opts *Options, encoder encoding.MarshalUnmarshaler) (sessions.Sess
|
|||
|
||||
// NewCookieLoader returns a new store that implements the SessionLoader
|
||||
// interface using http cookies.
|
||||
func NewCookieLoader(opts *Options, dencoder encoding.Unmarshaler) (*Store, error) {
|
||||
func NewCookieLoader(getOptions GetOptionsFunc, dencoder encoding.Unmarshaler) (*Store, error) {
|
||||
if dencoder == nil {
|
||||
return nil, fmt.Errorf("internal/sessions: dencoder cannot be nil")
|
||||
}
|
||||
cs, err := newStore(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs := newStore(getOptions)
|
||||
cs.decoder = dencoder
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func newStore(opts *Options) (*Store, error) {
|
||||
if opts.Name == "" {
|
||||
return nil, fmt.Errorf("internal/sessions: cookie name cannot be empty")
|
||||
}
|
||||
|
||||
func newStore(getOptions GetOptionsFunc) *Store {
|
||||
return &Store{
|
||||
Name: opts.Name,
|
||||
Secure: opts.Secure,
|
||||
HTTPOnly: opts.HTTPOnly,
|
||||
Domain: opts.Domain,
|
||||
Expire: opts.Expire,
|
||||
}, nil
|
||||
getOptions: getOptions,
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *Store) makeCookie(value string) *http.Cookie {
|
||||
opts := cs.getOptions()
|
||||
return &http.Cookie{
|
||||
Name: cs.Name,
|
||||
Name: opts.Name,
|
||||
Value: value,
|
||||
Path: "/",
|
||||
Domain: cs.Domain,
|
||||
HttpOnly: cs.HTTPOnly,
|
||||
Secure: cs.Secure,
|
||||
Expires: timeNow().Add(cs.Expire),
|
||||
Domain: opts.Domain,
|
||||
HttpOnly: opts.HTTPOnly,
|
||||
Secure: opts.Secure,
|
||||
Expires: timeNow().Add(opts.Expire),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +114,8 @@ func getCookies(r *http.Request, name string) []*http.Cookie {
|
|||
|
||||
// LoadSession returns a State from the cookie in the request.
|
||||
func (cs *Store) LoadSession(r *http.Request) (string, error) {
|
||||
cookies := getCookies(r, cs.Name)
|
||||
opts := cs.getOptions()
|
||||
cookies := getCookies(r, opts.Name)
|
||||
if len(cookies) == 0 {
|
||||
return "", sessions.ErrNoSessionFound
|
||||
}
|
||||
|
|
|
@ -32,13 +32,16 @@ func TestNewStore(t *testing.T) {
|
|||
want sessions.SessionStore
|
||||
wantErr bool
|
||||
}{
|
||||
{"good", &Options{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, encoder, &Store{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, false},
|
||||
{"missing name", &Options{Name: "", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, encoder, nil, true},
|
||||
{"good", &Options{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, encoder, &Store{getOptions: func() Options {
|
||||
return Options{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}
|
||||
}}, false},
|
||||
{"missing encoder", &Options{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, nil, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := NewStore(tt.opts, tt.encoder)
|
||||
got, err := NewStore(func() Options {
|
||||
return *tt.opts
|
||||
}, tt.encoder)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("NewStore() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
@ -66,13 +69,16 @@ func TestNewCookieLoader(t *testing.T) {
|
|||
want *Store
|
||||
wantErr bool
|
||||
}{
|
||||
{"good", &Options{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, encoder, &Store{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, false},
|
||||
{"missing name", &Options{Name: "", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, encoder, nil, true},
|
||||
{"good", &Options{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, encoder, &Store{getOptions: func() Options {
|
||||
return Options{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}
|
||||
}}, false},
|
||||
{"missing encoder", &Options{Name: "_cookie", Secure: true, HTTPOnly: true, Domain: "pomerium.io", Expire: 10 * time.Second}, nil, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := NewCookieLoader(tt.opts, tt.encoder)
|
||||
got, err := NewCookieLoader(func() Options {
|
||||
return *tt.opts
|
||||
}, tt.encoder)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("NewCookieLoader() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
@ -117,13 +123,17 @@ func TestStore_SaveSession(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &Store{
|
||||
Name: "_pomerium",
|
||||
Secure: true,
|
||||
HTTPOnly: true,
|
||||
Domain: "pomerium.io",
|
||||
Expire: 10 * time.Second,
|
||||
encoder: tt.encoder,
|
||||
decoder: tt.decoder,
|
||||
getOptions: func() Options {
|
||||
return Options{
|
||||
Name: "_pomerium",
|
||||
Secure: true,
|
||||
HTTPOnly: true,
|
||||
Domain: "pomerium.io",
|
||||
Expire: 10 * time.Second,
|
||||
}
|
||||
},
|
||||
encoder: tt.encoder,
|
||||
decoder: tt.decoder,
|
||||
}
|
||||
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
|
|
|
@ -65,8 +65,10 @@ func TestVerifier(t *testing.T) {
|
|||
encSession = append(encSession, cryptutil.NewKey()...)
|
||||
}
|
||||
|
||||
cs, err := NewStore(&Options{
|
||||
Name: "_pomerium",
|
||||
cs, err := NewStore(func() Options {
|
||||
return Options{
|
||||
Name: "_pomerium",
|
||||
}
|
||||
}, encoder)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue