mirror of
https://github.com/nais/wonderwall.git
synced 2026-08-23 21:16:14 +00:00
refactor: separate cookie operations to own package
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package cookie
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/nais/wonderwall/pkg/crypto"
|
||||
)
|
||||
|
||||
type Cookie struct {
|
||||
*http.Cookie
|
||||
}
|
||||
|
||||
func (in Cookie) Encrypt(crypter crypto.Crypter) (*Cookie, error) {
|
||||
plaintext := []byte(in.Cookie.Value)
|
||||
ciphertext, err := crypter.Encrypt(plaintext)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to encrypt cookie '%s': %w", in.Cookie.Name, err)
|
||||
}
|
||||
|
||||
value := base64.StdEncoding.EncodeToString(ciphertext)
|
||||
|
||||
encryptedCookie := in.Cookie
|
||||
encryptedCookie.Value = value
|
||||
|
||||
return &Cookie{encryptedCookie}, nil
|
||||
}
|
||||
|
||||
func (in Cookie) Decrypt(crypter crypto.Crypter) (string, error) {
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(in.Value)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("value for cookie '%s' is not base64 encoded: %w", in.Name, err)
|
||||
}
|
||||
|
||||
plaintext, err := crypter.Decrypt(ciphertext)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to decrypt cookie '%s': %w", in.Name, err)
|
||||
}
|
||||
|
||||
return string(plaintext), err
|
||||
}
|
||||
|
||||
func Clear(w http.ResponseWriter, name string, opts Options) {
|
||||
expires := time.Now().Add(-7 * 24 * time.Hour)
|
||||
maxAge := -1
|
||||
|
||||
cookie := &http.Cookie{
|
||||
Expires: expires,
|
||||
HttpOnly: true,
|
||||
MaxAge: maxAge,
|
||||
Name: name,
|
||||
Path: "/",
|
||||
SameSite: opts.SameSite,
|
||||
Secure: opts.Secure,
|
||||
}
|
||||
|
||||
http.SetCookie(w, cookie)
|
||||
}
|
||||
|
||||
func Get(r *http.Request, key string) (*Cookie, error) {
|
||||
cookie, err := r.Cookie(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("no cookie named '%s': %w", key, err)
|
||||
}
|
||||
|
||||
return &Cookie{cookie}, nil
|
||||
}
|
||||
|
||||
func Make(name, value string, opts Options) *Cookie {
|
||||
expires := time.Now().Add(opts.ExpiresIn)
|
||||
maxAge := int(opts.ExpiresIn.Seconds())
|
||||
|
||||
cookie := &http.Cookie{
|
||||
Expires: expires,
|
||||
HttpOnly: true,
|
||||
MaxAge: maxAge,
|
||||
Name: name,
|
||||
Path: "/",
|
||||
SameSite: opts.SameSite,
|
||||
Secure: opts.Secure,
|
||||
Value: value,
|
||||
}
|
||||
|
||||
return &Cookie{cookie}
|
||||
}
|
||||
|
||||
func Set(w http.ResponseWriter, cookie *Cookie) {
|
||||
http.SetCookie(w, cookie.Cookie)
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package cookie_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/nais/wonderwall/pkg/cookie"
|
||||
"github.com/nais/wonderwall/pkg/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
encryptionKey = `G8Roe6AcoBpdr5GhO3cs9iORl4XIC8eq` // 256 bits AES
|
||||
)
|
||||
|
||||
func TestMake(t *testing.T) {
|
||||
expiresIn := 5 * time.Minute
|
||||
opts := cookie.DefaultOptions().WithExpiresIn(expiresIn)
|
||||
|
||||
name := "some-cookie"
|
||||
value := "some-value"
|
||||
|
||||
result := cookie.Make(name, value, opts)
|
||||
|
||||
shouldExpireBefore := time.Now().Add(expiresIn)
|
||||
assert.True(t, result.Expires.Before(shouldExpireBefore))
|
||||
assert.Equal(t, int(opts.ExpiresIn.Seconds()), result.MaxAge)
|
||||
assert.True(t, result.HttpOnly)
|
||||
assert.Equal(t, name, result.Name)
|
||||
assert.Equal(t, value, result.Value)
|
||||
assert.Equal(t, opts.SameSite, result.SameSite)
|
||||
assert.Equal(t, opts.Secure, result.Secure)
|
||||
assert.Equal(t, "/", result.Path)
|
||||
}
|
||||
|
||||
func TestClear(t *testing.T) {
|
||||
opts := cookie.DefaultOptions()
|
||||
name := "some-name"
|
||||
|
||||
writer := httptest.NewRecorder()
|
||||
cookie.Clear(writer, name, opts)
|
||||
|
||||
cookies := writer.Result().Cookies()
|
||||
|
||||
var result *http.Cookie
|
||||
for _, c := range cookies {
|
||||
if c.Name == name {
|
||||
result = c
|
||||
}
|
||||
}
|
||||
|
||||
shouldExpireBefore := time.Now().Add(-7 * 24 * time.Hour)
|
||||
|
||||
assert.NotNil(t, result)
|
||||
assert.True(t, result.Expires.Before(time.Now()))
|
||||
assert.True(t, result.Expires.Before(shouldExpireBefore))
|
||||
assert.Equal(t, -1, result.MaxAge)
|
||||
assert.True(t, result.HttpOnly)
|
||||
assert.Equal(t, name, result.Name)
|
||||
assert.Equal(t, "", result.Value)
|
||||
assert.Equal(t, opts.SameSite, result.SameSite)
|
||||
assert.Equal(t, opts.Secure, result.Secure)
|
||||
assert.Equal(t, "/", result.Path)
|
||||
}
|
||||
|
||||
func TestCookie_Encrypt(t *testing.T) {
|
||||
crypter := crypto.NewCrypter([]byte(encryptionKey))
|
||||
|
||||
opts := cookie.DefaultOptions().WithExpiresIn(1 * time.Minute)
|
||||
name := "some-name"
|
||||
value := "some-value"
|
||||
|
||||
plaintextCookie := cookie.Make(name, value, opts)
|
||||
encryptedCookie, err := plaintextCookie.Encrypt(crypter)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, value, encryptedCookie.Value)
|
||||
}
|
||||
|
||||
func TestCookie_Decrypt(t *testing.T) {
|
||||
crypter := crypto.NewCrypter([]byte(encryptionKey))
|
||||
|
||||
opts := cookie.DefaultOptions().WithExpiresIn(1 * time.Minute)
|
||||
name := "some-name"
|
||||
value := "some-value"
|
||||
|
||||
plaintextCookie := cookie.Make(name, value, opts)
|
||||
encryptedCookie, err := plaintextCookie.Encrypt(crypter)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, value, encryptedCookie.Value)
|
||||
|
||||
plaintext, err := encryptedCookie.Decrypt(crypter)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, value, plaintext)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cookie
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
ExpiresIn time.Duration
|
||||
SameSite http.SameSite
|
||||
Secure bool
|
||||
}
|
||||
|
||||
func DefaultOptions() Options {
|
||||
return Options{
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
Secure: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (o Options) WithSameSite(sameSite http.SameSite) Options {
|
||||
o.SameSite = sameSite
|
||||
return o
|
||||
}
|
||||
|
||||
func (o Options) WithExpiresIn(expiresIn time.Duration) Options {
|
||||
o.ExpiresIn = expiresIn
|
||||
return o
|
||||
}
|
||||
|
||||
func (o Options) WithSecure(secure bool) Options {
|
||||
o.Secure = secure
|
||||
return o
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package cookie_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/nais/wonderwall/pkg/cookie"
|
||||
)
|
||||
|
||||
func TestDefaultOptions(t *testing.T) {
|
||||
opts := cookie.DefaultOptions()
|
||||
|
||||
assert.Equal(t, http.SameSiteLaxMode, opts.SameSite)
|
||||
assert.True(t, opts.Secure)
|
||||
assert.Empty(t, opts.ExpiresIn)
|
||||
}
|
||||
|
||||
func TestOptions_WithExpiresIn(t *testing.T) {
|
||||
expiresIn := 1 * time.Minute
|
||||
opts := cookie.Options{}.WithExpiresIn(expiresIn)
|
||||
|
||||
assert.Equal(t, 1*time.Minute, opts.ExpiresIn)
|
||||
|
||||
opts = cookie.Options{
|
||||
ExpiresIn: 2 * time.Minute,
|
||||
}
|
||||
newOpts := opts.WithExpiresIn(expiresIn)
|
||||
|
||||
assert.Equal(t, 2*time.Minute, opts.ExpiresIn, "original options should be unchanged")
|
||||
assert.Equal(t, 1*time.Minute, newOpts.ExpiresIn, "copy of options should have new value")
|
||||
}
|
||||
|
||||
func TestOptions_WithSameSite(t *testing.T) {
|
||||
sameSite := http.SameSiteDefaultMode
|
||||
opts := cookie.Options{}.WithSameSite(sameSite)
|
||||
|
||||
assert.Equal(t, http.SameSiteDefaultMode, opts.SameSite)
|
||||
|
||||
opts = cookie.Options{
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
newOpts := opts.WithSameSite(sameSite)
|
||||
|
||||
assert.Equal(t, http.SameSiteLaxMode, opts.SameSite, "original options should be unchanged")
|
||||
assert.Equal(t, http.SameSiteDefaultMode, newOpts.SameSite, "copy of options should have new value")
|
||||
}
|
||||
|
||||
func TestOptions_WithSecure(t *testing.T) {
|
||||
opts := cookie.Options{}.WithSecure(true)
|
||||
|
||||
assert.True(t, opts.Secure)
|
||||
|
||||
opts = cookie.Options{
|
||||
Secure: false,
|
||||
}
|
||||
newOpts := opts.WithSecure(true)
|
||||
|
||||
assert.False(t, opts.Secure, "original options should be unchanged")
|
||||
assert.True(t, newOpts.Secure, "copy of options should have new value")
|
||||
}
|
||||
+11
-82
@@ -1,107 +1,36 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/nais/wonderwall/pkg/openid"
|
||||
"github.com/nais/wonderwall/pkg/cookie"
|
||||
)
|
||||
|
||||
const (
|
||||
LoginCookieLifetime = 60 * time.Minute
|
||||
|
||||
SessionCookieNameTemplate = "io.nais.wonderwall.session"
|
||||
LoginCookieNameTemplate = "io.nais.wonderwall.callback"
|
||||
SessionCookieName = "io.nais.wonderwall.session"
|
||||
LoginCookieName = "io.nais.wonderwall.callback"
|
||||
)
|
||||
|
||||
func (h *Handler) GetLoginCookieName() string {
|
||||
return LoginCookieNameTemplate
|
||||
}
|
||||
|
||||
func (h *Handler) GetSessionCookieName() string {
|
||||
return SessionCookieNameTemplate
|
||||
}
|
||||
|
||||
func (h *Handler) getLoginCookie(r *http.Request) (*openid.LoginCookie, error) {
|
||||
loginCookieJson, err := h.getEncryptedCookie(r, h.GetLoginCookieName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var loginCookie openid.LoginCookie
|
||||
err = json.Unmarshal([]byte(loginCookieJson), &loginCookie)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &loginCookie, nil
|
||||
}
|
||||
|
||||
func (h *Handler) setLoginCookie(w http.ResponseWriter, loginCookie *openid.LoginCookie) error {
|
||||
loginCookieJson, err := json.Marshal(loginCookie)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshalling login cookie: %w", err)
|
||||
}
|
||||
|
||||
err = h.setEncryptedCookie(w, h.GetLoginCookieName(), string(loginCookieJson), LoginCookieLifetime)
|
||||
func (h *Handler) setEncryptedCookie(w http.ResponseWriter, key string, plaintext string, opts cookie.Options) error {
|
||||
encryptedCookie, err := cookie.Make(key, plaintext, opts).Encrypt(h.Crypter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cookie.Set(w, encryptedCookie)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) setEncryptedCookie(w http.ResponseWriter, key string, plaintext string, expiresIn time.Duration) error {
|
||||
ciphertext, err := h.Crypter.Encrypt([]byte(plaintext))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to encrypt cookie '%s': %w", key, err)
|
||||
}
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Expires: time.Now().Add(expiresIn),
|
||||
HttpOnly: true,
|
||||
MaxAge: int(expiresIn.Seconds()),
|
||||
Name: key,
|
||||
Path: "/",
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
Secure: h.SecureCookies,
|
||||
Value: base64.StdEncoding.EncodeToString(ciphertext),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) getEncryptedCookie(r *http.Request, key string) (string, error) {
|
||||
encoded, err := r.Cookie(key)
|
||||
func (h *Handler) getDecryptedCookie(r *http.Request, key string) (string, error) {
|
||||
encryptedCookie, err := cookie.Get(r, key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("no cookie named '%s': %w", key, err)
|
||||
}
|
||||
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(encoded.Value)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cookie named '%s' is not base64 encoded: %w", key, err)
|
||||
}
|
||||
|
||||
plaintext, err := h.Crypter.Decrypt(ciphertext)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to decrypt cookie '%s': %w", key, err)
|
||||
}
|
||||
|
||||
return string(plaintext), nil
|
||||
return encryptedCookie.Decrypt(h.Crypter)
|
||||
}
|
||||
|
||||
func (h *Handler) deleteCookie(w http.ResponseWriter, key string) {
|
||||
expires := time.Now().Add(-7 * 24 * time.Hour)
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Expires: expires,
|
||||
HttpOnly: true,
|
||||
MaxAge: -1,
|
||||
Name: key,
|
||||
Path: "/",
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
Secure: h.SecureCookies,
|
||||
})
|
||||
func (h *Handler) deleteCookie(w http.ResponseWriter, name string, opts cookie.Options) {
|
||||
cookie.Clear(w, name, opts)
|
||||
}
|
||||
|
||||
+17
-21
@@ -7,20 +7,21 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/nais/wonderwall/pkg/config"
|
||||
"github.com/nais/wonderwall/pkg/cookie"
|
||||
"github.com/nais/wonderwall/pkg/crypto"
|
||||
"github.com/nais/wonderwall/pkg/openid"
|
||||
"github.com/nais/wonderwall/pkg/session"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
Config config.Config
|
||||
Crypter crypto.Crypter
|
||||
OauthConfig oauth2.Config
|
||||
Provider openid.Provider
|
||||
SecureCookies bool
|
||||
Sessions session.Store
|
||||
lock sync.Mutex
|
||||
Httplogger zerolog.Logger
|
||||
Config config.Config
|
||||
Cookies cookie.Options
|
||||
Crypter crypto.Crypter
|
||||
OauthConfig oauth2.Config
|
||||
Provider openid.Provider
|
||||
Sessions session.Store
|
||||
lock sync.Mutex
|
||||
Httplogger zerolog.Logger
|
||||
}
|
||||
|
||||
func NewHandler(
|
||||
@@ -41,18 +42,13 @@ func NewHandler(
|
||||
}
|
||||
|
||||
return &Handler{
|
||||
Config: cfg,
|
||||
Crypter: crypter,
|
||||
Httplogger: httplogger,
|
||||
lock: sync.Mutex{},
|
||||
OauthConfig: oauthConfig,
|
||||
Provider: provider,
|
||||
Sessions: sessionStore,
|
||||
SecureCookies: true,
|
||||
Config: cfg,
|
||||
Cookies: cookie.DefaultOptions(),
|
||||
Crypter: crypter,
|
||||
Httplogger: httplogger,
|
||||
lock: sync.Mutex{},
|
||||
OauthConfig: oauthConfig,
|
||||
Provider: provider,
|
||||
Sessions: sessionStore,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) WithSecureCookie(enabled bool) *Handler {
|
||||
h.SecureCookies = enabled
|
||||
return h
|
||||
}
|
||||
|
||||
@@ -57,8 +57,7 @@ func (h *Handler) Callback(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// delete login cookie as we no longer need it
|
||||
h.deleteCookie(w, h.GetLoginCookieName())
|
||||
h.clearLoginCookie(w)
|
||||
|
||||
http.Redirect(w, r, loginCookie.Referer, http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func (h *Handler) FrontChannelLogout(w http.ResponseWriter, r *http.Request) {
|
||||
sid := params.Get("sid")
|
||||
|
||||
// Unconditionally destroy all local references to the session.
|
||||
h.deleteCookie(w, h.GetSessionCookieName())
|
||||
h.deleteCookie(w, SessionCookieName, h.Cookies)
|
||||
|
||||
if len(sid) == 0 {
|
||||
log.Info("sid parameter not set in request; ignoring")
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/nais/wonderwall/pkg/cookie"
|
||||
"github.com/nais/wonderwall/pkg/openid"
|
||||
"github.com/nais/wonderwall/pkg/router/request"
|
||||
)
|
||||
|
||||
const (
|
||||
LoginCookieLifetime = 1 * time.Hour
|
||||
)
|
||||
|
||||
func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
|
||||
params, err := openid.GenerateLoginParameters()
|
||||
if err != nil {
|
||||
@@ -29,7 +36,7 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err = h.setLoginCookie(w, &openid.LoginCookie{
|
||||
err = h.setLoginCookies(w, &openid.LoginCookie{
|
||||
State: params.State,
|
||||
Nonce: params.Nonce,
|
||||
CodeVerifier: params.CodeVerifier,
|
||||
@@ -42,3 +49,40 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
http.Redirect(w, r, loginURL, http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
func (h *Handler) getLoginCookie(r *http.Request) (*openid.LoginCookie, error) {
|
||||
loginCookieJson, err := h.getDecryptedCookie(r, LoginCookieName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var loginCookie openid.LoginCookie
|
||||
err = json.Unmarshal([]byte(loginCookieJson), &loginCookie)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &loginCookie, nil
|
||||
}
|
||||
|
||||
func (h *Handler) setLoginCookies(w http.ResponseWriter, loginCookie *openid.LoginCookie) error {
|
||||
loginCookieJson, err := json.Marshal(loginCookie)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshalling login cookie: %w", err)
|
||||
}
|
||||
|
||||
opts := h.Cookies.WithExpiresIn(LoginCookieLifetime)
|
||||
value := string(loginCookieJson)
|
||||
|
||||
err = h.setEncryptedCookie(w, LoginCookieName, value, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) clearLoginCookie(w http.ResponseWriter) {
|
||||
opts := h.Cookies
|
||||
cookie.Clear(w, LoginCookieName, opts)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
h.deleteCookie(w, h.GetSessionCookieName())
|
||||
h.deleteCookie(w, SessionCookieName, h.Cookies)
|
||||
|
||||
v := u.Query()
|
||||
|
||||
@@ -37,9 +37,10 @@ func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) {
|
||||
v.Add("post_logout_redirect_uri", postLogoutURI)
|
||||
}
|
||||
|
||||
if len(idToken) != 0 {
|
||||
if len(idToken) > 0 {
|
||||
v.Add("id_token_hint", idToken)
|
||||
}
|
||||
|
||||
u.RawQuery = v.Encode()
|
||||
|
||||
http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect)
|
||||
|
||||
@@ -38,7 +38,9 @@ func newHandler(provider openid.Provider) *router.Handler {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return h.WithSecureCookie(false)
|
||||
|
||||
h.Cookies = h.Cookies.WithSecure(false)
|
||||
return h
|
||||
}
|
||||
|
||||
func TestHandler_Login(t *testing.T) {
|
||||
@@ -65,7 +67,7 @@ func TestHandler_Login(t *testing.T) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
cookies := client.Jar.Cookies(loginURL)
|
||||
loginCookie := getCookieFromJar(h.GetLoginCookieName(), cookies)
|
||||
loginCookie := getCookieFromJar(router.LoginCookieName, cookies)
|
||||
assert.NotNil(t, loginCookie)
|
||||
|
||||
location := resp.Header.Get("location")
|
||||
@@ -122,8 +124,8 @@ func TestHandler_Callback_and_Logout(t *testing.T) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
cookies := client.Jar.Cookies(loginURL)
|
||||
sessionCookie := getCookieFromJar(h.GetSessionCookieName(), cookies)
|
||||
loginCookie := getCookieFromJar(h.GetLoginCookieName(), cookies)
|
||||
sessionCookie := getCookieFromJar(router.SessionCookieName, cookies)
|
||||
loginCookie := getCookieFromJar(router.LoginCookieName, cookies)
|
||||
|
||||
assert.Nil(t, sessionCookie)
|
||||
assert.NotNil(t, loginCookie)
|
||||
@@ -150,8 +152,8 @@ func TestHandler_Callback_and_Logout(t *testing.T) {
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
|
||||
cookies = client.Jar.Cookies(callbackURL)
|
||||
sessionCookie = getCookieFromJar(h.GetSessionCookieName(), cookies)
|
||||
loginCookie = getCookieFromJar(h.GetLoginCookieName(), cookies)
|
||||
sessionCookie = getCookieFromJar(router.SessionCookieName, cookies)
|
||||
loginCookie = getCookieFromJar(router.LoginCookieName, cookies)
|
||||
|
||||
assert.NotNil(t, sessionCookie)
|
||||
assert.Nil(t, loginCookie)
|
||||
@@ -166,7 +168,7 @@ func TestHandler_Callback_and_Logout(t *testing.T) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
cookies = client.Jar.Cookies(logoutURL)
|
||||
sessionCookie = getCookieFromJar(h.GetSessionCookieName(), cookies)
|
||||
sessionCookie = getCookieFromJar(router.SessionCookieName, cookies)
|
||||
|
||||
assert.Nil(t, sessionCookie)
|
||||
|
||||
@@ -232,7 +234,7 @@ func TestHandler_FrontChannelLogout(t *testing.T) {
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
|
||||
|
||||
cookies := client.Jar.Cookies(callbackURL)
|
||||
sessionCookie := getCookieFromJar(h.GetSessionCookieName(), cookies)
|
||||
sessionCookie := getCookieFromJar(router.SessionCookieName, cookies)
|
||||
|
||||
assert.NotNil(t, sessionCookie)
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ func (h *Handler) localSessionID(sid string) string {
|
||||
}
|
||||
|
||||
func (h *Handler) getSessionFromCookie(w http.ResponseWriter, r *http.Request) (*session.Data, error) {
|
||||
sessionID, err := h.getEncryptedCookie(r, h.GetSessionCookieName())
|
||||
sessionID, err := h.getDecryptedCookie(r, SessionCookieName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("no session cookie: %w", err)
|
||||
}
|
||||
@@ -80,7 +80,9 @@ func (h *Handler) createSession(w http.ResponseWriter, r *http.Request, external
|
||||
return fmt.Errorf("getting access token lifetime: %w", err)
|
||||
}
|
||||
|
||||
err = h.setEncryptedCookie(w, h.GetSessionCookieName(), sessionID, sessionLifetime)
|
||||
opts := h.Cookies.WithExpiresIn(sessionLifetime)
|
||||
|
||||
err = h.setEncryptedCookie(w, SessionCookieName, sessionID, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting session cookie: %w", err)
|
||||
}
|
||||
|
||||
@@ -10,29 +10,31 @@ import (
|
||||
)
|
||||
|
||||
func (h *Handler) SessionFallbackExternalIDCookieName() string {
|
||||
return h.GetSessionCookieName() + ".1"
|
||||
return SessionCookieName + ".1"
|
||||
}
|
||||
|
||||
func (h *Handler) SessionFallbackIDTokenCookieName() string {
|
||||
return h.GetSessionCookieName() + ".2"
|
||||
return SessionCookieName + ".2"
|
||||
}
|
||||
|
||||
func (h *Handler) SessionFallbackAccessTokenCookieName() string {
|
||||
return h.GetSessionCookieName() + ".3"
|
||||
return SessionCookieName + ".3"
|
||||
}
|
||||
|
||||
func (h *Handler) SetSessionFallback(w http.ResponseWriter, data *session.Data, expiresIn time.Duration) error {
|
||||
err := h.setEncryptedCookie(w, h.SessionFallbackExternalIDCookieName(), data.ExternalSessionID, expiresIn)
|
||||
opts := h.Cookies.WithExpiresIn(expiresIn)
|
||||
|
||||
err := h.setEncryptedCookie(w, h.SessionFallbackExternalIDCookieName(), data.ExternalSessionID, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting session id fallback cookie: %w", err)
|
||||
}
|
||||
|
||||
err = h.setEncryptedCookie(w, h.SessionFallbackAccessTokenCookieName(), data.AccessToken, expiresIn)
|
||||
err = h.setEncryptedCookie(w, h.SessionFallbackAccessTokenCookieName(), data.AccessToken, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting session id_token fallback cookie: %w", err)
|
||||
}
|
||||
|
||||
err = h.setEncryptedCookie(w, h.SessionFallbackIDTokenCookieName(), data.IDToken, expiresIn)
|
||||
err = h.setEncryptedCookie(w, h.SessionFallbackIDTokenCookieName(), data.IDToken, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting session access_token fallback cookie: %w", err)
|
||||
}
|
||||
@@ -41,17 +43,17 @@ func (h *Handler) SetSessionFallback(w http.ResponseWriter, data *session.Data,
|
||||
}
|
||||
|
||||
func (h *Handler) GetSessionFallback(r *http.Request) (*session.Data, error) {
|
||||
externalSessionID, err := h.getEncryptedCookie(r, h.SessionFallbackExternalIDCookieName())
|
||||
externalSessionID, err := h.getDecryptedCookie(r, h.SessionFallbackExternalIDCookieName())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading session ID from fallback cookie: %w", err)
|
||||
}
|
||||
|
||||
idToken, err := h.getEncryptedCookie(r, h.SessionFallbackIDTokenCookieName())
|
||||
idToken, err := h.getDecryptedCookie(r, h.SessionFallbackIDTokenCookieName())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading id_token from fallback cookie: %w", err)
|
||||
}
|
||||
|
||||
accessToken, err := h.getEncryptedCookie(r, h.SessionFallbackAccessTokenCookieName())
|
||||
accessToken, err := h.getDecryptedCookie(r, h.SessionFallbackAccessTokenCookieName())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading access_token from fallback cookie: %w", err)
|
||||
}
|
||||
@@ -66,7 +68,7 @@ func (h *Handler) DeleteSessionFallback(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
h.deleteCookie(w, cookieName)
|
||||
h.deleteCookie(w, cookieName, h.Cookies)
|
||||
}
|
||||
|
||||
deleteIfNotFound(h, w, h.SessionFallbackAccessTokenCookieName())
|
||||
|
||||
Reference in New Issue
Block a user