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:
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user