github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/usermanager/usermanager.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package usermanager
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/apiserver/common"
    14  	"github.com/juju/juju/apiserver/facade"
    15  	"github.com/juju/juju/apiserver/params"
    16  	"github.com/juju/juju/permission"
    17  	"github.com/juju/juju/state"
    18  )
    19  
    20  var logger = loggo.GetLogger("juju.apiserver.usermanager")
    21  
    22  // UserManagerAPI implements the user manager interface and is the concrete
    23  // implementation of the api end point.
    24  type UserManagerAPI struct {
    25  	state      *state.State
    26  	authorizer facade.Authorizer
    27  	check      *common.BlockChecker
    28  	apiUser    names.UserTag
    29  	isAdmin    bool
    30  }
    31  
    32  // NewUserManagerAPI provides the signature required for facade registration.
    33  func NewUserManagerAPI(
    34  	st *state.State,
    35  	resources facade.Resources,
    36  	authorizer facade.Authorizer,
    37  ) (*UserManagerAPI, error) {
    38  	if !authorizer.AuthClient() {
    39  		return nil, common.ErrPerm
    40  	}
    41  
    42  	// Since we know this is a user tag (because AuthClient is true),
    43  	// we just do the type assertion to the UserTag.
    44  	apiUser, _ := authorizer.GetAuthTag().(names.UserTag)
    45  	// Pretty much all of the user manager methods have special casing for admin
    46  	// users, so look once when we start and remember if the user is an admin.
    47  	isAdmin, err := authorizer.HasPermission(permission.SuperuserAccess, st.ControllerTag())
    48  	if err != nil {
    49  		return nil, errors.Trace(err)
    50  	}
    51  
    52  	return &UserManagerAPI{
    53  		state:      st,
    54  		authorizer: authorizer,
    55  		check:      common.NewBlockChecker(st),
    56  		apiUser:    apiUser,
    57  		isAdmin:    isAdmin,
    58  	}, nil
    59  }
    60  
    61  func (api *UserManagerAPI) hasControllerAdminAccess() (bool, error) {
    62  	isAdmin, err := api.authorizer.HasPermission(permission.SuperuserAccess, api.state.ControllerTag())
    63  	if errors.IsNotFound(err) {
    64  		return false, nil
    65  	}
    66  	return isAdmin, err
    67  }
    68  
    69  // AddUser adds a user with a username, and either a password or
    70  // a randomly generated secret key which will be returned.
    71  func (api *UserManagerAPI) AddUser(args params.AddUsers) (params.AddUserResults, error) {
    72  	var result params.AddUserResults
    73  
    74  	if err := api.check.ChangeAllowed(); err != nil {
    75  		return result, errors.Trace(err)
    76  	}
    77  
    78  	if len(args.Users) == 0 {
    79  		return result, nil
    80  	}
    81  
    82  	// Create the results list to populate.
    83  	result.Results = make([]params.AddUserResult, len(args.Users))
    84  
    85  	isSuperUser, err := api.hasControllerAdminAccess()
    86  	if err != nil {
    87  		return result, errors.Trace(err)
    88  	}
    89  	if !isSuperUser {
    90  		return result, common.ErrPerm
    91  	}
    92  
    93  	for i, arg := range args.Users {
    94  		var user *state.User
    95  		var err error
    96  		if arg.Password != "" {
    97  			user, err = api.state.AddUser(arg.Username, arg.DisplayName, arg.Password, api.apiUser.Id())
    98  		} else {
    99  			user, err = api.state.AddUserWithSecretKey(arg.Username, arg.DisplayName, api.apiUser.Id())
   100  		}
   101  		if err != nil {
   102  			err = errors.Annotate(err, "failed to create user")
   103  			result.Results[i].Error = common.ServerError(err)
   104  			continue
   105  		} else {
   106  			result.Results[i] = params.AddUserResult{
   107  				Tag:       user.Tag().String(),
   108  				SecretKey: user.SecretKey(),
   109  			}
   110  		}
   111  
   112  	}
   113  	return result, nil
   114  }
   115  
   116  // RemoveUser permanently removes a user from the current controller for each
   117  // entity provided. While the user is permanently removed we keep it's
   118  // information around for auditing purposes.
   119  // TODO(redir): Add information about getting deleted user information when we
   120  // add that capability.
   121  func (api *UserManagerAPI) RemoveUser(entities params.Entities) (params.ErrorResults, error) {
   122  	var deletions params.ErrorResults
   123  
   124  	if err := api.check.ChangeAllowed(); err != nil {
   125  		return deletions, errors.Trace(err)
   126  	}
   127  
   128  	controllerOwner, err := api.state.ControllerOwner()
   129  	if err != nil {
   130  		return deletions, errors.Trace(err)
   131  	}
   132  
   133  	// Create the results list to populate.
   134  	deletions.Results = make([]params.ErrorResult, len(entities.Entities))
   135  
   136  	isSuperUser, err := api.hasControllerAdminAccess()
   137  	if err != nil {
   138  		return deletions, errors.Trace(err)
   139  	}
   140  	if !api.isAdmin && !isSuperUser {
   141  		return deletions, common.ErrPerm
   142  	}
   143  
   144  	// Remove the entities.
   145  	for i, e := range entities.Entities {
   146  		user, err := names.ParseUserTag(e.Tag)
   147  		if err != nil {
   148  			deletions.Results[i].Error = common.ServerError(err)
   149  			continue
   150  		}
   151  
   152  		if controllerOwner.Id() == user.Id() {
   153  			deletions.Results[i].Error = common.ServerError(
   154  				errors.Errorf("cannot delete controller owner %q", user.Name()))
   155  			continue
   156  		}
   157  		err = api.state.RemoveUser(user)
   158  		if err != nil {
   159  			if errors.IsUserNotFound(err) {
   160  				deletions.Results[i].Error = common.ServerError(err)
   161  			} else {
   162  				deletions.Results[i].Error = common.ServerError(
   163  					errors.Annotatef(err, "failed to delete user %q", user.Name()))
   164  			}
   165  			continue
   166  		}
   167  		deletions.Results[i].Error = nil
   168  	}
   169  	return deletions, nil
   170  }
   171  
   172  func (api *UserManagerAPI) getUser(tag string) (*state.User, error) {
   173  	userTag, err := names.ParseUserTag(tag)
   174  	if err != nil {
   175  		return nil, errors.Trace(err)
   176  	}
   177  	user, err := api.state.User(userTag)
   178  	if err != nil {
   179  		return nil, errors.Wrap(err, common.ErrPerm)
   180  	}
   181  	return user, nil
   182  }
   183  
   184  // EnableUser enables one or more users.  If the user is already enabled,
   185  // the action is considered a success.
   186  func (api *UserManagerAPI) EnableUser(users params.Entities) (params.ErrorResults, error) {
   187  	isSuperUser, err := api.hasControllerAdminAccess()
   188  	if err != nil {
   189  		return params.ErrorResults{}, errors.Trace(err)
   190  	}
   191  	if !isSuperUser {
   192  		return params.ErrorResults{}, common.ErrPerm
   193  	}
   194  
   195  	if err := api.check.ChangeAllowed(); err != nil {
   196  		return params.ErrorResults{}, errors.Trace(err)
   197  	}
   198  	return api.enableUserImpl(users, "enable", (*state.User).Enable)
   199  }
   200  
   201  // DisableUser disables one or more users.  If the user is already disabled,
   202  // the action is considered a success.
   203  func (api *UserManagerAPI) DisableUser(users params.Entities) (params.ErrorResults, error) {
   204  	isSuperUser, err := api.hasControllerAdminAccess()
   205  	if err != nil {
   206  		return params.ErrorResults{}, errors.Trace(err)
   207  	}
   208  	if !isSuperUser {
   209  		return params.ErrorResults{}, common.ErrPerm
   210  	}
   211  
   212  	if err := api.check.ChangeAllowed(); err != nil {
   213  		return params.ErrorResults{}, errors.Trace(err)
   214  	}
   215  	return api.enableUserImpl(users, "disable", (*state.User).Disable)
   216  }
   217  
   218  func (api *UserManagerAPI) enableUserImpl(args params.Entities, action string, method func(*state.User) error) (params.ErrorResults, error) {
   219  	var result params.ErrorResults
   220  
   221  	if len(args.Entities) == 0 {
   222  		return result, nil
   223  	}
   224  
   225  	isSuperUser, err := api.hasControllerAdminAccess()
   226  	if err != nil {
   227  		return result, errors.Trace(err)
   228  	}
   229  
   230  	if !api.isAdmin && isSuperUser {
   231  		return result, common.ErrPerm
   232  	}
   233  
   234  	// Create the results list to populate.
   235  	result.Results = make([]params.ErrorResult, len(args.Entities))
   236  
   237  	for i, arg := range args.Entities {
   238  		user, err := api.getUser(arg.Tag)
   239  		if err != nil {
   240  			result.Results[i].Error = common.ServerError(err)
   241  			continue
   242  		}
   243  		err = method(user)
   244  		if err != nil {
   245  			result.Results[i].Error = common.ServerError(errors.Errorf("failed to %s user: %s", action, err))
   246  		}
   247  	}
   248  	return result, nil
   249  }
   250  
   251  // UserInfo returns information on a user.
   252  func (api *UserManagerAPI) UserInfo(request params.UserInfoRequest) (params.UserInfoResults, error) {
   253  	var results params.UserInfoResults
   254  	isAdmin, err := api.hasControllerAdminAccess()
   255  	if err != nil {
   256  		return results, errors.Trace(err)
   257  	}
   258  
   259  	var accessForUser = func(userTag names.UserTag, result *params.UserInfoResult) {
   260  		// Lookup the access the specified user has to the controller.
   261  		access, err := common.GetPermission(api.state.UserPermission, userTag, api.state.ControllerTag())
   262  		if err == nil {
   263  			result.Result.Access = string(access)
   264  		} else if err != nil && !errors.IsNotFound(err) {
   265  			result.Result = nil
   266  			result.Error = common.ServerError(err)
   267  		}
   268  	}
   269  
   270  	var infoForUser = func(user *state.User) params.UserInfoResult {
   271  		var lastLogin *time.Time
   272  		userLastLogin, err := user.LastLogin()
   273  		if err != nil {
   274  			if !state.IsNeverLoggedInError(err) {
   275  				logger.Debugf("error getting last login: %v", err)
   276  			}
   277  		} else {
   278  			lastLogin = &userLastLogin
   279  		}
   280  		result := params.UserInfoResult{
   281  			Result: &params.UserInfo{
   282  				Username:       user.Name(),
   283  				DisplayName:    user.DisplayName(),
   284  				CreatedBy:      user.CreatedBy(),
   285  				DateCreated:    user.DateCreated(),
   286  				LastConnection: lastLogin,
   287  				Disabled:       user.IsDisabled(),
   288  			},
   289  		}
   290  		if user.IsDisabled() {
   291  			// disabled users have no access to the controller.
   292  			result.Result.Access = string(permission.NoAccess)
   293  		} else {
   294  			accessForUser(user.UserTag(), &result)
   295  		}
   296  		return result
   297  	}
   298  
   299  	argCount := len(request.Entities)
   300  	if argCount == 0 {
   301  		users, err := api.state.AllUsers(request.IncludeDisabled)
   302  		if err != nil {
   303  			return results, errors.Trace(err)
   304  		}
   305  		for _, user := range users {
   306  			if !isAdmin && !api.authorizer.AuthOwner(user.Tag()) {
   307  				continue
   308  			}
   309  			results.Results = append(results.Results, infoForUser(user))
   310  		}
   311  		return results, nil
   312  	}
   313  
   314  	// Create the results list to populate.
   315  	for _, arg := range request.Entities {
   316  		userTag, err := names.ParseUserTag(arg.Tag)
   317  		if err != nil {
   318  			results.Results = append(results.Results, params.UserInfoResult{Error: common.ServerError(err)})
   319  			continue
   320  		}
   321  		if !isAdmin && !api.authorizer.AuthOwner(userTag) {
   322  			results.Results = append(results.Results, params.UserInfoResult{Error: common.ServerError(common.ErrPerm)})
   323  			continue
   324  		}
   325  		if !userTag.IsLocal() {
   326  			// TODO(wallyworld) record login information about external users.
   327  			result := params.UserInfoResult{
   328  				Result: &params.UserInfo{
   329  					Username: userTag.Id(),
   330  				},
   331  			}
   332  			accessForUser(userTag, &result)
   333  			results.Results = append(results.Results, result)
   334  			continue
   335  		}
   336  		user, err := api.getUser(arg.Tag)
   337  		if err != nil {
   338  			results.Results = append(results.Results, params.UserInfoResult{Error: common.ServerError(err)})
   339  			continue
   340  		}
   341  		results.Results = append(results.Results, infoForUser(user))
   342  	}
   343  
   344  	return results, nil
   345  }
   346  
   347  // SetPassword changes the stored password for the specified users.
   348  func (api *UserManagerAPI) SetPassword(args params.EntityPasswords) (params.ErrorResults, error) {
   349  	if err := api.check.ChangeAllowed(); err != nil {
   350  		return params.ErrorResults{}, errors.Trace(err)
   351  	}
   352  
   353  	var result params.ErrorResults
   354  
   355  	if len(args.Changes) == 0 {
   356  		return result, nil
   357  	}
   358  
   359  	// Create the results list to populate.
   360  	result.Results = make([]params.ErrorResult, len(args.Changes))
   361  	for i, arg := range args.Changes {
   362  		if err := api.setPassword(arg); err != nil {
   363  			result.Results[i].Error = common.ServerError(err)
   364  		}
   365  	}
   366  	return result, nil
   367  }
   368  
   369  func (api *UserManagerAPI) setPassword(arg params.EntityPassword) error {
   370  	user, err := api.getUser(arg.Tag)
   371  	if err != nil {
   372  		return errors.Trace(err)
   373  	}
   374  
   375  	isSuperUser, err := api.hasControllerAdminAccess()
   376  	if err != nil {
   377  		return errors.Trace(err)
   378  	}
   379  
   380  	if api.apiUser != user.UserTag() && !api.isAdmin && !isSuperUser {
   381  		return errors.Trace(common.ErrPerm)
   382  	}
   383  	if arg.Password == "" {
   384  		return errors.New("cannot use an empty password")
   385  	}
   386  	if err := user.SetPassword(arg.Password); err != nil {
   387  		return errors.Annotate(err, "failed to set password")
   388  	}
   389  	return nil
   390  }
   391  
   392  // ResetPassword resets password for supplied users by
   393  // invalidating current passwords (if any) and generating
   394  // new random secret keys which will be returned.
   395  // Users cannot reset their own password.
   396  func (api *UserManagerAPI) ResetPassword(args params.Entities) (params.AddUserResults, error) {
   397  	var result params.AddUserResults
   398  
   399  	if err := api.check.ChangeAllowed(); err != nil {
   400  		return result, errors.Trace(err)
   401  	}
   402  
   403  	if len(args.Entities) == 0 {
   404  		return result, nil
   405  	}
   406  
   407  	isSuperUser, err := api.hasControllerAdminAccess()
   408  	if err != nil {
   409  		return result, errors.Trace(err)
   410  	}
   411  
   412  	result.Results = make([]params.AddUserResult, len(args.Entities))
   413  	for i, arg := range args.Entities {
   414  		result.Results[i] = params.AddUserResult{Tag: arg.Tag}
   415  		user, err := api.getUser(arg.Tag)
   416  		if err != nil {
   417  			result.Results[i].Error = common.ServerError(err)
   418  			continue
   419  		}
   420  		if isSuperUser && api.apiUser != user.Tag() {
   421  			key, err := user.ResetPassword()
   422  			if err != nil {
   423  				result.Results[i].Error = common.ServerError(err)
   424  				continue
   425  			}
   426  			result.Results[i].SecretKey = key
   427  		} else {
   428  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   429  		}
   430  	}
   431  	return result, nil
   432  }