github.com/pavlo67/common@v0.5.3/common/auth/auth_stub/stub.go (about) 1 package auth_stub 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/GehirnInc/crypt" 9 _ "github.com/GehirnInc/crypt/sha256_crypt" 10 "github.com/pkg/errors" 11 12 "github.com/pavlo67/common/common/auth" 13 "github.com/pavlo67/common/common/rbac" 14 ) 15 16 var _ auth.Operator = &authstub{} 17 18 type authstub struct { 19 crypter crypt.Crypter 20 actors []auth.Actor 21 } 22 23 const onNew = "on authstub.New()" 24 25 func New(defaultActors []auth.Actor) (auth.Operator, error) { 26 27 authOp := authstub{crypter: crypt.SHA256.New()} 28 29 for _, actor := range defaultActors { 30 if actor.Creds == nil { 31 actor.Creds = auth.Creds{} 32 } 33 34 var err error 35 actor.Creds[auth.CredsPasshash], err = authOp.crypter.Generate([]byte(actor.Creds[auth.CredsPassword]), nil) 36 if err != nil { 37 return nil, errors.Wrap(err, onNew) 38 } 39 delete(actor.Creds, auth.CredsPassword) 40 41 authOp.actors = append(authOp.actors, actor) 42 } 43 44 return &authOp, nil 45 } 46 47 const onSetCreds = "on authstub.SetCreds()" 48 49 func (authOp *authstub) SetCreds(actor auth.Actor, toSet auth.Creds) (*auth.Creds, error) { 50 if passwordToSet := strings.TrimSpace(toSet[auth.CredsPassword]); passwordToSet != "" { 51 var err error 52 toSet[auth.CredsPasshash], err = authOp.crypter.Generate([]byte(passwordToSet), nil) 53 if err != nil { 54 return nil, errors.Wrap(err, onSetCreds) 55 } 56 delete(actor.Creds, auth.CredsPassword) 57 58 } 59 delete(toSet, auth.CredsPassword) 60 61 var idToFind auth.ID 62 63 if actor.Identity != nil { 64 idToFind = actor.Identity.ID 65 if idToFindAnother := auth.ID(toSet[auth.CredsID]); idToFindAnother != "" { 66 if actor.Identity.Roles.Has(rbac.RoleAdmin) { 67 idToFind = idToFindAnother 68 } else { 69 return nil, fmt.Errorf(onSetCreds+": actor (H%#v) can't set alien creds non having admin role", actor.Identity) 70 } 71 } 72 } 73 74 i := -1 75 76 if idToFind == "" { 77 i = len(authOp.actors) 78 actor := auth.Actor{Identity: &auth.Identity{ID: auth.ID(strconv.Itoa(i))}} 79 authOp.actors = append(authOp.actors, actor) 80 } else { 81 for iToCheck, actorToSet := range authOp.actors { 82 if actorToSet.Identity != nil && actorToSet.Identity.ID == idToFind { 83 i = iToCheck 84 } 85 } 86 if i < 0 { 87 return nil, errors.Wrapf(auth.ErrNoUser, "no user with ID = %s", idToFind) 88 } 89 } 90 91 actorToSet := authOp.actors[i] 92 93 if nicknameToSet := strings.TrimSpace(toSet[auth.CredsNickname]); nicknameToSet != "" { 94 actorToSet.Identity.Nickname = nicknameToSet 95 delete(toSet, auth.CredsNickname) 96 } 97 if roleStr, ok := toSet[auth.CredsRole]; ok { 98 role := rbac.Role(roleStr) 99 if role == rbac.RoleAdmin && !actor.Roles.Has(rbac.RoleAdmin) { 100 return nil, fmt.Errorf(onSetCreds+": actor (H%#v) can't set admin role non having own admin role", actor.Identity) 101 } 102 103 // TODO: multiple roles 104 actorToSet.Identity.Roles = rbac.Roles{rbac.Role(role)} 105 } 106 107 if actorToSet.Creds == nil { 108 actorToSet.Creds = auth.Creds{} 109 } 110 for k, v := range toSet { 111 actorToSet.Creds[k] = v 112 } 113 114 authOp.actors[i] = actorToSet 115 116 return &auth.Creds{auth.CredsNickname: actorToSet.Identity.Nickname}, nil // auth.CredsRole: actorToSet.Identity.Roles 117 } 118 119 const onAuthenticate = "on authstub.Authenticate()" 120 121 func (authOp *authstub) Authenticate(toAuth auth.Creds) (*auth.Actor, error) { 122 nickname := toAuth[auth.CredsNickname] 123 124 // l.Infof("ACTORS: %#v", authOp.actors) 125 126 l.Infof("TO AUTH: %s / %#v", nickname, toAuth) 127 128 for _, actor := range authOp.actors { 129 if actor.Identity != nil && actor.Identity.Nickname == nickname { 130 if err := authOp.crypter.Verify(actor.Creds[auth.CredsPasshash], []byte(toAuth[auth.CredsPassword])); err == nil { 131 return &actor, nil 132 } 133 } 134 } 135 136 return nil, auth.ErrNotAuthenticated 137 }