/
interfaces.go
148 lines (129 loc) · 4.3 KB
/
interfaces.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package common
import (
"github.com/juju/errors"
"github.com/juju/names/v5"
"github.com/juju/juju/controller"
"github.com/juju/juju/core/container"
"github.com/juju/juju/core/network"
"github.com/juju/juju/state"
)
// AuthFunc returns whether the given entity is available to some operation.
type AuthFunc func(tag names.Tag) bool
// GetAuthFunc returns an AuthFunc.
type GetAuthFunc func() (AuthFunc, error)
// AuthAny returns an AuthFunc generator that returns an AuthFunc that
// accepts any tag authorized by any of its arguments. If no arguments
// are passed this is equivalent to AuthNever.
func AuthAny(getFuncs ...GetAuthFunc) GetAuthFunc {
return func() (AuthFunc, error) {
funcs := make([]AuthFunc, len(getFuncs))
for i, getFunc := range getFuncs {
f, err := getFunc()
if err != nil {
return nil, errors.Trace(err)
}
funcs[i] = f
}
combined := func(tag names.Tag) bool {
for _, f := range funcs {
if f(tag) {
return true
}
}
return false
}
return combined, nil
}
}
// AuthAlways returns an authentication function that always returns true iff it is passed a valid tag.
func AuthAlways() GetAuthFunc {
return func() (AuthFunc, error) {
return func(tag names.Tag) bool {
return true
}, nil
}
}
// AuthFuncForTag returns an authentication function that always returns true iff it is passed a specific tag.
func AuthFuncForTag(valid names.Tag) GetAuthFunc {
return func() (AuthFunc, error) {
return func(tag names.Tag) bool {
return tag == valid
}, nil
}
}
// AuthFuncForTagKind returns a GetAuthFunc which creates an AuthFunc
// allowing only the given tag kind and denies all others. Passing an
// empty kind is an error.
func AuthFuncForTagKind(kind string) GetAuthFunc {
return func() (AuthFunc, error) {
if kind == "" {
return nil, errors.Errorf("tag kind cannot be empty")
}
return func(tag names.Tag) bool {
// Allow only the given tag kind.
if tag == nil {
return false
}
return tag.Kind() == kind
}, nil
}
}
// Authorizer represents the authenticated entity using the API server.
type Authorizer interface {
// AuthController returns whether the authenticated entity is
// a machine acting as a controller. Can't be removed from this
// interface without introducing a dependency on something else
// to look up that property: it's not inherent in the result of
// GetAuthTag, as the other methods all are.
AuthController() bool
// AuthMachineAgent returns true if the entity is a machine agent.
AuthMachineAgent() bool
// GetAuthTag returns the entity's tag.
GetAuthTag() names.Tag
}
// AuthFuncForMachineAgent returns a GetAuthFunc which creates an AuthFunc
// allowing only machine agents and their controllers
func AuthFuncForMachineAgent(authorizer Authorizer) GetAuthFunc {
return func() (AuthFunc, error) {
isModelManager := authorizer.AuthController()
isMachineAgent := authorizer.AuthMachineAgent()
authEntityTag := authorizer.GetAuthTag()
return func(tag names.Tag) bool {
if isMachineAgent && tag == authEntityTag {
// A machine agent can always access its own machine.
return true
}
switch tag := tag.(type) {
case names.MachineTag:
parentId := container.ParentId(tag.Id())
if parentId == "" {
// All top-level machines are accessible by the controller.
return isModelManager
}
// All containers with the authenticated machine as a
// parent are accessible by it.
// TODO(dfc) sometimes authEntity tag is nil, which is fine because nil is
// only equal to nil, but it suggests someone is passing an authorizer
// with a nil tag.
return isMachineAgent && names.NewMachineTag(parentId) == authEntityTag
default:
return false
}
}, nil
}
}
// ControllerConfigState defines the methods needed by
// ControllerConfigAPI
type ControllerConfigState interface {
ControllerConfig() (controller.Config, error)
ModelExists(string) (bool, error)
NewExternalControllers() state.ExternalControllers
APIHostPortsForAgents() ([]network.SpaceHostPorts, error)
CompletedMigrationForModel(string) (state.ModelMigration, error)
}
type controllerInfoState interface {
ControllerConfig() (controller.Config, error)
APIHostPortsForAgents() ([]network.SpaceHostPorts, error)
}