github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/common/password.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 "gopkg.in/juju/names.v2" 10 11 "github.com/juju/juju/apiserver/params" 12 "github.com/juju/juju/state" 13 ) 14 15 var logger = loggo.GetLogger("juju.apiserver.common") 16 17 // PasswordChanger implements a common SetPasswords method for use by 18 // various facades. 19 type PasswordChanger struct { 20 st state.EntityFinder 21 getCanChange GetAuthFunc 22 } 23 24 // NewPasswordChanger returns a new PasswordChanger. The GetAuthFunc will be 25 // used on each invocation of SetPasswords to determine current permissions. 26 func NewPasswordChanger(st state.EntityFinder, getCanChange GetAuthFunc) *PasswordChanger { 27 return &PasswordChanger{ 28 st: st, 29 getCanChange: getCanChange, 30 } 31 } 32 33 // SetPasswords sets the given password for each supplied entity, if possible. 34 func (pc *PasswordChanger) SetPasswords(args params.EntityPasswords) (params.ErrorResults, error) { 35 result := params.ErrorResults{ 36 Results: make([]params.ErrorResult, len(args.Changes)), 37 } 38 if len(args.Changes) == 0 { 39 return result, nil 40 } 41 canChange, err := pc.getCanChange() 42 if err != nil { 43 return params.ErrorResults{}, errors.Trace(err) 44 } 45 for i, param := range args.Changes { 46 tag, err := names.ParseTag(param.Tag) 47 if err != nil { 48 result.Results[i].Error = ServerError(ErrPerm) 49 continue 50 } 51 if !canChange(tag) { 52 result.Results[i].Error = ServerError(ErrPerm) 53 continue 54 } 55 if err := pc.setPassword(tag, param.Password); err != nil { 56 result.Results[i].Error = ServerError(err) 57 } 58 } 59 return result, nil 60 } 61 62 func (pc *PasswordChanger) setMongoPassword(entity state.Entity, password string) error { 63 type mongoPassworder interface { 64 SetMongoPassword(password string) error 65 } 66 // We set the mongo password first on the grounds that 67 // if it fails, the agent in question should still be able 68 // to authenticate to another API server and ask it to change 69 // its password. 70 if entity0, ok := entity.(mongoPassworder); ok { 71 if err := entity0.SetMongoPassword(password); err != nil { 72 return err 73 } 74 logger.Infof("setting mongo password for %q", entity.Tag()) 75 return nil 76 } 77 // TODO(dfc) fix 78 return NotSupportedError(entity.Tag(), "mongo access") 79 } 80 81 func (pc *PasswordChanger) setPassword(tag names.Tag, password string) error { 82 type jobsGetter interface { 83 Jobs() []state.MachineJob 84 } 85 var err error 86 entity0, err := pc.st.FindEntity(tag) 87 if err != nil { 88 return err 89 } 90 entity, ok := entity0.(state.Authenticator) 91 if !ok { 92 return NotSupportedError(tag, "authentication") 93 } 94 if entity, ok := entity0.(jobsGetter); ok { 95 for _, job := range entity.Jobs() { 96 paramsJob := job.ToParams() 97 if paramsJob.NeedsState() { 98 err = pc.setMongoPassword(entity0, password) 99 break 100 } 101 } 102 } 103 if err == nil { 104 err = entity.SetPassword(password) 105 logger.Infof("setting password for %q", tag) 106 } 107 return err 108 }