github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/state/user.go (about)

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // NOTE: the users that are being stored in the database here are only
     5  // the local users, like "admin" or "bob".  In the  world
     6  // where we have external user providers hooked up, there are no records
     7  // in the database for users that are authenticated elsewhere.
     8  
     9  package state
    10  
    11  import (
    12  	"crypto/rand"
    13  	"fmt"
    14  	"sort"
    15  	"strings"
    16  	"time"
    17  
    18  	"github.com/juju/errors"
    19  	"github.com/juju/utils"
    20  	"gopkg.in/juju/names.v2"
    21  	"gopkg.in/mgo.v2"
    22  	"gopkg.in/mgo.v2/bson"
    23  	"gopkg.in/mgo.v2/txn"
    24  
    25  	"github.com/juju/juju/permission"
    26  )
    27  
    28  const userGlobalKeyPrefix = "us"
    29  
    30  func userGlobalKey(userID string) string {
    31  	return fmt.Sprintf("%s#%s", userGlobalKeyPrefix, userID)
    32  }
    33  
    34  func userIDFromGlobalKey(key string) string {
    35  	prefix := userGlobalKeyPrefix + "#"
    36  	return strings.TrimPrefix(key, prefix)
    37  }
    38  
    39  func (st *State) checkUserExists(name string) (bool, error) {
    40  	users, closer := st.db().GetCollection(usersC)
    41  	defer closer()
    42  
    43  	var count int
    44  	var err error
    45  	if count, err = users.FindId(name).Count(); err != nil {
    46  		return false, err
    47  	}
    48  	return count > 0, nil
    49  }
    50  
    51  // AddUser adds a user to the database.
    52  func (st *State) AddUser(name, displayName, password, creator string) (*User, error) {
    53  	return st.addUser(name, displayName, password, creator, nil)
    54  }
    55  
    56  // AddUserWithSecretKey adds the user with the specified name, and assigns it
    57  // a randomly generated secret key. This secret key may be used for the user
    58  // and controller to mutually authenticate one another, without without relying
    59  // on TLS certificates.
    60  //
    61  // The new user will not have a password. A password must be set, clearing the
    62  // secret key in the process, before the user can login normally.
    63  func (st *State) AddUserWithSecretKey(name, displayName, creator string) (*User, error) {
    64  	secretKey, err := generateSecretKey()
    65  	if err != nil {
    66  		return nil, errors.Trace(err)
    67  	}
    68  	return st.addUser(name, displayName, "", creator, secretKey)
    69  }
    70  
    71  func (st *State) addUser(name, displayName, password, creator string, secretKey []byte) (*User, error) {
    72  	if !names.IsValidUserName(name) {
    73  		return nil, errors.Errorf("invalid user name %q", name)
    74  	}
    75  	nameToLower := strings.ToLower(name)
    76  
    77  	dateCreated := st.nowToTheSecond()
    78  	user := &User{
    79  		st: st,
    80  		doc: userDoc{
    81  			DocID:       nameToLower,
    82  			Name:        name,
    83  			DisplayName: displayName,
    84  			SecretKey:   secretKey,
    85  			CreatedBy:   creator,
    86  			DateCreated: dateCreated,
    87  		},
    88  	}
    89  
    90  	if password != "" {
    91  		salt, err := utils.RandomSalt()
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		user.doc.PasswordHash = utils.UserPasswordHash(password, salt)
    96  		user.doc.PasswordSalt = salt
    97  	}
    98  
    99  	ops := []txn.Op{{
   100  		C:      usersC,
   101  		Id:     nameToLower,
   102  		Assert: txn.DocMissing,
   103  		Insert: &user.doc,
   104  	}}
   105  	controllerUserOps := createControllerUserOps(st.ControllerUUID(),
   106  		names.NewUserTag(name),
   107  		names.NewUserTag(creator),
   108  		displayName,
   109  		dateCreated,
   110  		defaultControllerPermission)
   111  	ops = append(ops, controllerUserOps...)
   112  
   113  	err := st.db().RunTransaction(ops)
   114  	if err == txn.ErrAborted {
   115  		err = errors.Errorf("username unavailable")
   116  	}
   117  	if err != nil {
   118  		if errors.IsAlreadyExists(err) {
   119  			err = errors.Errorf("username unavailable")
   120  		}
   121  		return nil, errors.Trace(err)
   122  	}
   123  	return user, nil
   124  }
   125  
   126  // RemoveUser marks the user as deleted. This obviates the ability of a user
   127  // to function, but keeps the userDoc retaining provenance, i.e. auditing.
   128  func (st *State) RemoveUser(tag names.UserTag) error {
   129  	name := strings.ToLower(tag.Name())
   130  
   131  	u, err := st.User(tag)
   132  	if err != nil {
   133  		return errors.Trace(err)
   134  	}
   135  	if u.IsDeleted() {
   136  		return nil
   137  	}
   138  
   139  	buildTxn := func(attempt int) ([]txn.Op, error) {
   140  		if attempt > 0 {
   141  			// If it is not our first attempt, refresh the user.
   142  			if err := u.Refresh(); err != nil {
   143  				return nil, errors.Trace(err)
   144  			}
   145  		}
   146  		ops := []txn.Op{{
   147  			Id:     name,
   148  			C:      usersC,
   149  			Assert: txn.DocExists,
   150  			Update: bson.M{"$set": bson.M{"deleted": true}},
   151  		}}
   152  		return ops, nil
   153  	}
   154  	return st.db().Run(buildTxn)
   155  }
   156  
   157  func createInitialUserOps(controllerUUID string, user names.UserTag, password, salt string, dateCreated time.Time) []txn.Op {
   158  	nameToLower := strings.ToLower(user.Name())
   159  	doc := userDoc{
   160  		DocID:        nameToLower,
   161  		Name:         user.Name(),
   162  		DisplayName:  user.Name(),
   163  		PasswordHash: utils.UserPasswordHash(password, salt),
   164  		PasswordSalt: salt,
   165  		CreatedBy:    user.Name(),
   166  		DateCreated:  dateCreated,
   167  	}
   168  	ops := []txn.Op{{
   169  		C:      usersC,
   170  		Id:     nameToLower,
   171  		Assert: txn.DocMissing,
   172  		Insert: &doc,
   173  	}}
   174  	controllerUserOps := createControllerUserOps(controllerUUID,
   175  		names.NewUserTag(user.Name()),
   176  		names.NewUserTag(user.Name()),
   177  		user.Name(),
   178  		dateCreated,
   179  		// first user is controller admin.
   180  		permission.SuperuserAccess)
   181  
   182  	ops = append(ops, controllerUserOps...)
   183  	return ops
   184  
   185  }
   186  
   187  // getUser fetches information about the user with the
   188  // given name into the provided userDoc.
   189  func (st *State) getUser(name string, udoc *userDoc) error {
   190  	users, closer := st.db().GetCollection(usersC)
   191  	defer closer()
   192  
   193  	name = strings.ToLower(name)
   194  	err := users.Find(bson.D{{"_id", name}}).One(udoc)
   195  	if err == mgo.ErrNotFound {
   196  		err = errors.NotFoundf("user %q", name)
   197  	}
   198  	// DateCreated is inserted as UTC, but read out as local time. So we
   199  	// convert it back to UTC here.
   200  	udoc.DateCreated = udoc.DateCreated.UTC()
   201  	return err
   202  }
   203  
   204  // User returns the state User for the given name.
   205  func (st *State) User(tag names.UserTag) (*User, error) {
   206  	if !tag.IsLocal() {
   207  		return nil, errors.NotFoundf("user %q", tag.Id())
   208  	}
   209  	user := &User{st: st}
   210  	if err := st.getUser(tag.Name(), &user.doc); err != nil {
   211  		return nil, errors.Trace(err)
   212  	}
   213  	if user.doc.Deleted {
   214  		// This error is returned to the apiserver and from there to the api
   215  		// client. So we don't annotate with information regarding deletion.
   216  		// TODO(redir): We'll return a deletedUserError in the future so we can
   217  		// return more appropriate errors, e.g. username not available.
   218  		return nil, DeletedUserError{UserName: user.Name()}
   219  	}
   220  	return user, nil
   221  }
   222  
   223  // AllUsers returns a slice of state.User. This includes all active users. If
   224  // includeDeactivated is true it also returns inactive users. At this point it
   225  // never returns deleted users.
   226  func (st *State) AllUsers(includeDeactivated bool) ([]*User, error) {
   227  	var result []*User
   228  
   229  	users, closer := st.db().GetCollection(usersC)
   230  	defer closer()
   231  
   232  	var query bson.D
   233  	// TODO(redir): Provide option to retrieve deleted users in future PR.
   234  	// e.g. if !includeDelted.
   235  	// Ensure the query checks for users without the deleted attribute, and
   236  	// also that if it does that the value is not true. fwereade wanted to be
   237  	// sure we cannot miss users that previously existed without the deleted
   238  	// attr. Since this will only be in 2.0 that should never happen, but...
   239  	// belt and suspenders.
   240  	query = append(query, bson.DocElem{
   241  		"deleted", bson.D{{"$ne", true}},
   242  	})
   243  
   244  	// As above, in the case that a user previously existed and doesn't have a
   245  	// deactivated attribute, we make sure the query checks for the existence
   246  	// of the attribute, and if it exists that it is not true.
   247  	if !includeDeactivated {
   248  		query = append(query, bson.DocElem{
   249  			"deactivated", bson.D{{"$ne", true}},
   250  		})
   251  	}
   252  	iter := users.Find(query).Iter()
   253  	defer iter.Close()
   254  
   255  	var doc userDoc
   256  	for iter.Next(&doc) {
   257  		result = append(result, &User{st: st, doc: doc})
   258  	}
   259  	if err := iter.Close(); err != nil {
   260  		return nil, errors.Trace(err)
   261  	}
   262  	// Always return a predictable order, sort by Name.
   263  	sort.Sort(userList(result))
   264  	return result, nil
   265  }
   266  
   267  // User represents a local user in the database.
   268  type User struct {
   269  	st           *State
   270  	doc          userDoc
   271  	lastLoginDoc userLastLoginDoc
   272  }
   273  
   274  type userDoc struct {
   275  	DocID        string    `bson:"_id"`
   276  	Name         string    `bson:"name"`
   277  	DisplayName  string    `bson:"displayname"`
   278  	Deactivated  bool      `bson:"deactivated,omitempty"`
   279  	Deleted      bool      `bson:"deleted,omitempty"` // Deleted users are marked deleted but not removed.
   280  	SecretKey    []byte    `bson:"secretkey,omitempty"`
   281  	PasswordHash string    `bson:"passwordhash"`
   282  	PasswordSalt string    `bson:"passwordsalt"`
   283  	CreatedBy    string    `bson:"createdby"`
   284  	DateCreated  time.Time `bson:"datecreated"`
   285  }
   286  
   287  type userLastLoginDoc struct {
   288  	DocID     string `bson:"_id"`
   289  	ModelUUID string `bson:"model-uuid"`
   290  	// LastLogin is updated by the apiserver whenever the user
   291  	// connects over the API. This update is not done using mgo.txn
   292  	// so this value could well change underneath a normal transaction
   293  	// and as such, it should NEVER appear in any transaction asserts.
   294  	// It is really informational only as far as everyone except the
   295  	// api server is concerned.
   296  	LastLogin time.Time `bson:"last-login"`
   297  }
   298  
   299  // String returns "<name>" where <name> is the Name of the user.
   300  func (u *User) String() string {
   301  	return u.UserTag().Id()
   302  }
   303  
   304  // Name returns the User name.
   305  func (u *User) Name() string {
   306  	return u.doc.Name
   307  }
   308  
   309  // DisplayName returns the display name of the User.
   310  func (u *User) DisplayName() string {
   311  	return u.doc.DisplayName
   312  }
   313  
   314  // CreatedBy returns the name of the User that created this User.
   315  func (u *User) CreatedBy() string {
   316  	return u.doc.CreatedBy
   317  }
   318  
   319  // DateCreated returns when this User was created in UTC.
   320  func (u *User) DateCreated() time.Time {
   321  	return u.doc.DateCreated.UTC()
   322  }
   323  
   324  // Tag returns the Tag for the User.
   325  func (u *User) Tag() names.Tag {
   326  	return u.UserTag()
   327  }
   328  
   329  // UserTag returns the Tag for the User.
   330  func (u *User) UserTag() names.UserTag {
   331  	name := u.doc.Name
   332  	return names.NewLocalUserTag(name)
   333  }
   334  
   335  // LastLogin returns when this User last connected through the API in UTC.
   336  // The resulting time will be nil if the user has never logged in.  In the
   337  // normal case, the LastLogin is the last time that the user connected through
   338  // the API server.
   339  func (u *User) LastLogin() (time.Time, error) {
   340  	lastLogins, closer := u.st.db().GetRawCollection(userLastLoginC)
   341  	defer closer()
   342  
   343  	var lastLogin userLastLoginDoc
   344  	err := lastLogins.FindId(u.doc.DocID).Select(bson.D{{"last-login", 1}}).One(&lastLogin)
   345  	if err != nil {
   346  		if err == mgo.ErrNotFound {
   347  			err = errors.Wrap(err, NeverLoggedInError(u.UserTag().Name()))
   348  		}
   349  		return time.Time{}, errors.Trace(err)
   350  	}
   351  
   352  	return lastLogin.LastLogin.UTC(), nil
   353  }
   354  
   355  // NeverLoggedInError is used to indicate that a user has never logged in.
   356  type NeverLoggedInError string
   357  
   358  // Error returns the error string for a user who has never logged
   359  // in.
   360  func (e NeverLoggedInError) Error() string {
   361  	return `never logged in: "` + string(e) + `"`
   362  }
   363  
   364  // IsNeverLoggedInError returns true if err is of type NeverLoggedInError.
   365  func IsNeverLoggedInError(err error) bool {
   366  	_, ok := errors.Cause(err).(NeverLoggedInError)
   367  	return ok
   368  }
   369  
   370  // UpdateLastLogin sets the LastLogin time of the user to be now (to the
   371  // nearest second).
   372  func (u *User) UpdateLastLogin() (err error) {
   373  	if err := u.ensureNotDeleted(); err != nil {
   374  		return errors.Annotate(err, "cannot update last login")
   375  	}
   376  	lastLogins, closer := u.st.db().GetCollection(userLastLoginC)
   377  	defer closer()
   378  
   379  	lastLoginsW := lastLogins.Writeable()
   380  
   381  	// Update the safe mode of the underlying session to not require
   382  	// write majority, nor sync to disk.
   383  	session := lastLoginsW.Underlying().Database.Session
   384  	session.SetSafe(&mgo.Safe{})
   385  
   386  	lastLogin := userLastLoginDoc{
   387  		DocID:     u.doc.DocID,
   388  		ModelUUID: u.st.ModelUUID(),
   389  		LastLogin: u.st.nowToTheSecond(),
   390  	}
   391  
   392  	_, err = lastLoginsW.UpsertId(lastLogin.DocID, lastLogin)
   393  	return errors.Trace(err)
   394  }
   395  
   396  // SecretKey returns the user's secret key, if any.
   397  func (u *User) SecretKey() []byte {
   398  	return u.doc.SecretKey
   399  }
   400  
   401  // SetPassword sets the password associated with the User.
   402  func (u *User) SetPassword(password string) error {
   403  	if err := u.ensureNotDeleted(); err != nil {
   404  		return errors.Annotate(err, "cannot set password")
   405  	}
   406  	salt, err := utils.RandomSalt()
   407  	if err != nil {
   408  		return err
   409  	}
   410  	return u.SetPasswordHash(utils.UserPasswordHash(password, salt), salt)
   411  }
   412  
   413  // SetPasswordHash stores the hash and the salt of the
   414  // password. If the User has a secret key set then it
   415  // will be cleared.
   416  func (u *User) SetPasswordHash(pwHash string, pwSalt string) error {
   417  	if err := u.ensureNotDeleted(); err != nil {
   418  		// If we do get a late set of the password this is fine b/c we have an
   419  		// explicit check before login.
   420  		return errors.Annotate(err, "cannot set password hash")
   421  	}
   422  	update := bson.D{{"$set", bson.D{
   423  		{"passwordhash", pwHash},
   424  		{"passwordsalt", pwSalt},
   425  	}}}
   426  	if u.doc.SecretKey != nil {
   427  		update = append(update,
   428  			bson.DocElem{"$unset", bson.D{{"secretkey", ""}}},
   429  		)
   430  	}
   431  	ops := []txn.Op{{
   432  		C:      usersC,
   433  		Id:     u.Name(),
   434  		Assert: txn.DocExists,
   435  		Update: update,
   436  	}}
   437  	if err := u.st.db().RunTransaction(ops); err != nil {
   438  		return errors.Annotatef(err, "cannot set password of user %q", u.Name())
   439  	}
   440  	u.doc.PasswordHash = pwHash
   441  	u.doc.PasswordSalt = pwSalt
   442  	u.doc.SecretKey = nil
   443  	return nil
   444  }
   445  
   446  // PasswordValid returns whether the given password is valid for the User. The
   447  // caller should call user.Refresh before calling this.
   448  func (u *User) PasswordValid(password string) bool {
   449  	// If the User is deactivated or deleted, there is no point in carrying on.
   450  	// Since any authentication checks are done very soon after the user is
   451  	// read from the database, there is a very small timeframe where an user
   452  	// could be disabled after it has been read but prior to being checked, but
   453  	// in practice, this isn't a problem.
   454  	if u.IsDisabled() || u.IsDeleted() {
   455  		return false
   456  	}
   457  	if u.doc.PasswordSalt != "" {
   458  		return utils.UserPasswordHash(password, u.doc.PasswordSalt) == u.doc.PasswordHash
   459  	}
   460  	return false
   461  }
   462  
   463  // Refresh refreshes information about the User from the state.
   464  func (u *User) Refresh() error {
   465  	var udoc userDoc
   466  	if err := u.st.getUser(u.Name(), &udoc); err != nil {
   467  		return err
   468  	}
   469  	u.doc = udoc
   470  	return nil
   471  }
   472  
   473  // Disable deactivates the user.  Disabled identities cannot log in.
   474  func (u *User) Disable() error {
   475  	if err := u.ensureNotDeleted(); err != nil {
   476  		return errors.Annotate(err, "cannot disable")
   477  	}
   478  	owner, err := u.st.ControllerOwner()
   479  	if err != nil {
   480  		return errors.Trace(err)
   481  	}
   482  	if u.doc.Name == owner.Name() {
   483  		return errors.Unauthorizedf("cannot disable controller model owner")
   484  	}
   485  	return errors.Annotatef(u.setDeactivated(true), "cannot disable user %q", u.Name())
   486  }
   487  
   488  // Enable reactivates the user, setting disabled to false.
   489  func (u *User) Enable() error {
   490  	if err := u.ensureNotDeleted(); err != nil {
   491  		return errors.Annotate(err, "cannot enable")
   492  	}
   493  	return errors.Annotatef(u.setDeactivated(false), "cannot enable user %q", u.Name())
   494  }
   495  
   496  func (u *User) setDeactivated(value bool) error {
   497  	ops := []txn.Op{{
   498  		C:      usersC,
   499  		Id:     u.Name(),
   500  		Assert: txn.DocExists,
   501  		Update: bson.D{{"$set", bson.D{{"deactivated", value}}}},
   502  	}}
   503  	if err := u.st.db().RunTransaction(ops); err != nil {
   504  		if err == txn.ErrAborted {
   505  			err = fmt.Errorf("user no longer exists")
   506  		}
   507  		return err
   508  	}
   509  	u.doc.Deactivated = value
   510  	return nil
   511  }
   512  
   513  // IsDisabled returns whether the user is currently enabled.
   514  func (u *User) IsDisabled() bool {
   515  	// Yes, this is a cached value, but in practice the user object is
   516  	// never held around for a long time.
   517  	return u.doc.Deactivated
   518  }
   519  
   520  // IsDeleted returns whether the user is currently deleted.
   521  func (u *User) IsDeleted() bool {
   522  	return u.doc.Deleted
   523  }
   524  
   525  // DeletedUserError is used to indicate when an attempt to mutate a deleted
   526  // user is attempted.
   527  type DeletedUserError struct {
   528  	UserName string
   529  }
   530  
   531  // Error implements the error interface.
   532  func (e DeletedUserError) Error() string {
   533  	return fmt.Sprintf("user %q is permanently deleted", e.UserName)
   534  }
   535  
   536  // ensureNotDeleted refreshes the user to ensure it wasn't deleted since we
   537  // acquired it.
   538  func (u *User) ensureNotDeleted() error {
   539  	if err := u.Refresh(); err != nil {
   540  		return errors.Trace(err)
   541  	}
   542  	if u.doc.Deleted {
   543  		return DeletedUserError{u.Name()}
   544  	}
   545  	return nil
   546  }
   547  
   548  // ResetPassword clears the user's password (if there is one),
   549  // and generates a new secret key for the user.
   550  // This must be an active user.
   551  func (u *User) ResetPassword() ([]byte, error) {
   552  	var key []byte
   553  	buildTxn := func(attempt int) ([]txn.Op, error) {
   554  		if err := u.ensureNotDeleted(); err != nil {
   555  			return nil, errors.Trace(err)
   556  		}
   557  		if u.IsDisabled() {
   558  			return nil, fmt.Errorf("user deactivated")
   559  		}
   560  		var err error
   561  		key, err = generateSecretKey()
   562  		if err != nil {
   563  			return nil, errors.Trace(err)
   564  		}
   565  		update := bson.D{
   566  			{
   567  				"$set", bson.D{
   568  					{"secretkey", key},
   569  				},
   570  			},
   571  			{
   572  				"$unset", bson.D{
   573  					{"passwordhash", ""},
   574  					{"passwordsalt", ""},
   575  				},
   576  			},
   577  		}
   578  		return []txn.Op{{
   579  			C:      usersC,
   580  			Id:     u.Name(),
   581  			Assert: txn.DocExists,
   582  			Update: update,
   583  		}}, nil
   584  	}
   585  	if err := u.st.db().Run(buildTxn); err != nil {
   586  		return nil, errors.Annotatef(err, "cannot reset password for user %q", u.Name())
   587  	}
   588  	u.doc.SecretKey = key
   589  	u.doc.PasswordHash = ""
   590  	u.doc.PasswordSalt = ""
   591  	return key, nil
   592  }
   593  
   594  // generateSecretKey generates a random, 32-byte secret key.
   595  func generateSecretKey() ([]byte, error) {
   596  	var secretKey [32]byte
   597  	if _, err := rand.Read(secretKey[:]); err != nil {
   598  		return nil, errors.Trace(err)
   599  	}
   600  	return secretKey[:], nil
   601  }
   602  
   603  // userList type is used to provide the methods for sorting.
   604  type userList []*User
   605  
   606  func (u userList) Len() int           { return len(u) }
   607  func (u userList) Swap(i, j int)      { u[i], u[j] = u[j], u[i] }
   608  func (u userList) Less(i, j int) bool { return u[i].Name() < u[j].Name() }