3
0

Refactored access token removal logic

This commit is contained in:
Denis Arh
2021-09-22 20:24:03 +02:00
parent 0249641bda
commit 426b9c4fb0
6 changed files with 58 additions and 59 deletions
+3 -57
View File
@@ -1,11 +1,10 @@
package auth
import (
"github.com/cortezaproject/corteza-server/system/types"
"github.com/go-chi/jwtauth"
"net/http"
"github.com/cortezaproject/corteza-server/pkg/errors"
"github.com/go-chi/jwtauth"
)
func MiddlewareValidOnly(next http.Handler) http.Handler {
@@ -15,24 +14,15 @@ 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()
roles []uint64
)
var ctx = r.Context()
// retrieve token and claims from context
tkn, claims, err := jwtauth.FromContext(ctx)
tkn, _, 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) {
@@ -48,51 +38,7 @@ func AccessTokenCheck(scope ...string) func(http.Handler) http.Handler {
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
}
+11
View File
@@ -1458,3 +1458,14 @@ func (svc auth) checkLimits(ctx context.Context) error {
return nil
}
// RemoveAccessTokens removes all user's access tokens when suspended,
// deleted or security context changes
func (svc auth) RemoveAccessTokens(ctx context.Context, user *types.User) error {
return svc.recordAction(
ctx,
&authActionProps{user: user},
AuthActionAccessTokensRemoved,
svc.store.DeleteAuthOA2TokenByUserID(ctx, user.ID),
)
}
+23 -2
View File
@@ -11,12 +11,13 @@ package service
import (
"context"
"fmt"
"strings"
"time"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/errors"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/system/types"
"strings"
"time"
)
type (
@@ -636,6 +637,26 @@ func AuthActionEmailOtpVerify(props ...*authActionProps) *authAction {
return a
}
// AuthActionAccessTokensRemoved returns "system:auth.accessTokensRemoved" action
//
// This function is auto-generated.
//
func AuthActionAccessTokensRemoved(props ...*authActionProps) *authAction {
a := &authAction{
timestamp: time.Now(),
resource: "system:auth",
action: "accessTokensRemoved",
log: "access tokens for {{user}} removed",
severity: actionlog.Notice,
}
if len(props) > 0 {
a.props = props[0]
}
return a
}
// *********************************************************************************************************************
// *********************************************************************************************************************
// Error constructors
+2
View File
@@ -83,6 +83,8 @@ actions:
- action: emailOtpVerify
log: "email one-time-password for {{user}} verified"
- action: accessTokensRemoved
log: "access tokens for {{user}} removed"
errors:
- error: invalidCredentials
message: "invalid username and password combination"
+10
View File
@@ -30,6 +30,7 @@ type (
eventbus eventDispatcher
user UserService
auth roleAuth
store store.Storer
@@ -80,6 +81,10 @@ type (
rbacRoleUpdater interface {
UpdateRoles(rr ...*rbac.Role)
}
roleAuth interface {
RemoveAccessTokens(context.Context, *types.User) error
}
)
func Role() *role {
@@ -90,6 +95,7 @@ func Role() *role {
actionlog: DefaultActionlog,
user: DefaultUser,
auth: DefaultAuth,
store: DefaultStore,
system: make(map[string]bool),
@@ -716,6 +722,10 @@ func (svc role) MemberRemove(ctx context.Context, roleID, memberID uint64) (err
return
}
if err = svc.auth.RemoveAccessTokens(ctx, m); err != nil {
return
}
_ = svc.eventbus.WaitFor(ctx, event.RoleMemberAfterRemove(m, r))
return nil
}()
+9
View File
@@ -54,6 +54,7 @@ type (
CheckPasswordStrength(string) bool
SetPasswordCredentials(context.Context, uint64, string) error
RemovePasswordCredentials(context.Context, uint64) error
RemoveAccessTokens(context.Context, *types.User) error
}
userAccessController interface {
@@ -557,6 +558,10 @@ func (svc user) Delete(ctx context.Context, userID uint64) (err error) {
return
}
if err = svc.auth.RemoveAccessTokens(ctx, u); err != nil {
return
}
_ = svc.eventbus.WaitFor(ctx, event.UserAfterDelete(nil, u))
return nil
}()
@@ -646,6 +651,10 @@ func (svc user) Suspend(ctx context.Context, userID uint64) (err error) {
return
}
if err = svc.auth.RemoveAccessTokens(ctx, u); err != nil {
return
}
_ = svc.eventbus.WaitFor(ctx, event.UserAfterSuspend(u, &oldUser))
return nil
}()