// EnvUserInfo returns information on all users in the environment. func (c *Client) EnvUserInfo() (params.EnvUserInfoResults, error) { var results params.EnvUserInfoResults env, err := c.api.state.Environment() if err != nil { return results, errors.Trace(err) } users, err := env.Users() if err != nil { return results, errors.Trace(err) } for _, user := range users { var lastConn *time.Time userLastConn, err := user.LastConnection() if err != nil { if !state.IsNeverConnectedError(err) { return results, errors.Trace(err) } } else { lastConn = &userLastConn } results.Results = append(results.Results, params.EnvUserInfoResult{ Result: ¶ms.EnvUserInfo{ UserName: user.UserName(), DisplayName: user.DisplayName(), CreatedBy: user.CreatedBy(), DateCreated: user.DateCreated(), LastConnection: lastConn, }, }) } return results, 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 lastConnPointer(c *gc.C, modelUser *state.ModelUser) *time.Time { lastConn, err := modelUser.LastConnection() if err != nil { if state.IsNeverConnectedError(err) { return nil } c.Fatal(err) } return &lastConn }
func lastConnPointer(c *gc.C, st *state.State, modelUser permission.UserAccess) *time.Time { lastConn, err := st.LastModelConnection(modelUser.UserTag) if err != nil { if state.IsNeverConnectedError(err) { return nil } c.Fatal(err) } return &lastConn }
func lastConnPointer(c *gc.C, envUser *state.EnvironmentUser) *time.Time { lastConn, err := envUser.LastConnection() if err != nil { if state.IsNeverConnectedError(err) { return nil } c.Fatal(err) } return &lastConn }
// AllModels allows controller administrators to get the list of all the // environments in the controller. func (s *ControllerAPI) AllModels() (params.UserModelList, error) { result := params.UserModelList{} if err := s.checkHasAdmin(); err != nil { return result, errors.Trace(err) } // Get all the environments that the authenticated user can see, and // supplement that with the other environments that exist that the user // cannot see. The reason we do this is to get the LastConnection time for // the environments that the user is able to see, so we have consistent // output when listing with or without --all when an admin user. environments, err := s.state.ModelsForUser(s.apiUser) if err != nil { return result, errors.Trace(err) } visibleEnvironments := set.NewStrings() for _, env := range environments { lastConn, err := env.LastConnection() if err != nil && !state.IsNeverConnectedError(err) { return result, errors.Trace(err) } visibleEnvironments.Add(env.UUID()) result.UserModels = append(result.UserModels, params.UserModel{ Model: params.Model{ Name: env.Name(), UUID: env.UUID(), OwnerTag: env.Owner().String(), }, LastConnection: &lastConn, }) } allEnvs, err := s.state.AllModels() if err != nil { return result, errors.Trace(err) } for _, env := range allEnvs { if !visibleEnvironments.Contains(env.UUID()) { result.UserModels = append(result.UserModels, params.UserModel{ Model: params.Model{ Name: env.Name(), UUID: env.UUID(), OwnerTag: env.Owner().String(), }, // No LastConnection as this user hasn't. }) } } // Sort the resulting sequence by environment name, then owner. sort.Sort(orderedUserModels(result.UserModels)) return result, nil }
// LastLogin implements loginEntity.LastLogin. func (u *modelUserEntity) LastLogin() (time.Time, error) { // The last connection for the model takes precedence over // the local user last login time. t, err := u.modelUser.LastConnection() if state.IsNeverConnectedError(err) { if u.user != nil { // There's a global user, so use that login time instead. return u.user.LastLogin() } // Since we're implementing LastLogin, we need // to implement LastLogin error semantics too. err = state.NeverLoggedInError(err.Error()) } return t, err }
func (s *MigrationImportSuite) AssertUserEqual(c *gc.C, newUser, oldUser permission.UserAccess) { c.Assert(newUser.UserName, gc.Equals, oldUser.UserName) c.Assert(newUser.DisplayName, gc.Equals, oldUser.DisplayName) c.Assert(newUser.CreatedBy, gc.Equals, oldUser.CreatedBy) c.Assert(newUser.DateCreated, gc.Equals, oldUser.DateCreated) c.Assert(newUser.Access, gc.Equals, newUser.Access) connTime, err := s.State.LastModelConnection(oldUser.UserTag) if state.IsNeverConnectedError(err) { _, err := s.State.LastModelConnection(newUser.UserTag) // The new user should also return an error for last connection. c.Assert(err, jc.Satisfies, state.IsNeverConnectedError) } else { c.Assert(err, jc.ErrorIsNil) newTime, err := s.State.LastModelConnection(newUser.UserTag) c.Assert(err, jc.ErrorIsNil) c.Assert(newTime, gc.Equals, connTime) } }
func (s *MigrationImportSuite) AssertUserEqual(c *gc.C, newUser, oldUser *state.ModelUser) { c.Assert(newUser.UserName(), gc.Equals, oldUser.UserName()) c.Assert(newUser.DisplayName(), gc.Equals, oldUser.DisplayName()) c.Assert(newUser.CreatedBy(), gc.Equals, oldUser.CreatedBy()) c.Assert(newUser.DateCreated(), gc.Equals, oldUser.DateCreated()) c.Assert(newUser.ReadOnly(), gc.Equals, oldUser.ReadOnly()) connTime, err := oldUser.LastConnection() if state.IsNeverConnectedError(err) { _, err := newUser.LastConnection() // The new user should also return an error for last connection. c.Assert(err, jc.Satisfies, state.IsNeverConnectedError) } else { c.Assert(err, jc.ErrorIsNil) newTime, err := newUser.LastConnection() c.Assert(err, jc.ErrorIsNil) c.Assert(newTime, gc.Equals, connTime) } }
// ListEnvironments returns the environments that the specified user // has access to in the current server. Only that state server owner // can list environments for any user (at this stage). Other users // can only ask about their own environments. func (em *EnvironmentManagerAPI) ListEnvironments(user params.Entity) (params.UserEnvironmentList, error) { result := params.UserEnvironmentList{} userTag, err := names.ParseUserTag(user.Tag) if err != nil { return result, errors.Trace(err) } err = em.authCheck(userTag) if err != nil { return result, errors.Trace(err) } environments, err := em.state.EnvironmentsForUser(userTag) if err != nil { return result, errors.Trace(err) } for _, env := range environments { var lastConn *time.Time userLastConn, err := env.LastConnection() if err != nil { if !state.IsNeverConnectedError(err) { return result, errors.Trace(err) } } else { lastConn = &userLastConn } result.UserEnvironments = append(result.UserEnvironments, params.UserEnvironment{ Environment: params.Environment{ Name: env.Name(), UUID: env.UUID(), OwnerTag: env.Owner().String(), }, LastConnection: lastConn, }) logger.Debugf("list env: %s, %s, %s", env.Name(), env.UUID(), env.Owner()) } return result, nil }
// ListModels returns the models that the specified user // has access to in the current server. Only that controller owner // can list models for any user (at this stage). Other users // can only ask about their own models. func (em *ModelManagerAPI) ListModels(user params.Entity) (params.UserModelList, error) { result := params.UserModelList{} userTag, err := names.ParseUserTag(user.Tag) if err != nil { return result, errors.Trace(err) } err = em.authCheck(userTag) if err != nil { return result, errors.Trace(err) } models, err := em.state.ModelsForUser(userTag) if err != nil { return result, errors.Trace(err) } for _, model := range models { var lastConn *time.Time userLastConn, err := model.LastConnection() if err != nil { if !state.IsNeverConnectedError(err) { return result, errors.Trace(err) } } else { lastConn = &userLastConn } result.UserModels = append(result.UserModels, params.UserModel{ Model: params.Model{ Name: model.Name(), UUID: model.UUID(), OwnerTag: model.Owner().String(), }, LastConnection: lastConn, }) logger.Debugf("list models: %s, %s, %s", model.Name(), model.UUID(), model.Owner()) } return result, nil }
// LastLogin implements loginEntity.LastLogin. func (u *modelUserEntity) LastLogin() (time.Time, error) { // The last connection for the model takes precedence over // the local user last login time. var err error var t time.Time if !permission.IsEmptyUserAccess(u.modelUser) { t, err = u.st.LastModelConnection(u.modelUser.UserTag) } else { err = state.NeverConnectedError("controller user") } if state.IsNeverConnectedError(err) || permission.IsEmptyUserAccess(u.modelUser) { if u.user != nil { // There's a global user, so use that login time instead. return u.user.LastLogin() } // Since we're implementing LastLogin, we need // to implement LastLogin error semantics too. err = state.NeverLoggedInError(err.Error()) } return t, errors.Trace(err) }
// ModelUserInfo converts *state.ModelUser to params.ModelUserInfo. func ModelUserInfo(user ModelUser) (params.ModelUserInfo, error) { access, err := StateToParamsModelAccess(user.Access()) if err != nil { return params.ModelUserInfo{}, errors.Trace(err) } var lastConn *time.Time userLastConn, err := user.LastConnection() if err == nil { lastConn = &userLastConn } else if !state.IsNeverConnectedError(err) { return params.ModelUserInfo{}, errors.Trace(err) } userInfo := params.ModelUserInfo{ UserName: user.UserName(), DisplayName: user.DisplayName(), LastConnection: lastConn, Access: access, } return userInfo, nil }