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: ¶ms.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: ¶ms.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 }