Ensure extra user validation during access token validation

- validate a token exist in store
- when user is suspended, deleted or roles are removed - removes ALL user's tokens
This commit is contained in:
Vivek Patel
2021-09-22 21:09:55 +02:00
committed by Denis Arh
parent 54cbfe20d8
commit 0249641bda
2 changed files with 73 additions and 2 deletions
+6
View File
@@ -25,7 +25,13 @@ type (
}
tokenStore interface {
LookupUserByID(ctx context.Context, id uint64) (*types.User, error)
LookupAuthOa2tokenByAccess(ctx context.Context, access string) (*types.AuthOa2token, error)
SearchRoleMembers(ctx context.Context, f types.RoleMemberFilter) (types.RoleMemberSet, types.RoleMemberFilter, error)
CreateAuthOa2token(ctx context.Context, rr ...*types.AuthOa2token) error
DeleteAuthOA2TokenByUserID(ctx context.Context, _userID uint64) error
UpsertAuthConfirmedClient(ctx context.Context, rr ...*types.AuthConfirmedClient) error
}
+67 -2
View File
@@ -1,6 +1,8 @@
package auth
import (
"github.com/cortezaproject/corteza-server/system/types"
"github.com/go-chi/jwtauth"
"net/http"
"github.com/cortezaproject/corteza-server/pkg/errors"
@@ -13,13 +15,25 @@ func MiddlewareValidOnly(next http.Handler) http.Handler {
func AccessTokenCheck(scope ...string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var ctx = r.Context()
var (
ctx = r.Context()
roles []uint64
)
if !GetIdentityFromContext(ctx).Valid() {
// retrieve token and claims from context
tkn, claims, err := jwtauth.FromContext(ctx)
if err != nil || !tkn.Valid {
errors.ProperlyServeHTTP(w, r, ErrUnauthorized(), false)
return
}
i := ClaimsToIdentity(claims)
if !i.Valid() {
errors.ProperlyServeHTTP(w, r, ErrUnauthorized(), false)
return
}
// check valid scope
for _, s := range scope {
if !CheckScope(ctx.Value(scopeCtxKey{}), s) {
errors.ProperlyServeHTTP(w, r, ErrUnauthorizedScope(), false)
@@ -27,7 +41,58 @@ func AccessTokenCheck(scope ...string) func(http.Handler) http.Handler {
}
}
// verify JWT from store
_, err = DefaultJwtStore.LookupAuthOa2tokenByAccess(ctx, tkn.Raw)
if err != nil {
errors.ProperlyServeHTTP(w, r, ErrUnauthorized(), false)
return
}
u, err := DefaultJwtStore.LookupUserByID(ctx, i.Identity())
if err != nil {
errors.ProperlyServeHTTP(w, r, ErrUnauthorized(), false)
return
}
deleteTokens := func() {
_ = DefaultJwtStore.DeleteAuthOA2TokenByUserID(ctx, u.ID)
}
// check if user is not suspended or deleted otherwise remove their all tokens
if u.SuspendedAt != nil || u.DeletedAt != nil {
deleteTokens()
errors.ProperlyServeHTTP(w, r, ErrUnauthorized(), false)
return
}
// check if user's role haven't changed otherwise remove their all tokens
set, _, _ := DefaultJwtStore.SearchRoleMembers(ctx, types.RoleMemberFilter{UserID: u.ID})
_ = set.Walk(func(member *types.RoleMember) error {
roles = append(roles, member.RoleID)
return nil
})
if !equal(roles, i.memberOf) {
deleteTokens()
errors.ProperlyServeHTTP(w, r, ErrUnauthorized(), false)
return
}
next.ServeHTTP(w, r)
})
}
}
// Equal tells whether a and b contain the same elements.
// A nil argument is equivalent to an empty slice.
// fixme maybe move to utils
func equal(a, b []uint64) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}