mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-06 22:30:56 +03:00
jwt: increase leeway and add some tests
also export a constant for the Cookie name Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
@@ -49,8 +49,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
basicRealm = "Basic realm=\"SFTPGo\""
|
basicRealm = "Basic realm=\"SFTPGo\""
|
||||||
jwtCookieKey = "jwt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -142,7 +141,7 @@ func createAndSetCookie(w http.ResponseWriter, r *http.Request, claims *jwt.Clai
|
|||||||
|
|
||||||
func setCookie(w http.ResponseWriter, r *http.Request, cookiePath, cookieValue string, duration time.Duration) {
|
func setCookie(w http.ResponseWriter, r *http.Request, cookiePath, cookieValue string, duration time.Duration) {
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: jwtCookieKey,
|
Name: jwt.CookieKey,
|
||||||
Value: cookieValue,
|
Value: cookieValue,
|
||||||
Path: cookiePath,
|
Path: cookiePath,
|
||||||
Expires: time.Now().Add(duration),
|
Expires: time.Now().Add(duration),
|
||||||
@@ -156,7 +155,7 @@ func setCookie(w http.ResponseWriter, r *http.Request, cookiePath, cookieValue s
|
|||||||
func removeCookie(w http.ResponseWriter, r *http.Request, cookiePath string) {
|
func removeCookie(w http.ResponseWriter, r *http.Request, cookiePath string) {
|
||||||
invalidateToken(r)
|
invalidateToken(r)
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: jwtCookieKey,
|
Name: jwt.CookieKey,
|
||||||
Value: "",
|
Value: "",
|
||||||
Path: cookiePath,
|
Path: cookiePath,
|
||||||
Expires: time.Unix(0, 0),
|
Expires: time.Unix(0, 0),
|
||||||
|
|||||||
@@ -809,7 +809,7 @@ func removeOIDCCookie(w http.ResponseWriter, r *http.Request) {
|
|||||||
func canSkipOIDCValidation(r *http.Request) bool {
|
func canSkipOIDCValidation(r *http.Request) bool {
|
||||||
_, err := r.Cookie(oidcCookieKey)
|
_, err := r.Cookie(oidcCookieKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err = r.Cookie(jwtCookieKey)
|
_, err = r.Cookie(jwt.CookieKey)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -845,7 +845,7 @@ func TestSkipOIDCAuth(t *testing.T) {
|
|||||||
rr := httptest.NewRecorder()
|
rr := httptest.NewRecorder()
|
||||||
r, err := http.NewRequest(http.MethodGet, webClientLogoutPath, nil)
|
r, err := http.NewRequest(http.MethodGet, webClientLogoutPath, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
r.Header.Set("Cookie", fmt.Sprintf("%v=%v", jwtCookieKey, tokenString))
|
r.Header.Set("Cookie", fmt.Sprintf("%v=%v", jwt.CookieKey, tokenString))
|
||||||
server.router.ServeHTTP(rr, r)
|
server.router.ServeHTTP(rr, r)
|
||||||
assert.Equal(t, http.StatusFound, rr.Code)
|
assert.Equal(t, http.StatusFound, rr.Code)
|
||||||
assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
|
assert.Equal(t, webClientLoginPath, rr.Header().Get("Location"))
|
||||||
|
|||||||
@@ -1071,7 +1071,7 @@ func (s *httpdServer) refreshAdminToken(w http.ResponseWriter, r *http.Request,
|
|||||||
func (s *httpdServer) updateContextFromCookie(r *http.Request) *http.Request {
|
func (s *httpdServer) updateContextFromCookie(r *http.Request) *http.Request {
|
||||||
_, err := jwt.FromContext(r.Context())
|
_, err := jwt.FromContext(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err = r.Cookie(jwtCookieKey)
|
_, err = r.Cookie(jwt.CookieKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ import (
|
|||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CookieKey = "jwt"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
TokenCtxKey = &contextKey{"Token"}
|
TokenCtxKey = &contextKey{"Token"}
|
||||||
ErrorCtxKey = &contextKey{"Error"}
|
ErrorCtxKey = &contextKey{"Error"}
|
||||||
@@ -235,7 +239,7 @@ func VerifyTokenWithKey(payload string, algo []jose.SignatureAlgorithm, key any)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := claims.ValidateWithLeeway(jwt.Expected{Time: time.Now()}, 15*time.Second); err != nil {
|
if err := claims.ValidateWithLeeway(jwt.Expected{Time: time.Now()}, 30*time.Second); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &claims, nil
|
return &claims, nil
|
||||||
@@ -244,7 +248,7 @@ func VerifyTokenWithKey(payload string, algo []jose.SignatureAlgorithm, key any)
|
|||||||
// TokenFromCookie tries to retrieve the token string from a cookie named
|
// TokenFromCookie tries to retrieve the token string from a cookie named
|
||||||
// "jwt".
|
// "jwt".
|
||||||
func TokenFromCookie(r *http.Request) string {
|
func TokenFromCookie(r *http.Request) string {
|
||||||
cookie, err := r.Cookie("jwt")
|
cookie, err := r.Cookie(CookieKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,3 +223,33 @@ func TestContext(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, "jwt context value Token", TokenCtxKey.String())
|
assert.Equal(t, "jwt context value Token", TokenCtxKey.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidationLeeway(t *testing.T) {
|
||||||
|
s, err := NewSigner(jose.HS256, util.GenerateRandomBytes(32))
|
||||||
|
require.NoError(t, err)
|
||||||
|
claims := &Claims{}
|
||||||
|
claims.Audience = []string{util.GenerateUniqueID()}
|
||||||
|
claims.SetIssuedAt(time.Now().Add(10 * time.Second)) // issued at in the future
|
||||||
|
claims.SetExpiry(time.Now().Add(10 * time.Second))
|
||||||
|
token, err := s.Sign(claims)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = VerifyToken(s, token)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
claims = &Claims{}
|
||||||
|
claims.Audience = []string{util.GenerateUniqueID()}
|
||||||
|
claims.SetExpiry(time.Now().Add(-10 * time.Second)) // expired
|
||||||
|
token, err = s.Sign(claims)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = VerifyToken(s, token)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
claims = &Claims{}
|
||||||
|
claims.Audience = []string{util.GenerateUniqueID()}
|
||||||
|
claims.SetExpiry(time.Now().Add(30 * time.Second))
|
||||||
|
claims.SetNotBefore(time.Now().Add(10 * time.Second)) // not before in the future
|
||||||
|
token, err = s.Sign(claims)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = VerifyToken(s, token)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user