diff --git a/compose/rest/attachment.go b/compose/rest/attachment.go index b516723b2..16c3d4286 100644 --- a/compose/rest/attachment.go +++ b/compose/rest/attachment.go @@ -7,11 +7,10 @@ import ( "net/http" "net/url" - "github.com/cortezaproject/corteza-server/pkg/api" - "github.com/cortezaproject/corteza-server/compose/rest/request" "github.com/cortezaproject/corteza-server/compose/service" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/api" "github.com/cortezaproject/corteza-server/pkg/auth" "github.com/pkg/errors" ) diff --git a/pkg/auth/errors.go b/pkg/auth/errors.go index 4ec5b8469..13549b438 100644 --- a/pkg/auth/errors.go +++ b/pkg/auth/errors.go @@ -5,7 +5,7 @@ import ( "github.com/cortezaproject/corteza-server/pkg/locale" ) -func ErrUnauthorized() error { +func errUnauthorized() error { return errors.New( errors.KindUnauthorized, @@ -22,7 +22,7 @@ func ErrUnauthorized() error { ) } -func ErrUnauthorizedScope() error { +func errUnauthorizedScope() error { return errors.New( errors.KindUnauthorized, @@ -38,20 +38,3 @@ func ErrUnauthorizedScope() error { errors.StackTrimAtFn("http.HandlerFunc.ServeHTTP"), ) } - -func ErrMalformedToken(details string) error { - return errors.New( - errors.KindUnauthorized, - - "malformed token: "+details, - - errors.Meta("type", "malformedToken"), - - // translation namespace & key - errors.Meta(locale.ErrorMetaNamespace{}, "internal"), - errors.Meta(locale.ErrorMetaKey{}, "auth.errors.malformedToken"), - - errors.StackSkip(1), - errors.StackTrimAtFn("http.HandlerFunc.ServeHTTP"), - ) -} diff --git a/pkg/auth/scope.go b/pkg/auth/scope.go index 7d0e5e1b0..67df568cb 100644 --- a/pkg/auth/scope.go +++ b/pkg/auth/scope.go @@ -14,6 +14,10 @@ const ( // We're using interface{} and casting it if needed to simplify usage of the fn by directly // using it with map[string]interface{} claims type func CheckJwtScope(token jwt.Token, required ...string) bool { + if token == nil { + return false + } + scopeClaimRaw, has := token.Get("scope") if !has { return false diff --git a/pkg/auth/token_issuer.go b/pkg/auth/token_issuer.go index 2da5f0023..c1ca9240e 100644 --- a/pkg/auth/token_issuer.go +++ b/pkg/auth/token_issuer.go @@ -148,7 +148,7 @@ func (tm *tokenIssuer) newTokenRequest() *TokenRequest { // Validate performs token validation by checking existence of access-token in the store func (tm *tokenIssuer) Validate(ctx context.Context, token jwt.Token) (err error) { if err = tm.lookup(ctx, token.JwtID()); err != nil { - return ErrUnauthorized() + return errUnauthorized() } return nil diff --git a/pkg/auth/token_middleware.go b/pkg/auth/token_middleware.go index a0a1a4004..7de57f6f9 100644 --- a/pkg/auth/token_middleware.go +++ b/pkg/auth/token_middleware.go @@ -16,11 +16,31 @@ var ( HttpTokenVerifier func(http.Handler) http.Handler ) -// verifier is a custom middleware as the built-in one does not look at query parameters -// and it instructs to build one yourself +// verifier returns a jwt verification middleware +// +// Tasks +// 1. picks token from header, query or cookie +// 2. extracts identity (if any) and adds it into request context +// +// In there is no token func verifier(ja *jwtauth.JWTAuth) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { - return jwtauth.Verify(ja, jwtauth.TokenFromHeader, jwtauth.TokenFromQuery, jwtauth.TokenFromCookie)(next) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + token, err := jwtauth.VerifyRequest(ja, r, jwtauth.TokenFromHeader, jwtauth.TokenFromQuery, jwtauth.TokenFromCookie) + ctx := r.Context() + + if token != nil && err == nil { + if err = TokenIssuer.Validate(ctx, token); err != nil { + errors.ProperlyServeHTTP(w, r, err, false) + return + } + } + + ctx = jwtauth.NewContext(ctx, token, err) + ctx = SetIdentityToContext(ctx, IdentityFromToken(token)) + + next.ServeHTTP(w, r.WithContext(ctx)) + }) } } @@ -51,30 +71,30 @@ func HttpTokenValidator(scope ...string) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - token, err := verifyToken(r.Context(), TokenIssuer, scope...) + err := verifyToken(r.Context(), scope...) if err != nil && !errors.Is(err, jwtauth.ErrNoTokenFound) { errors.ProperlyServeHTTP(w, r, err, false) return } - r = r.WithContext(SetIdentityToContext(r.Context(), IdentityFromToken(token))) next.ServeHTTP(w, r) }) } } // pulls token from context and validates scope & access-token -func verifyToken(ctx context.Context, issuer *tokenIssuer, scope ...string) (token jwt.Token, err error) { +func verifyToken(ctx context.Context, scope ...string) (err error) { + var token jwt.Token if token, _, err = jwtauth.FromContext(ctx); err != nil { return } - if len(scope) > 0 && !CheckJwtScope(token, scope...) { - return nil, ErrUnauthorizedScope() + if token == nil { + return errUnauthorized() } - if err = issuer.Validate(ctx, token); err != nil { - return + if len(scope) > 0 && !CheckJwtScope(token, scope...) { + return errUnauthorizedScope() } return