// checkCreds validates the entities credentials in the current model. // If the entity is a user, and lookForModelUser is true, a model user must exist // for the model. In the case of a user logging in to the server, but // not a model, there is no env user needed. While we have the env // user, if we do have it, update the last login time. // // Note that when logging in with lookForModelUser true, the returned // entity will be modelUserEntity, not *state.User (external users // don't have user entries) or *state.ModelUser (we // don't want to lose the local user information associated with that). func checkCreds(st *state.State, req params.LoginRequest, lookForModelUser bool, authenticator authentication.EntityAuthenticator) (state.Entity, *time.Time, error) { var tag names.Tag if req.AuthTag != "" { var err error tag, err = names.ParseTag(req.AuthTag) if err != nil { return nil, nil, errors.Trace(err) } } var entityFinder authentication.EntityFinder = st if lookForModelUser { // When looking up model users, use a custom // entity finder that looks up both the local user (if the user // tag is in the local domain) and the model user. entityFinder = modelUserEntityFinder{st} } entity, err := authenticator.Authenticate(entityFinder, tag, req) if err != nil { return nil, nil, errors.Trace(err) } // For user logins, update the last login time. var lastLogin *time.Time if entity, ok := entity.(loginEntity); ok { userLastLogin, err := entity.LastLogin() if err != nil && !state.IsNeverLoggedInError(err) { return nil, nil, errors.Trace(err) } entity.UpdateLastLogin() lastLogin = &userLastLogin } return entity, lastLogin, nil }
// checkCreds validates the entities credentials in the current environment. // If the entity is a user, and lookForEnvUser is true, an env user must exist // for the environment. In the case of a user logging in to the server, but // not an environment, there is no env user needed. While we have the env // user, if we do have it, update the last login time. func checkCreds(st *state.State, req params.LoginRequest, lookForEnvUser bool) (state.Entity, *time.Time, error) { tag, err := names.ParseTag(req.AuthTag) if err != nil { return nil, nil, err } entity, err := st.FindEntity(tag) if errors.IsNotFound(err) { // We return the same error when an entity does not exist as for a bad // password, so that we don't allow unauthenticated users to find // information about existing entities. logger.Debugf("entity %q not found", tag) return nil, nil, common.ErrBadCreds } if err != nil { return nil, nil, errors.Trace(err) } authenticator, err := authentication.FindEntityAuthenticator(entity) if err != nil { return nil, nil, err } if err = authenticator.Authenticate(entity, req.Credentials, req.Nonce); err != nil { logger.Debugf("bad credentials") return nil, nil, err } // For user logins, update the last login time. // NOTE: this code path is only for local users. When we support remote // user logins with bearer tokens, we will need to make sure that we also // update the last connection times for the environment users there. var lastLogin *time.Time if user, ok := entity.(*state.User); ok { userLastLogin, err := user.LastLogin() if err != nil && !state.IsNeverLoggedInError(err) { return nil, nil, errors.Trace(err) } if lookForEnvUser { envUser, err := st.EnvironmentUser(user.UserTag()) if err != nil { return nil, nil, errors.Wrap(err, common.ErrBadCreds) } // The last connection for the environment takes precedence over // the local user last login time. userLastLogin, err = envUser.LastConnection() if err != nil && !state.IsNeverConnectedError(err) { return nil, nil, errors.Trace(err) } envUser.UpdateLastConnection() } // Only update the user's last login time if it is a successful // login, meaning that if we are logging into an environment, make // sure that there is an environment user in that environment for // this user. user.UpdateLastLogin() lastLogin = &userLastLogin } return entity, lastLogin, nil }
func lastLoginPointer(c *gc.C, user *state.User) *time.Time { lastLogin, err := user.LastLogin() if err != nil { if state.IsNeverLoggedInError(err) { return nil } c.Fatal(err) } return &lastLogin }
// UserInfo returns information on a user. func (api *UserManagerAPI) UserInfo(request params.UserInfoRequest) (params.UserInfoResults, error) { var results params.UserInfoResults var infoForUser = func(user *state.User) params.UserInfoResult { var lastLogin *time.Time userLastLogin, err := user.LastLogin() if err != nil { if !state.IsNeverLoggedInError(err) { logger.Debugf("error getting last login: %v", err) } } else { lastLogin = &userLastLogin } return params.UserInfoResult{ Result: ¶ms.UserInfo{ Username: user.Name(), DisplayName: user.DisplayName(), CreatedBy: user.CreatedBy(), DateCreated: user.DateCreated(), LastConnection: lastLogin, Disabled: user.IsDisabled(), }, } } argCount := len(request.Entities) if argCount == 0 { users, err := api.state.AllUsers(request.IncludeDisabled) if err != nil { return results, errors.Trace(err) } for _, user := range users { results.Results = append(results.Results, infoForUser(user)) } return results, nil } results.Results = make([]params.UserInfoResult, argCount) for i, arg := range request.Entities { user, err := api.getUser(arg.Tag) if err != nil { results.Results[i].Error = common.ServerError(err) continue } results.Results[i] = infoForUser(user) } return results, nil }
// UserInfo returns information on a user. func (api *UserManagerAPI) UserInfo(request params.UserInfoRequest) (params.UserInfoResults, error) { var results params.UserInfoResults isAdmin, err := api.hasControllerAdminAccess() if err != nil { return results, errors.Trace(err) } var accessForUser = func(userTag names.UserTag, result *params.UserInfoResult) { // Lookup the access the specified user has to the controller. _, controllerUserAccess, err := common.UserAccess(api.state, userTag) if err == nil { result.Result.Access = string(controllerUserAccess.Access) } else if err != nil && !errors.IsNotFound(err) { result.Result = nil result.Error = common.ServerError(err) } } var infoForUser = func(user *state.User) params.UserInfoResult { var lastLogin *time.Time userLastLogin, err := user.LastLogin() if err != nil { if !state.IsNeverLoggedInError(err) { logger.Debugf("error getting last login: %v", err) } } else { lastLogin = &userLastLogin } result := params.UserInfoResult{ Result: ¶ms.UserInfo{ Username: user.Name(), DisplayName: user.DisplayName(), CreatedBy: user.CreatedBy(), DateCreated: user.DateCreated(), LastConnection: lastLogin, Disabled: user.IsDisabled(), }, } accessForUser(user.UserTag(), &result) return result } argCount := len(request.Entities) if argCount == 0 { users, err := api.state.AllUsers(request.IncludeDisabled) if err != nil { return results, errors.Trace(err) } for _, user := range users { if !isAdmin && !api.authorizer.AuthOwner(user.Tag()) { continue } results.Results = append(results.Results, infoForUser(user)) } return results, nil } // Create the results list to populate. for _, arg := range request.Entities { userTag, err := names.ParseUserTag(arg.Tag) if err != nil { results.Results = append(results.Results, params.UserInfoResult{Error: common.ServerError(err)}) continue } if !isAdmin && !api.authorizer.AuthOwner(userTag) { results.Results = append(results.Results, params.UserInfoResult{Error: common.ServerError(common.ErrPerm)}) continue } if !userTag.IsLocal() { // TODO(wallyworld) record login information about external users. result := params.UserInfoResult{ Result: ¶ms.UserInfo{ Username: userTag.Id(), }, } accessForUser(userTag, &result) results.Results = append(results.Results, result) continue } user, err := api.getUser(arg.Tag) if err != nil { results.Results = append(results.Results, params.UserInfoResult{Error: common.ServerError(err)}) continue } results.Results = append(results.Results, infoForUser(user)) } return results, nil }