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() }