From 7d551a83123a3a17582659fa28efe4fedecbfcf5 Mon Sep 17 00:00:00 2001 From: William Petit Date: Sat, 1 Apr 2023 19:30:45 +0200 Subject: [PATCH] feat(auth): accept clock skew for token validation --- internal/auth/agent/authenticator.go | 11 ++++++++--- internal/auth/thirdparty/authenticator.go | 17 +++++++++++------ internal/auth/thirdparty/jwt.go | 3 ++- internal/server/server.go | 4 ++-- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/internal/auth/agent/authenticator.go b/internal/auth/agent/authenticator.go index e771646..3892d1a 100644 --- a/internal/auth/agent/authenticator.go +++ b/internal/auth/agent/authenticator.go @@ -14,8 +14,11 @@ import ( "gitlab.com/wpetit/goweb/logger" ) +const DefaultAcceptableSkew = 5 * time.Minute + type Authenticator struct { - repo datastore.AgentRepository + repo datastore.AgentRepository + acceptableSkew time.Duration } // Authenticate implements auth.Authenticator. @@ -72,6 +75,7 @@ func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth []byte(rawToken), jwt.WithKeySet(agent.KeySet.Set, jws.WithRequireKid(false)), jwt.WithValidate(true), + jwt.WithAcceptableSkew(a.acceptableSkew), ) if err != nil { return nil, errors.WithStack(err) @@ -91,9 +95,10 @@ func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth return user, nil } -func NewAuthenticator(repo datastore.AgentRepository) *Authenticator { +func NewAuthenticator(repo datastore.AgentRepository, acceptableSkew time.Duration) *Authenticator { return &Authenticator{ - repo: repo, + repo: repo, + acceptableSkew: acceptableSkew, } } diff --git a/internal/auth/thirdparty/authenticator.go b/internal/auth/thirdparty/authenticator.go index 245e983..4dae9e1 100644 --- a/internal/auth/thirdparty/authenticator.go +++ b/internal/auth/thirdparty/authenticator.go @@ -4,6 +4,7 @@ import ( "context" "net/http" "strings" + "time" "forge.cadoles.com/Cadoles/emissary/internal/auth" "forge.cadoles.com/Cadoles/emissary/internal/jwk" @@ -11,9 +12,12 @@ import ( "gitlab.com/wpetit/goweb/logger" ) +const DefaultAcceptableSkew = 5 * time.Minute + type Authenticator struct { - keys jwk.Set - issuer string + keys jwk.Set + issuer string + acceptableSkew time.Duration } // Authenticate implements auth.Authenticator. @@ -30,7 +34,7 @@ func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth return nil, errors.WithStack(auth.ErrUnauthenticated) } - token, err := parseToken(ctx, a.keys, a.issuer, rawToken) + token, err := parseToken(ctx, a.keys, a.issuer, rawToken, a.acceptableSkew) if err != nil { return nil, errors.WithStack(err) } @@ -57,10 +61,11 @@ func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth return user, nil } -func NewAuthenticator(keys jwk.Set, issuer string) *Authenticator { +func NewAuthenticator(keys jwk.Set, issuer string, acceptableSkew time.Duration) *Authenticator { return &Authenticator{ - keys: keys, - issuer: issuer, + keys: keys, + issuer: issuer, + acceptableSkew: acceptableSkew, } } diff --git a/internal/auth/thirdparty/jwt.go b/internal/auth/thirdparty/jwt.go index 42ba931..df7e445 100644 --- a/internal/auth/thirdparty/jwt.go +++ b/internal/auth/thirdparty/jwt.go @@ -13,12 +13,13 @@ import ( const keyRole = "role" -func parseToken(ctx context.Context, keys jwk.Set, issuer string, rawToken string) (jwt.Token, error) { +func parseToken(ctx context.Context, keys jwk.Set, issuer string, rawToken string, acceptableSkew time.Duration) (jwt.Token, error) { token, err := jwt.Parse( []byte(rawToken), jwt.WithKeySet(keys, jws.WithRequireKid(false)), jwt.WithIssuer(issuer), jwt.WithValidate(true), + jwt.WithAcceptableSkew(acceptableSkew), ) if err != nil { return nil, errors.WithStack(err) diff --git a/internal/server/server.go b/internal/server/server.go index 7804d26..7d3721d 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -105,8 +105,8 @@ func (s *Server) run(parentCtx context.Context, addrs chan net.Addr, errs chan e r.Group(func(r chi.Router) { r.Use(auth.Middleware( - thirdparty.NewAuthenticator(keys, string(s.conf.Issuer)), - agent.NewAuthenticator(s.agentRepo), + thirdparty.NewAuthenticator(keys, string(s.conf.Issuer), thirdparty.DefaultAcceptableSkew), + agent.NewAuthenticator(s.agentRepo, agent.DefaultAcceptableSkew), )) r.Route("/agents", func(r chi.Router) {