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