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