From 54cbfe20d8e47755c033be625c58f1dabe62a1f0 Mon Sep 17 00:00:00 2001 From: Vivek Patel Date: Fri, 17 Sep 2021 08:50:26 +0530 Subject: [PATCH 1/5] Adds JWT token generation methods - Generates token encoded with user and save it to store - Updated token generation method usage in Corredor and Impersonalization --- app/boot_levels.go | 2 ++ pkg/auth/interfaces.go | 6 ++++ pkg/auth/jwt.go | 76 +++++++++++++++++++++++++++++++++++++-- pkg/corredor/service.go | 21 +++++++++-- system/rest/auth.go | 12 +++++-- tests/system/auth_test.go | 52 +++++++++++++++++++++++++++ 6 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 tests/system/auth_test.go diff --git a/app/boot_levels.go b/app/boot_levels.go index 163be24f0..253532efd 100644 --- a/app/boot_levels.go +++ b/app/boot_levels.go @@ -406,6 +406,8 @@ func (app *CortezaApp) InitServices(ctx context.Context) (err error) { return } + auth.SetJWTStore(app.Store) + corredor.Service().SetUserFinder(sysService.DefaultUser) corredor.Service().SetRoleFinder(sysService.DefaultRole) diff --git a/pkg/auth/interfaces.go b/pkg/auth/interfaces.go index c46300ae6..d4f3d0001 100644 --- a/pkg/auth/interfaces.go +++ b/pkg/auth/interfaces.go @@ -1,6 +1,7 @@ package auth import ( + "context" "github.com/dgrijalva/jwt-go" "net/http" ) @@ -17,8 +18,13 @@ type ( Encode(identity Identifiable, scope ...string) string } + TokenGenerator interface { + Generate(ctx context.Context, identity Identifiable) (string, error) + } + TokenHandler interface { TokenEncoder + TokenGenerator 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 0e3dc93d0..7812566e3 100644 --- a/pkg/auth/jwt.go +++ b/pkg/auth/jwt.go @@ -2,7 +2,10 @@ package auth import ( "context" + "encoding/json" "fmt" + "github.com/cortezaproject/corteza-server/pkg/id" + "github.com/cortezaproject/corteza-server/system/types" "net/http" "strconv" "strings" @@ -20,17 +23,27 @@ type ( expiry time.Duration tokenAuth *jwtauth.JWTAuth } + + tokenStore interface { + CreateAuthOa2token(ctx context.Context, rr ...*types.AuthOa2token) error + UpsertAuthConfirmedClient(ctx context.Context, rr ...*types.AuthConfirmedClient) error + } + + ExtraReqInfo struct { + RemoteAddr string + UserAgent string + } ) var ( DefaultJwtHandler TokenHandler + DefaultJwtStore tokenStore ) func SetupDefault(secret string, expiry time.Duration) { // Use JWT secret for hmac signer for now DefaultSigner = HmacSigner(secret) DefaultJwtHandler, _ = JWT(secret, expiry) - } func JWT(secret string, expiry time.Duration) (tkn *token, err error) { @@ -46,6 +59,13 @@ func JWT(secret string, expiry time.Duration) (tkn *token, err error) { return tkn, nil } +// SetJWTStore set store for JWT +// @todo find better way to initiate store, +// it mainly used for generating and storing accessToken for impersonate and corredor, Ref: j.Generate() +func SetJWTStore(store tokenStore) { + DefaultJwtStore = store +} + func (t *token) Authenticate(token string) (jwt.MapClaims, error) { dt, err := t.tokenAuth.Decode(token) if err != nil { @@ -88,7 +108,6 @@ func (t *token) Encode(i Identifiable, scope ...string) string { } func (t *token) encode(i Identifiable, clientID uint64, scope ...string) string { - roles := "" for _, r := range i.Roles() { roles += fmt.Sprintf(" %d", r) @@ -132,6 +151,59 @@ func (t *token) HttpAuthenticator() func(http.Handler) http.Handler { } } +func (t *token) Generate(ctx context.Context, i Identifiable) (tokenString string, err error) { + var ( + eti = GetExtraReqInfoFromContext(ctx) + oa2t = &types.AuthOa2token{ + ID: id.Next(), + CreatedAt: time.Now().Round(time.Second), + RemoteAddr: eti.RemoteAddr, + UserAgent: eti.UserAgent, + } + + acc = &types.AuthConfirmedClient{ + ConfirmedAt: oa2t.CreatedAt, + } + ) + + tokenString = t.Encode(i) + oa2t.Access = tokenString + oa2t.ExpiresAt = oa2t.CreatedAt.Add(t.expiry) + + if oa2t.Data, err = json.Marshal(oa2t); err != nil { + return + } + + // extend this with the client + oa2t.ClientID = 0 + + // copy client id to auth client confirmation + acc.ClientID = oa2t.ClientID + + if oa2t.UserID, _ = ExtractFromSubClaim(i.String()); oa2t.UserID == 0 { + // UserID stores collection of IDs: user's ID and set of all roles' user is member of + return "", fmt.Errorf("could not parse user ID from token") + } + + // copy user id to auth client confirmation + acc.UserID = oa2t.UserID + + if err = DefaultJwtStore.UpsertAuthConfirmedClient(ctx, acc); err != nil { + return + } + + return tokenString, DefaultJwtStore.CreateAuthOa2token(ctx, oa2t) +} + +func GetExtraReqInfoFromContext(ctx context.Context) ExtraReqInfo { + eti := ctx.Value(ExtraReqInfo{}) + if eti != nil { + return eti.(ExtraReqInfo) + } else { + return ExtraReqInfo{} + } +} + // ClaimsToIdentity decodes sub & roles claims into identity func ClaimsToIdentity(c jwt.MapClaims) (i *identity) { var ( diff --git a/pkg/corredor/service.go b/pkg/corredor/service.go index ef0d3f36c..89f73f154 100644 --- a/pkg/corredor/service.go +++ b/pkg/corredor/service.go @@ -104,7 +104,8 @@ type ( } authTokenMaker interface { - Encode(auth.Identifiable, ...string) string + auth.TokenEncoder + auth.TokenGenerator } ) @@ -653,6 +654,8 @@ func (svc service) exec(ctx context.Context, script string, runAs string, args S zap.String("eventType", args.EventType()), zap.String("resourceType", args.ResourceType()), ) + + token string ) log.Debug("triggered") @@ -716,7 +719,13 @@ func (svc service) exec(ctx context.Context, script string, runAs string, args S return } - if err = encodeArguments(req.Args, "authToken", svc.authTokenMaker.Encode(definer)); err != nil { + // Generate and save the token + token, err = svc.authTokenMaker.Generate(ctx, definer) + if err != nil { + return + } + + if err = encodeArguments(req.Args, "authToken", token); err != nil { return } @@ -728,7 +737,13 @@ func (svc service) exec(ctx context.Context, script string, runAs string, args S return } - if err = encodeArguments(req.Args, "authToken", svc.authTokenMaker.Encode(invoker)); err != nil { + // Generate and save the token + token, err = svc.authTokenMaker.Generate(ctx, invoker) + if err != nil { + return + } + + if err = encodeArguments(req.Args, "authToken", token); err != nil { return } } diff --git a/system/rest/auth.go b/system/rest/auth.go index 61390147d..7c58e8418 100644 --- a/system/rest/auth.go +++ b/system/rest/auth.go @@ -14,7 +14,7 @@ var _ = errors.Wrap type ( Auth struct { - tokenEncoder auth.TokenEncoder + tokenHandler auth.TokenGenerator settings *types.AppSettings authSvc authUserService } @@ -46,7 +46,7 @@ type ( func (Auth) New() *Auth { return &Auth{ - tokenEncoder: auth.DefaultJwtHandler, + tokenHandler: auth.DefaultJwtHandler, settings: service.CurrentSettings, authSvc: service.DefaultAuth, } @@ -69,8 +69,14 @@ func (ctrl *Auth) makePayload(ctx context.Context, user *types.User) (*authUserR return nil, err } + // Generate and save the token + t, err := ctrl.tokenHandler.Generate(ctx, user) + if err != nil { + return nil, nil + } + return &authUserResponse{ - JWT: ctrl.tokenEncoder.Encode(user), + JWT: t, User: &authUserPayload{ userPayload: &userPayload{ ID: user.ID, diff --git a/tests/system/auth_test.go b/tests/system/auth_test.go new file mode 100644 index 000000000..91e64aacd --- /dev/null +++ b/tests/system/auth_test.go @@ -0,0 +1,52 @@ +package system + +import ( + "context" + "github.com/cortezaproject/corteza-server/system/service" + "github.com/cortezaproject/corteza-server/system/types" + "net/http" + "testing" + + "github.com/cortezaproject/corteza-server/tests/helpers" +) + +func TestAuthImpersonate(t *testing.T) { + + var ( + h = newHelper(t) + ctx = context.Background() + user = h.createUserWithEmail(h.randEmail()) + input = &struct { + UserID uint64 `json:",string"` + }{ + UserID: user.ID, + } + ) + + helpers.AllowMe(h, types.UserRbacResource(user.ID), "impersonate") + + var res struct { + Response struct { + JWT string `json:"jwt"` + } `json:"response"` + } + h.apiInit(). + Post("/auth/impersonate"). + Header("Accept", "application/json"). + JSON(helpers.JSON(input)). + Expect(t). + Status(http.StatusOK). + Assert(helpers.AssertNoErrors). + End(). + JSON(&res) + + // make sure response has JWT token + jwt := res.Response.JWT + h.a.Greater(len(jwt), 0) + + at, err := service.DefaultStore.LookupAuthOa2tokenByAccess(ctx, jwt) + h.a.Nil(err) + h.a.NotNil(at) + h.a.Greater(len(at.Access), 0) + h.a.Equal(at.Access, jwt) +} From 0249641bda04190c16d2734b89d7fe0e00053892 Mon Sep 17 00:00:00 2001 From: Vivek Patel Date: Wed, 22 Sep 2021 00:14:50 +0530 Subject: [PATCH 2/5] 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 --- pkg/auth/jwt.go | 6 ++++ pkg/auth/middleware.go | 69 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/pkg/auth/jwt.go b/pkg/auth/jwt.go index 7812566e3..eb6046aa3 100644 --- a/pkg/auth/jwt.go +++ b/pkg/auth/jwt.go @@ -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 } diff --git a/pkg/auth/middleware.go b/pkg/auth/middleware.go index d6e2411b7..752032ed3 100644 --- a/pkg/auth/middleware.go +++ b/pkg/auth/middleware.go @@ -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 +} From 426b9c4fb0a9bfe388ab002e391d446c929f3b92 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Wed, 22 Sep 2021 20:24:03 +0200 Subject: [PATCH 3/5] Refactored access token removal logic --- pkg/auth/middleware.go | 60 ++---------------------------- system/service/auth.go | 11 ++++++ system/service/auth_actions.gen.go | 25 ++++++++++++- system/service/auth_actions.yaml | 2 + system/service/role.go | 10 +++++ system/service/user.go | 9 +++++ 6 files changed, 58 insertions(+), 59 deletions(-) diff --git a/pkg/auth/middleware.go b/pkg/auth/middleware.go index 752032ed3..c8212e06e 100644 --- a/pkg/auth/middleware.go +++ b/pkg/auth/middleware.go @@ -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 -} diff --git a/system/service/auth.go b/system/service/auth.go index ed6f87ad0..eb3fe574c 100644 --- a/system/service/auth.go +++ b/system/service/auth.go @@ -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), + ) +} diff --git a/system/service/auth_actions.gen.go b/system/service/auth_actions.gen.go index 487994170..c0dbf1162 100644 --- a/system/service/auth_actions.gen.go +++ b/system/service/auth_actions.gen.go @@ -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 diff --git a/system/service/auth_actions.yaml b/system/service/auth_actions.yaml index 69f8fe2d9..0796eb963 100644 --- a/system/service/auth_actions.yaml +++ b/system/service/auth_actions.yaml @@ -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" diff --git a/system/service/role.go b/system/service/role.go index aa279d460..ce4f70ffe 100644 --- a/system/service/role.go +++ b/system/service/role.go @@ -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 }() diff --git a/system/service/user.go b/system/service/user.go index b9ac03508..ca42482fc 100644 --- a/system/service/user.go +++ b/system/service/user.go @@ -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 }() From 92f225654c7da41eeb92d168ddc941c0c53c02d6 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Wed, 22 Sep 2021 21:23:42 +0200 Subject: [PATCH 4/5] Fix access token handling in integration test --- tests/automation/main_test.go | 7 ++++++- tests/compose/main_test.go | 8 ++++++-- tests/federation/main_test.go | 10 +++++++--- tests/helpers/auth.go | 11 ----------- tests/reporter/main_test.go | 9 ++++++--- tests/system/main_test.go | 8 ++++++-- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/tests/automation/main_test.go b/tests/automation/main_test.go index e548e0462..aadc1db11 100644 --- a/tests/automation/main_test.go +++ b/tests/automation/main_test.go @@ -116,10 +116,15 @@ func (h helper) secCtx() context.Context { func (h helper) apiInit() *apitest.APITest { InitTestApp() + tkn, err := auth.DefaultJwtHandler.Generate(context.Background(), h.cUser) + if err != nil { + panic(err) + } + return apitest. New(). Handler(r). - Intercept(helpers.ReqHeaderAuthBearer(h.cUser)) + Intercept(helpers.ReqHeaderRawAuthBearer(tkn)) } diff --git a/tests/compose/main_test.go b/tests/compose/main_test.go index 86becd259..7dde06a1e 100644 --- a/tests/compose/main_test.go +++ b/tests/compose/main_test.go @@ -117,11 +117,15 @@ func (h helper) secCtx() context.Context { func (h helper) apiInit() *apitest.APITest { InitTestApp() + tkn, err := auth.DefaultJwtHandler.Generate(context.Background(), h.cUser) + if err != nil { + panic(err) + } + return apitest. New(). Handler(r). - Intercept(helpers.ReqHeaderAuthBearer(h.cUser)) - + Intercept(helpers.ReqHeaderRawAuthBearer(tkn)) } func (h helper) mockPermissions(rules ...*rbac.Rule) { diff --git a/tests/federation/main_test.go b/tests/federation/main_test.go index ab06abc98..67e0375a4 100644 --- a/tests/federation/main_test.go +++ b/tests/federation/main_test.go @@ -99,13 +99,17 @@ func (h helper) secCtx() context.Context { // apitest basics, initialize, set handler, add auth func (h helper) apiInit() *apitest.APITest { - // InitTestApp() + InitTestApp() + + tkn, err := auth.DefaultJwtHandler.Generate(context.Background(), h.cUser) + if err != nil { + panic(err) + } return apitest. New(). Handler(r). - Intercept(helpers.ReqHeaderAuthBearer(h.cUser)) - + Intercept(helpers.ReqHeaderRawAuthBearer(tkn)) } // Unwraps error before it passes it to the tester diff --git a/tests/helpers/auth.go b/tests/helpers/auth.go index 6813a43fe..44266649c 100644 --- a/tests/helpers/auth.go +++ b/tests/helpers/auth.go @@ -7,7 +7,6 @@ import ( "github.com/steinfletcher/apitest" "github.com/cortezaproject/corteza-server/pkg/auth" - "github.com/cortezaproject/corteza-server/system/types" ) func BindAuthMiddleware(r chi.Router) { @@ -17,16 +16,6 @@ func BindAuthMiddleware(r chi.Router) { ) } -func ReqHeaderAuthBearer(user *types.User) apitest.Intercept { - return func(req *http.Request) { - if user == nil { - req.Header.Del("Authorization") - } else { - req.Header.Set("Authorization", "Bearer "+auth.DefaultJwtHandler.Encode(user)) - } - } -} - func ReqHeaderRawAuthBearer(token string) apitest.Intercept { return func(req *http.Request) { req.Header.Set("Authorization", "Bearer "+token) diff --git a/tests/reporter/main_test.go b/tests/reporter/main_test.go index 623894ef1..912355c4a 100644 --- a/tests/reporter/main_test.go +++ b/tests/reporter/main_test.go @@ -139,13 +139,16 @@ func (h helper) secCtx() context.Context { func (h helper) apiInit() *apitest.APITest { InitTestApp() + tkn, err := auth.DefaultJwtHandler.Generate(context.Background(), h.cUser) + if err != nil { + panic(err) + } + return apitest. New(). Handler(r). - Intercept(helpers.ReqHeaderAuthBearer(h.cUser)) - + Intercept(helpers.ReqHeaderRawAuthBearer(tkn)) } - func (h helper) mockPermissions(rules ...*rbac.Rule) { h.noError(rbac.Global().Grant( // TestService we use does not have any backend storage, diff --git a/tests/system/main_test.go b/tests/system/main_test.go index 0413731eb..1ddd0134a 100644 --- a/tests/system/main_test.go +++ b/tests/system/main_test.go @@ -150,11 +150,15 @@ func (h helper) secCtx() context.Context { func (h helper) apiInit() *apitest.APITest { InitTestApp() + tkn, err := auth.DefaultJwtHandler.Generate(context.Background(), h.cUser) + if err != nil { + panic(err) + } + return apitest. New(). Handler(r). - Intercept(helpers.ReqHeaderAuthBearer(h.cUser)) - + Intercept(helpers.ReqHeaderRawAuthBearer(tkn)) } func (h helper) mockPermissions(rules ...*rbac.Rule) { From 1c55cee2df9acc01a1e8c440768012bc94e80c96 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Wed, 22 Sep 2021 21:29:51 +0200 Subject: [PATCH 5/5] Fix access token handling in fed node handshake --- federation/service/node.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/federation/service/node.go b/federation/service/node.go index 436396623..4215b66cf 100644 --- a/federation/service/node.go +++ b/federation/service/node.go @@ -30,7 +30,7 @@ type ( actionlog actionlog.Recorder - tokenEncoder auth.TokenEncoder + tokenEncoder auth.TokenGenerator name string host string @@ -290,14 +290,18 @@ func (svc node) Pair(ctx context.Context, nodeID uint64) error { return err } + var accessToken string // Generate JWT token for the federated user - authToken := svc.tokenEncoder.Encode(u) + accessToken, err = svc.tokenEncoder.Generate(ctx, u) + if err != nil { + return err + } n.UpdatedBy = auth.GetIdentityFromContext(ctx).Identity() n.UpdatedAt = now() // Start handshake initialization remote node - if err = svc.handshaker.Init(ctx, n, authToken); err != nil { + if err = svc.handshaker.Init(ctx, n, accessToken); err != nil { return err } @@ -357,14 +361,15 @@ func (svc node) HandshakeConfirm(ctx context.Context, nodeID uint64) error { return err } + var accessToken string // Generate JWT token for the federated user - authToken := svc.tokenEncoder.Encode(u) + accessToken, err = svc.tokenEncoder.Generate(ctx, u) n.UpdatedBy = auth.GetIdentityFromContext(ctx).Identity() n.UpdatedAt = now() // Complete handshake on remote node - if err = svc.handshaker.Complete(ctx, n, authToken); err != nil { + if err = svc.handshaker.Complete(ctx, n, accessToken); err != nil { return err }