diff --git a/pkg/auth/interfaces.go b/pkg/auth/interfaces.go index 46628bc97..c46300ae6 100644 --- a/pkg/auth/interfaces.go +++ b/pkg/auth/interfaces.go @@ -1,6 +1,7 @@ package auth import ( + "github.com/dgrijalva/jwt-go" "net/http" ) @@ -13,11 +14,12 @@ type ( } TokenEncoder interface { - Encode(identity Identifiable) string + Encode(identity Identifiable, scope ...string) string } TokenHandler interface { TokenEncoder + Authenticate(token string) (jwt.MapClaims, error) HttpVerifier() func(http.Handler) http.Handler HttpAuthenticator() func(http.Handler) http.Handler } diff --git a/pkg/auth/jwt.go b/pkg/auth/jwt.go index 339ba3ad3..8c96a2d11 100644 --- a/pkg/auth/jwt.go +++ b/pkg/auth/jwt.go @@ -45,12 +45,48 @@ func JWT(secret string, expiry time.Duration) (tkn *token, err error) { return tkn, nil } -// HttpVerifier verifies JWT and stores it into context +func (t *token) Authenticate(token string) (jwt.MapClaims, error) { + dt, err := t.tokenAuth.Decode(token) + if err != nil { + return nil, err + } + + if dt == nil || !dt.Valid { + return nil, jwtauth.ErrUnauthorized + } + + if dt.Method != jwt.SigningMethodHS512 { + return nil, jwtauth.ErrAlgoInvalid + } + + if mc, is := dt.Claims.(jwt.MapClaims); is { + return mc, nil + } + + return nil, nil +} + +// HttpVerifier returns a HTTP handler that verifies JWT and stores it into context func (t *token) HttpVerifier() func(http.Handler) http.Handler { return jwtauth.Verifier(t.tokenAuth) } -func (t *token) Encode(i Identifiable) string { +func (t *token) Encode(i Identifiable, scope ...string) string { + var ( + // when possible, extend this with the client + clientID uint64 = 0 + ) + + if len(scope) == 0 { + // for backward compatibility we default + // unset scope to profile & api + scope = []string{"profile", "api"} + } + + return t.encode(i, clientID, scope...) +} + +func (t *token) encode(i Identifiable, clientID uint64, scope ...string) string { roles := "" for _, r := range i.Roles() { @@ -58,17 +94,10 @@ func (t *token) Encode(i Identifiable) string { } _, tkn, _ := t.tokenAuth.Encode(jwt.MapClaims{ - "sub": i.String(), - "exp": time.Now().Add(t.expiry).Unix(), - - // when possible, extend this with the client - "aud": "0", // we should be more strict here and provide a client! - - // at some point, we'll need to do this a bit more carefully; - // for now, we just add all necessary scopes so that users of this (cli, corredor) - // can create a useful JWT - "scope": "profile api", - + "sub": i.String(), + "exp": time.Now().Add(t.expiry).Unix(), + "aud": fmt.Sprintf("%d", clientID), + "scope": strings.Join(scope, " "), "roles": strings.TrimSpace(roles), }) diff --git a/pkg/corredor/service.go b/pkg/corredor/service.go index eb948dd8e..995e6f83d 100644 --- a/pkg/corredor/service.go +++ b/pkg/corredor/service.go @@ -105,7 +105,7 @@ type ( } authTokenMaker interface { - Encode(auth.Identifiable) string + Encode(auth.Identifiable, ...string) string } permissionRuleChecker interface {