github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "gopkg.in/macaroon.v1" 10 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 "github.com/juju/names" 14 15 "github.com/juju/juju/apiserver/common" 16 "github.com/juju/juju/apiserver/modelmanager" 17 "github.com/juju/juju/apiserver/params" 18 "github.com/juju/juju/state" 19 ) 20 21 var logger = loggo.GetLogger("juju.apiserver.usermanager") 22 23 func init() { 24 common.RegisterStandardFacade("UserManager", 1, NewUserManagerAPI) 25 } 26 27 // UserManagerAPI implements the user manager interface and is the concrete 28 // implementation of the api end point. 29 type UserManagerAPI struct { 30 state *state.State 31 authorizer common.Authorizer 32 createLocalLoginMacaroon func(names.UserTag) (*macaroon.Macaroon, error) 33 check *common.BlockChecker 34 apiUser names.UserTag 35 isAdmin bool 36 } 37 38 func NewUserManagerAPI( 39 st *state.State, 40 resources *common.Resources, 41 authorizer common.Authorizer, 42 ) (*UserManagerAPI, error) { 43 if !authorizer.AuthClient() { 44 return nil, common.ErrPerm 45 } 46 47 // Since we know this is a user tag (because AuthClient is true), 48 // we just do the type assertion to the UserTag. 49 apiUser, _ := authorizer.GetAuthTag().(names.UserTag) 50 // Pretty much all of the user manager methods have special casing for admin 51 // users, so look once when we start and remember if the user is an admin. 52 isAdmin, err := st.IsControllerAdministrator(apiUser) 53 if err != nil { 54 return nil, errors.Trace(err) 55 } 56 57 resource, ok := resources.Get("createLocalLoginMacaroon").(common.ValueResource) 58 if !ok { 59 return nil, errors.NotFoundf("userAuth resource") 60 } 61 createLocalLoginMacaroon, ok := resource.Value.(func(names.UserTag) (*macaroon.Macaroon, error)) 62 if !ok { 63 return nil, errors.NotValidf("userAuth resource") 64 } 65 66 return &UserManagerAPI{ 67 state: st, 68 authorizer: authorizer, 69 createLocalLoginMacaroon: createLocalLoginMacaroon, 70 check: common.NewBlockChecker(st), 71 apiUser: apiUser, 72 isAdmin: isAdmin, 73 }, nil 74 } 75 76 // AddUser adds a user with a username, and either a password or 77 // a randomly generated secret key which will be returned. 78 func (api *UserManagerAPI) AddUser(args params.AddUsers) (params.AddUserResults, error) { 79 result := params.AddUserResults{ 80 Results: make([]params.AddUserResult, len(args.Users)), 81 } 82 if err := api.check.ChangeAllowed(); err != nil { 83 return result, errors.Trace(err) 84 } 85 86 if len(args.Users) == 0 { 87 return result, nil 88 } 89 if !api.isAdmin { 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 if len(arg.SharedModelTags) > 0 { 113 modelAccess, err := modelmanager.FromModelAccessParam(arg.ModelAccess) 114 if err != nil { 115 err = errors.Annotatef(err, "user %q created but models not shared", arg.Username) 116 result.Results[i].Error = common.ServerError(err) 117 continue 118 } 119 userTag := user.Tag().(names.UserTag) 120 for _, modelTagStr := range arg.SharedModelTags { 121 modelTag, err := names.ParseModelTag(modelTagStr) 122 if err != nil { 123 err = errors.Annotatef(err, "user %q created but model %q not shared", arg.Username, modelTagStr) 124 result.Results[i].Error = common.ServerError(err) 125 break 126 } 127 err = modelmanager.ChangeModelAccess( 128 modelmanager.NewStateBackend(api.state), modelTag, api.apiUser, 129 userTag, params.GrantModelAccess, modelAccess, api.isAdmin) 130 if err != nil { 131 err = errors.Annotatef(err, "user %q created but model %q not shared", arg.Username, modelTagStr) 132 result.Results[i].Error = common.ServerError(err) 133 break 134 } 135 } 136 } 137 } 138 return result, nil 139 } 140 141 func (api *UserManagerAPI) getUser(tag string) (*state.User, error) { 142 userTag, err := names.ParseUserTag(tag) 143 if err != nil { 144 return nil, errors.Trace(err) 145 } 146 user, err := api.state.User(userTag) 147 if err != nil { 148 return nil, errors.Wrap(err, common.ErrPerm) 149 } 150 return user, nil 151 } 152 153 // EnableUser enables one or more users. If the user is already enabled, 154 // the action is consided a success. 155 func (api *UserManagerAPI) EnableUser(users params.Entities) (params.ErrorResults, error) { 156 if err := api.check.ChangeAllowed(); err != nil { 157 return params.ErrorResults{}, errors.Trace(err) 158 } 159 return api.enableUserImpl(users, "enable", (*state.User).Enable) 160 } 161 162 // DisableUser disables one or more users. If the user is already disabled, 163 // the action is consided a success. 164 func (api *UserManagerAPI) DisableUser(users params.Entities) (params.ErrorResults, error) { 165 if err := api.check.ChangeAllowed(); err != nil { 166 return params.ErrorResults{}, errors.Trace(err) 167 } 168 return api.enableUserImpl(users, "disable", (*state.User).Disable) 169 } 170 171 func (api *UserManagerAPI) enableUserImpl(args params.Entities, action string, method func(*state.User) error) (params.ErrorResults, error) { 172 result := params.ErrorResults{ 173 Results: make([]params.ErrorResult, len(args.Entities)), 174 } 175 if len(args.Entities) == 0 { 176 return result, nil 177 } 178 if !api.isAdmin { 179 return result, common.ErrPerm 180 } 181 182 for i, arg := range args.Entities { 183 user, err := api.getUser(arg.Tag) 184 if err != nil { 185 result.Results[i].Error = common.ServerError(err) 186 continue 187 } 188 err = method(user) 189 if err != nil { 190 result.Results[i].Error = common.ServerError(errors.Errorf("failed to %s user: %s", action, err)) 191 } 192 } 193 return result, nil 194 } 195 196 // UserInfo returns information on a user. 197 func (api *UserManagerAPI) UserInfo(request params.UserInfoRequest) (params.UserInfoResults, error) { 198 var results params.UserInfoResults 199 var infoForUser = func(user *state.User) params.UserInfoResult { 200 var lastLogin *time.Time 201 userLastLogin, err := user.LastLogin() 202 if err != nil { 203 if !state.IsNeverLoggedInError(err) { 204 logger.Debugf("error getting last login: %v", err) 205 } 206 } else { 207 lastLogin = &userLastLogin 208 } 209 return params.UserInfoResult{ 210 Result: ¶ms.UserInfo{ 211 Username: user.Name(), 212 DisplayName: user.DisplayName(), 213 CreatedBy: user.CreatedBy(), 214 DateCreated: user.DateCreated(), 215 LastConnection: lastLogin, 216 Disabled: user.IsDisabled(), 217 }, 218 } 219 } 220 221 argCount := len(request.Entities) 222 if argCount == 0 { 223 users, err := api.state.AllUsers(request.IncludeDisabled) 224 if err != nil { 225 return results, errors.Trace(err) 226 } 227 for _, user := range users { 228 results.Results = append(results.Results, infoForUser(user)) 229 } 230 return results, nil 231 } 232 233 results.Results = make([]params.UserInfoResult, argCount) 234 for i, arg := range request.Entities { 235 user, err := api.getUser(arg.Tag) 236 if err != nil { 237 results.Results[i].Error = common.ServerError(err) 238 continue 239 } 240 results.Results[i] = infoForUser(user) 241 } 242 243 return results, nil 244 } 245 246 // SetPassword changes the stored password for the specified users. 247 func (api *UserManagerAPI) SetPassword(args params.EntityPasswords) (params.ErrorResults, error) { 248 if err := api.check.ChangeAllowed(); err != nil { 249 return params.ErrorResults{}, errors.Trace(err) 250 } 251 result := params.ErrorResults{ 252 Results: make([]params.ErrorResult, len(args.Changes)), 253 } 254 if len(args.Changes) == 0 { 255 return result, nil 256 } 257 for i, arg := range args.Changes { 258 if err := api.setPassword(arg); err != nil { 259 result.Results[i].Error = common.ServerError(err) 260 } 261 } 262 return result, nil 263 } 264 265 func (api *UserManagerAPI) setPassword(arg params.EntityPassword) error { 266 user, err := api.getUser(arg.Tag) 267 if err != nil { 268 return errors.Trace(err) 269 } 270 if api.apiUser != user.UserTag() && !api.isAdmin { 271 return errors.Trace(common.ErrPerm) 272 } 273 if arg.Password == "" { 274 return errors.New("cannot use an empty password") 275 } 276 if err := user.SetPassword(arg.Password); err != nil { 277 return errors.Annotate(err, "failed to set password") 278 } 279 return nil 280 } 281 282 // CreateLocalLoginMacaroon creates a macaroon for the specified users to use 283 // for future logins. 284 func (api *UserManagerAPI) CreateLocalLoginMacaroon(args params.Entities) (params.MacaroonResults, error) { 285 results := params.MacaroonResults{ 286 Results: make([]params.MacaroonResult, len(args.Entities)), 287 } 288 createLocalLoginMacaroon := func(arg params.Entity) (*macaroon.Macaroon, error) { 289 user, err := api.getUser(arg.Tag) 290 if err != nil { 291 return nil, errors.Trace(err) 292 } 293 if api.apiUser != user.UserTag() && !api.isAdmin { 294 return nil, errors.Trace(common.ErrPerm) 295 } 296 return api.createLocalLoginMacaroon(user.UserTag()) 297 } 298 for i, arg := range args.Entities { 299 m, err := createLocalLoginMacaroon(arg) 300 if err != nil { 301 results.Results[i].Error = common.ServerError(err) 302 continue 303 } 304 results.Results[i].Result = m 305 } 306 return results, nil 307 }