/
auth.go
145 lines (130 loc) · 3.91 KB
/
auth.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
package x
import (
"github.com/iov-one/weave"
)
// Authenticator is an interface we can use to extract authentication info
// from the context. This should be passed into the constructor of
// handlers, so we can plug in another authentication system,
// rather than hard-coding x/auth for all extensions.
type Authenticator interface {
// GetConditions reveals all Conditions fulfilled,
// you may want GetAddresses helper
GetConditions(weave.Context) []weave.Condition
// HasAddress checks if any condition matches this address
HasAddress(weave.Context, weave.Address) bool
}
// MultiAuth chains together many Authenticators into one
type MultiAuth struct {
impls []Authenticator
}
var _ Authenticator = MultiAuth{}
// ChainAuth groups together a series of Authenticator
func ChainAuth(impls ...Authenticator) MultiAuth {
return MultiAuth{impls}
}
// GetConditions combines all Conditions from all Authenticators
func (m MultiAuth) GetConditions(ctx weave.Context) []weave.Condition {
var res []weave.Condition
for _, impl := range m.impls {
add := impl.GetConditions(ctx)
if len(add) > 0 {
res = append(res, add...)
}
}
// TODO: remove duplicates (don't sort?)
return res
}
// HasAddress returns true iff any Authenticator support this
func (m MultiAuth) HasAddress(ctx weave.Context, addr weave.Address) bool {
for _, impl := range m.impls {
if impl.HasAddress(ctx, addr) {
return true
}
}
return false
}
// GetAddresses wraps the GetConditions method of any Authenticator
func GetAddresses(ctx weave.Context, auth Authenticator) []weave.Address {
perms := auth.GetConditions(ctx)
addrs := make([]weave.Address, len(perms))
for i, p := range perms {
addrs[i] = p.Address()
}
return addrs
}
// AnySigner returns a permission or nil.
//
// This function returns always the first condition as defined in the
// transaction. Using this function can introduce a security hole. One must
// never assume the order of transaction signatures, because those are not part
// of signed content. Order of signatures in transaction can be altered at any
// time.
//
// This function is deprecated and must not be used for new implementations.
func AnySigner(ctx weave.Context, auth Authenticator) weave.Condition {
if sigs := auth.GetConditions(ctx); len(sigs) > 0 {
return sigs[0]
}
return nil
}
// HasAllAddresses returns true if all elements in required are
// also in context.
func HasAllAddresses(ctx weave.Context, auth Authenticator, required []weave.Address) bool {
for _, r := range required {
if !auth.HasAddress(ctx, r) {
return false
}
}
return true
}
// HasNAddresses returns true if at least n elements in requested are
// also in context.
func HasNAddresses(ctx weave.Context, auth Authenticator, required []weave.Address, n int) bool {
// Special case: is this an error???
if n <= 0 {
return true
}
for _, r := range required {
if auth.HasAddress(ctx, r) {
n--
if n == 0 {
return true
}
}
}
return false
}
// HasAllConditions returns true if all elements in required are
// also in context.
func HasAllConditions(ctx weave.Context, auth Authenticator, required []weave.Condition) bool {
return HasNConditions(ctx, auth, required, len(required))
}
// HasNConditions returns true if at least n elements in requested are
// also in context.
// Useful for threshold conditions (1 of 3, 3 of 5, etc...)
func HasNConditions(ctx weave.Context, auth Authenticator, requested []weave.Condition, n int) bool {
// Special case: is this an error???
if n <= 0 {
return true
}
perms := auth.GetConditions(ctx)
// NOTE: optimize this with sort from N^2 to N*log N (?)
// low-priority, as N is always small, better that it works
for _, perm := range requested {
if hasPerm(perms, perm) {
n--
if n == 0 {
return true
}
}
}
return false
}
func hasPerm(perms []weave.Condition, perm weave.Condition) bool {
for _, p := range perms {
if p.Equals(perm) {
return true
}
}
return false
}