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