mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-06-04 23:37:29 +02:00
Integrate cookie builder with CSRF cookies
This commit is contained in:
parent
eb9bfe5a1c
commit
19e59da0e8
@ -1,12 +1,10 @@
|
|||||||
package cookies
|
package cookies
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/clock"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/clock"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
|
||||||
@ -38,12 +36,13 @@ type csrf struct {
|
|||||||
// is used to mitigate replay attacks.
|
// is used to mitigate replay attacks.
|
||||||
OIDCNonce []byte `msgpack:"n,omitempty"`
|
OIDCNonce []byte `msgpack:"n,omitempty"`
|
||||||
|
|
||||||
cookieOpts *options.Cookie
|
builder Builder
|
||||||
time clock.Clock
|
encryptionSecret string
|
||||||
|
time clock.Clock
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCSRF creates a CSRF with random nonces
|
// NewCSRF creates a CSRF with random nonces
|
||||||
func NewCSRF(opts *options.Cookie) (CSRF, error) {
|
func NewCSRF(builder Builder, secret string) (CSRF, error) {
|
||||||
state, err := encryption.Nonce()
|
state, err := encryption.Nonce()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -57,18 +56,19 @@ func NewCSRF(opts *options.Cookie) (CSRF, error) {
|
|||||||
OAuthState: state,
|
OAuthState: state,
|
||||||
OIDCNonce: nonce,
|
OIDCNonce: nonce,
|
||||||
|
|
||||||
cookieOpts: opts,
|
builder: builder,
|
||||||
|
encryptionSecret: secret,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadCSRFCookie loads a CSRF object from a request's CSRF cookie
|
// LoadCSRFCookie loads a CSRF object from a request's CSRF cookie
|
||||||
func LoadCSRFCookie(req *http.Request, opts *options.Cookie) (CSRF, error) {
|
func LoadCSRFCookie(req *http.Request, builder Builder, secret string) (CSRF, error) {
|
||||||
cookie, err := req.Cookie(csrfCookieName(opts))
|
cookieValue, err := builder.ValidateRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to validate CSRF cookie value: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return decodeCSRFCookie(cookie, opts)
|
return decodeCSRFCookie(cookieValue, builder, secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashOAuthState returns the hash of the OAuth state nonce
|
// HashOAuthState returns the hash of the OAuth state nonce
|
||||||
@ -104,29 +104,27 @@ func (c *csrf) SetCookie(rw http.ResponseWriter, req *http.Request) (*http.Cooki
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie := MakeCookieFromOptions(
|
cookie, err := c.builder.
|
||||||
req,
|
WithStart(c.time.Now()).
|
||||||
c.cookieName(),
|
MakeCookie(req, encoded)
|
||||||
encoded,
|
if err != nil {
|
||||||
c.cookieOpts,
|
return nil, err
|
||||||
c.cookieOpts.Expire,
|
}
|
||||||
c.time.Now(),
|
|
||||||
)
|
|
||||||
http.SetCookie(rw, cookie)
|
http.SetCookie(rw, cookie)
|
||||||
|
|
||||||
return cookie, nil
|
return cookie, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearCookie removes the CSRF cookie
|
// ClearCookie removes the CSRF cookie
|
||||||
func (c *csrf) ClearCookie(rw http.ResponseWriter, req *http.Request) {
|
func (c *csrf) ClearCookie(rw http.ResponseWriter, req *http.Request) error {
|
||||||
http.SetCookie(rw, MakeCookieFromOptions(
|
cookie, err := c.builder.
|
||||||
req,
|
WithExpiration(time.Hour*-1).
|
||||||
c.cookieName(),
|
WithStart(c.time.Now()).
|
||||||
"",
|
MakeCookie(req, "")
|
||||||
c.cookieOpts,
|
if err != nil {
|
||||||
time.Hour*-1,
|
return fmt.Errorf("could not create cookie: %v", err)
|
||||||
c.time.Now(),
|
}
|
||||||
))
|
http.SetCookie(rw, cookie)
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeCookie MessagePack encodes and encrypts the CSRF and then creates a
|
// encodeCookie MessagePack encodes and encrypts the CSRF and then creates a
|
||||||
@ -142,58 +140,42 @@ func (c *csrf) encodeCookie() (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return encryption.SignedValue(c.cookieOpts.Secret, c.cookieName(), encrypted, c.time.Now())
|
return string(encrypted), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeCSRFCookie validates the signature then decrypts and decodes a CSRF
|
// decodeCSRFCookie validates the signature then decrypts and decodes a CSRF
|
||||||
// cookie into a CSRF struct
|
// cookie into a CSRF struct
|
||||||
func decodeCSRFCookie(cookie *http.Cookie, opts *options.Cookie) (*csrf, error) {
|
func decodeCSRFCookie(cookieValue string, builder Builder, secret string) (*csrf, error) {
|
||||||
val, _, ok := encryption.Validate(cookie, opts.Secret, opts.Expire)
|
decrypted, err := decrypt([]byte(cookieValue), secret)
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("CSRF cookie failed validation")
|
|
||||||
}
|
|
||||||
|
|
||||||
decrypted, err := decrypt(val, opts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid cookie, Unmarshal the CSRF
|
// Valid cookie, Unmarshal the CSRF
|
||||||
csrf := &csrf{cookieOpts: opts}
|
csrf := &csrf{builder: builder, encryptionSecret: secret}
|
||||||
err = msgpack.Unmarshal(decrypted, csrf)
|
if err := msgpack.Unmarshal(decrypted, csrf); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error unmarshalling data to CSRF: %v", err)
|
return nil, fmt.Errorf("error unmarshalling data to CSRF: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return csrf, nil
|
return csrf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cookieName returns the CSRF cookie's name derived from the base
|
func encrypt(data []byte, secret string) ([]byte, error) {
|
||||||
// session cookie name
|
cipher, err := makeCipher(secret)
|
||||||
func (c *csrf) cookieName() string {
|
|
||||||
return csrfCookieName(c.cookieOpts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func csrfCookieName(opts *options.Cookie) string {
|
|
||||||
return fmt.Sprintf("%v_csrf", opts.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func encrypt(data []byte, opts *options.Cookie) ([]byte, error) {
|
|
||||||
cipher, err := makeCipher(opts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return cipher.Encrypt(data)
|
return cipher.Encrypt(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decrypt(data []byte, opts *options.Cookie) ([]byte, error) {
|
func decrypt(data []byte, secret string) ([]byte, error) {
|
||||||
cipher, err := makeCipher(opts)
|
cipher, err := makeCipher(secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return cipher.Decrypt(data)
|
return cipher.Decrypt(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCipher(opts *options.Cookie) (encryption.Cipher, error) {
|
func makeCipher(secret string) (encryption.Cipher, error) {
|
||||||
return encryption.NewCFBCipher(encryption.SecretBytes(opts.Secret))
|
return encryption.NewCFBCipher(encryption.SecretBytes(secret))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user