Skip to content

Commit

Permalink
fix(api): xsrf session lifetime (#5340)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardlt authored Aug 11, 2020
1 parent eaa1d87 commit 7c77c38
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 25 deletions.
9 changes: 9 additions & 0 deletions engine/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,15 @@ func (a *API) PanicDump() func(s string) (io.WriteCloser, error) {
}
}

// SetCookieSession on given response writter, automatically add domain and path based on api config.
// This will returns a cookie with no expiration date that should be dropped by browser when closed.
func (a *API) SetCookieSession(w http.ResponseWriter, name, value string) {
a.setCookie(w, &http.Cookie{
Name: name,
Value: value,
})
}

// SetCookie on given response writter, automatically add domain and path based on api config.
func (a *API) SetCookie(w http.ResponseWriter, name, value string, expires time.Time) {
a.setCookie(w, &http.Cookie{
Expand Down
7 changes: 2 additions & 5 deletions engine/api/authentication/xsrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ import (
"github.com/ovh/cds/sdk"
)

// XSRFTokenDuration is set to 10 minutes.
var XSRFTokenDuration = 60 * 10

// NewSessionXSRFToken generate and store a XSRF token for a given session id.
func NewSessionXSRFToken(store cache.Store, sessionID string) (string, error) {
func NewSessionXSRFToken(store cache.Store, sessionID string, sessionExpirationDelaySecond int) (string, error) {
var XSRFToken = sdk.UUID()
var k = cache.Key("token", "xsrf", sessionID)
if err := store.SetWithTTL(k, &XSRFToken, XSRFTokenDuration); err != nil {
if err := store.SetWithTTL(k, &XSRFToken, sessionExpirationDelaySecond); err != nil {
return "", err
}
return XSRFToken, nil
Expand Down
29 changes: 9 additions & 20 deletions engine/api/router_middleware_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,49 +213,38 @@ func (api *API) xsrfMiddleware(ctx context.Context, w http.ResponseWriter, req *
ctx, end := telemetry.Span(ctx, "router.xsrfMiddleware")
defer end()

jwtValue := ctx.Value(contextJWT)
if jwtValue == nil {
sessionValue := ctx.Value(contextSession)
if sessionValue == nil {
return ctx, sdk.WithStack(sdk.ErrUnauthorized)
}

jwt, ok := jwtValue.(*jwt.Token)
session, ok := sessionValue.(*sdk.AuthSession)
if !ok {
return ctx, sdk.WithStack(sdk.ErrUnauthorized)
}

claims := jwt.Claims.(*sdk.AuthSessionJWTClaims)
sessionID := claims.StandardClaims.Id

xsrfToken := req.Header.Get(xsrfHeaderName)
existingXSRFToken, existXSRFTokenInCache := authentication.GetSessionXSRFToken(api.Cache, sessionID)
existingXSRFToken, existXSRFTokenInCache := authentication.GetSessionXSRFToken(api.Cache, session.ID)

// If it's not a read request we want to check the xsrf token then generate a new one
// else if its a read request we want to reuse a cached XSRF token or generate one
// else if its a read request we want to reuse a cached XSRF token or generate one if not in cache or nothing given by the client
if rc.PermissionLevel > sdk.PermissionRead {
if !existXSRFTokenInCache || xsrfToken != existingXSRFToken {
// We want to return a forbidden to allow the user to retry with a new token.
return ctx, sdk.WithStack(sdk.ErrForbidden)
}

newXSRFToken, err := authentication.NewSessionXSRFToken(api.Cache, sessionID)
if err != nil {
return ctx, err
}
// Set a cookie with the jwt token
api.SetCookie(w, xsrfCookieName, newXSRFToken,
time.Now().Add(time.Duration(authentication.XSRFTokenDuration)*time.Second))
} else {
if !existXSRFTokenInCache {
if !existXSRFTokenInCache || xsrfToken == "" {
sessionSecondsBeforeExpiration := int(session.ExpireAt.Sub(time.Now()).Seconds())
var err error
existingXSRFToken, err = authentication.NewSessionXSRFToken(api.Cache, sessionID)
existingXSRFToken, err = authentication.NewSessionXSRFToken(api.Cache, session.ID, sessionSecondsBeforeExpiration)
if err != nil {
return ctx, err
}
}

// Set a cookie with the jwt token
api.SetCookie(w, xsrfCookieName, existingXSRFToken,
time.Now().Add(time.Duration(authentication.XSRFTokenDuration)*time.Second))
api.SetCookieSession(w, xsrfCookieName, existingXSRFToken)
}

return ctx, nil
Expand Down

0 comments on commit 7c77c38

Please sign in to comment.