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  }