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