Merge branch '2021.9.x-fix-access-token' into 2021.9.x
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+80
-2
@@ -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,33 @@ type (
|
||||
expiry time.Duration
|
||||
tokenAuth *jwtauth.JWTAuth
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 +65,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 +114,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 +157,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 (
|
||||
|
||||
+12
-1
@@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/errors"
|
||||
"github.com/go-chi/jwtauth"
|
||||
)
|
||||
|
||||
func MiddlewareValidOnly(next http.Handler) http.Handler {
|
||||
@@ -15,11 +16,14 @@ func AccessTokenCheck(scope ...string) func(http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var ctx = r.Context()
|
||||
|
||||
if !GetIdentityFromContext(ctx).Valid() {
|
||||
// retrieve token and claims from context
|
||||
tkn, _, err := jwtauth.FromContext(ctx)
|
||||
if err != nil || !tkn.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,6 +31,13 @@ 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
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
+18
-3
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+9
-3
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
}
|
||||
|
||||
Generated
+23
-2
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}()
|
||||
|
||||
@@ -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
|
||||
}()
|
||||
|
||||
@@ -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))
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user