Skip to content
Snippets Groups Projects
Commit ab576798 authored by Rohith's avatar Rohith
Browse files

- adding the ability to select if a cookie is secure or now (#56)

- increasing the tests to cover the above
parent 8ce34625
Branches
Tags
No related merge requests found
......@@ -37,6 +37,7 @@ func newDefaultConfig() *Config {
TagData: make(map[string]string, 0),
ClaimsMatch: make(map[string]string, 0),
Header: make(map[string]string, 0),
SecureCookie: true,
CrossOrigin: CORS{},
SkipUpstreamTLSVerify: true,
}
......@@ -170,6 +171,9 @@ func readOptions(cx *cli.Context, config *Config) (err error) {
if cx.IsSet("encryption-key") {
config.EncryptionKey = cx.String("encryption-key")
}
if cx.IsSet("secure-cookie") {
config.SecureCookie = cx.Bool("secure-cookie")
}
if cx.IsSet("store-url") {
config.StoreURL = cx.String("store-url")
}
......@@ -330,6 +334,10 @@ func getOptions() []cli.Flag {
Name: "enable-refresh-tokens",
Usage: "enables the handling of the refresh tokens",
},
cli.BoolTFlag{
Name: "secure-cookie",
Usage: "enforces the cookie to be secure, default to true",
},
cli.StringFlag{
Name: "encryption-key",
Usage: "the encryption key used to encrpytion the session state",
......
......@@ -27,12 +27,12 @@ import (
//
// dropCookie drops a cookie into the response
//
func dropCookie(cx *gin.Context, name, value string, duration time.Duration) {
func dropCookie(cx *gin.Context, name, value string, duration time.Duration, secure bool) {
cookie := &http.Cookie{
Name: name,
Domain: strings.Split(cx.Request.Host, ":")[0],
Path: "/",
Secure: true,
Secure: secure,
Value: value,
}
if duration != 0 {
......@@ -45,35 +45,35 @@ func dropCookie(cx *gin.Context, name, value string, duration time.Duration) {
//
// dropAccessTokenCookie drops a access token cookie into the response
//
func dropAccessTokenCookie(cx *gin.Context, token jose.JWT, duration time.Duration) {
dropCookie(cx, cookieAccessToken, token.Encode(), duration)
func dropAccessTokenCookie(cx *gin.Context, token jose.JWT, duration time.Duration, secure bool) {
dropCookie(cx, cookieAccessToken, token.Encode(), duration, secure)
}
//
// dropRefreshTokenCookie drops a refresh token cookie into the response
//
func dropRefreshTokenCookie(cx *gin.Context, token string, duration time.Duration) {
dropCookie(cx, cookieRefreshToken, token, duration)
func dropRefreshTokenCookie(cx *gin.Context, token string, duration time.Duration, secure bool) {
dropCookie(cx, cookieRefreshToken, token, duration, secure)
}
//
// clearAllCookies is just a helper function for the below
//
func clearAllCookies(cx *gin.Context) {
clearAccessTokenCookie(cx)
clearRefreshTokenCookie(cx)
func clearAllCookies(cx *gin.Context, secure bool) {
clearAccessTokenCookie(cx, secure)
clearRefreshTokenCookie(cx, secure)
}
//
// clearRefreshSessionCookie clears the session cookie
//
func clearRefreshTokenCookie(cx *gin.Context) {
dropCookie(cx, cookieRefreshToken, "", time.Duration(-10*time.Hour))
func clearRefreshTokenCookie(cx *gin.Context, secure bool) {
dropCookie(cx, cookieRefreshToken, "", time.Duration(-10*time.Hour), secure)
}
//
// clearAccessTokenCookie clears the session cookie
//
func clearAccessTokenCookie(cx *gin.Context) {
dropCookie(cx, cookieAccessToken, "", time.Duration(-10*time.Hour))
func clearAccessTokenCookie(cx *gin.Context, secure bool) {
dropCookie(cx, cookieAccessToken, "", time.Duration(-10*time.Hour), secure)
}
......@@ -23,14 +23,21 @@ import (
func TestDropCookie(t *testing.T) {
context := newFakeGinContext("GET", "/admin")
dropCookie(context, "test-cookie", "test-value", 0)
dropCookie(context, "test-cookie", "test-value", 0, true)
assert.Equal(t, context.Writer.Header().Get("Set-Cookie"),
"test-cookie=test-value; Path=/; Domain=127.0.0.1; Secure",
"we have not set the cookie, headers: %v", context.Writer.Header())
context = newFakeGinContext("GET", "/admin")
dropCookie(context, "test-cookie", "test-value", 0)
dropCookie(context, "test-cookie", "test-value", 0, false)
assert.Equal(t, context.Writer.Header().Get("Set-Cookie"),
"test-cookie=test-value; Path=/; Domain=127.0.0.1",
"we have not set the cookie, headers: %v", context.Writer.Header())
context = newFakeGinContext("GET", "/admin")
dropCookie(context, "test-cookie", "test-value", 0, true)
assert.NotEqual(t, context.Writer.Header().Get("Set-Cookie"),
"test-cookie=test-value; Path=/; Domain=127.0.0.2; HttpOnly; Secure",
"we have not set the cookie, headers: %v", context.Writer.Header())
......@@ -38,7 +45,7 @@ func TestDropCookie(t *testing.T) {
func TestClearAccessTokenCookie(t *testing.T) {
context := newFakeGinContext("GET", "/admin")
clearAccessTokenCookie(context)
clearAccessTokenCookie(context, true)
assert.Contains(t, context.Writer.Header().Get("Set-Cookie"),
"kc-access=; Path=/; Domain=127.0.0.1; Expires=",
"we have not cleared the, headers: %v", context.Writer.Header())
......@@ -46,7 +53,7 @@ func TestClearAccessTokenCookie(t *testing.T) {
func TestClearRefreshAccessTokenCookie(t *testing.T) {
context := newFakeGinContext("GET", "/admin")
clearRefreshTokenCookie(context)
clearRefreshTokenCookie(context, true)
assert.Contains(t, context.Writer.Header().Get("Set-Cookie"),
"kc-state=; Path=/; Domain=127.0.0.1; Expires=",
"we have not cleared the, headers: %v", context.Writer.Header())
......@@ -54,7 +61,7 @@ func TestClearRefreshAccessTokenCookie(t *testing.T) {
func TestClearAllCookies(t *testing.T) {
context := newFakeGinContext("GET", "/admin")
clearAllCookies(context)
clearAllCookies(context, true)
assert.Contains(t, context.Writer.Header().Get("Set-Cookie"),
"kc-access=; Path=/; Domain=127.0.0.1; Expires=",
"we have not cleared the, headers: %v", context.Writer.Header())
......
......@@ -118,6 +118,8 @@ type Config struct {
IdleDuration time.Duration `json:"idle-duration" yaml:"idle-duration"`
// EncryptionKey is the encryption key used to encrypt the refresh token
EncryptionKey string `json:"encryption-key" yaml:"encryption-key"`
// SecureCookie enforces the cookie as secure
SecureCookie bool `json:"secure-cookie" yaml:"secure-cookie"`
// ClaimsMatch is a series of checks, the claims in the token must match those here
ClaimsMatch map[string]string `json:"claims" yaml:"claims"`
// Keepalives specifies wheather we use keepalives on the upstream
......
......@@ -151,7 +151,7 @@ func (r oauthProxy) oauthCallbackHandler(cx *gin.Context) {
}).Infof("issuing a new access token for user, email: %s", identity.Email)
// step: drop's a session cookie with the access token
dropAccessTokenCookie(cx, session, r.config.IdleDuration)
dropAccessTokenCookie(cx, session, r.config.IdleDuration, r.config.SecureCookie)
// step: does the response has a refresh token and we are NOT ignore refresh tokens?
if r.config.EnableRefreshTokens && response.RefreshToken != "" {
......@@ -175,7 +175,7 @@ func (r oauthProxy) oauthCallbackHandler(cx *gin.Context) {
}).Warnf("failed to save the refresh token in the store")
}
default:
dropRefreshTokenCookie(cx, encrypted, r.config.IdleDuration*2)
dropRefreshTokenCookie(cx, encrypted, r.config.IdleDuration*2, r.config.SecureCookie)
}
}
......@@ -249,7 +249,7 @@ func (r oauthProxy) logoutHandler(cx *gin.Context) {
return
}
// step: delete the access token
clearAccessTokenCookie(cx)
clearAccessTokenCookie(cx, r.config.SecureCookie)
log.WithFields(log.Fields{
"email": user.email,
......@@ -315,7 +315,7 @@ func (r oauthProxy) logoutHandler(cx *gin.Context) {
}).Errorf("invalid response from revocation endpoint")
}
}
clearAllCookies(cx)
clearAllCookies(cx, r.config.SecureCookie)
if redirectURL != "" {
r.redirectToURL(redirectURL, cx)
......
......@@ -247,7 +247,7 @@ func (r *oauthProxy) authenticationHandler() gin.HandlerFunc {
switch err {
case ErrRefreshTokenExpired:
log.WithFields(log.Fields{"token": token}).Warningf("the refresh token has expired")
clearAllCookies(cx)
clearAllCookies(cx, r.config.SecureCookie)
default:
log.WithFields(log.Fields{"error": err.Error()}).Errorf("failed to refresh the access token")
}
......@@ -263,7 +263,7 @@ func (r *oauthProxy) authenticationHandler() gin.HandlerFunc {
}).Infof("injecting refreshed access token, expires on: %s", expires.Format(time.RFC1123))
// step: clear the cookie up
dropAccessTokenCookie(cx, token, r.config.IdleDuration)
dropAccessTokenCookie(cx, token, r.config.IdleDuration, r.config.SecureCookie)
if r.useStore() {
go func(t jose.JWT, rt string) {
......@@ -285,7 +285,7 @@ func (r *oauthProxy) authenticationHandler() gin.HandlerFunc {
}(user.token, rToken)
} else {
// step: update the expiration on the refresh token
dropRefreshTokenCookie(cx, rToken, r.config.IdleDuration*2)
dropRefreshTokenCookie(cx, rToken, r.config.IdleDuration*2, r.config.SecureCookie)
}
// step: update the with the new access token
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment