/
authorizer.go
102 lines (86 loc) · 3.47 KB
/
authorizer.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
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package security
import (
"reflect"
"v.io/v23/context"
)
// DefaultAuthorizer returns an Authorizer that implements a "reasonably secure"
// authorization policy that can be used whenever in doubt.
//
// It has the conservative policy that requires one end of the RPC to have a
// blessing that is extended from the blessing presented by the other end.
func DefaultAuthorizer() Authorizer {
return defaultAuthorizer{}
}
type defaultAuthorizer struct{}
func (defaultAuthorizer) Authorize(ctx *context.T, call Call) error {
var (
localNames = LocalBlessingNames(ctx, call)
remoteNames, remoteErr = RemoteBlessingNames(ctx, call)
)
// Authorize if any element in localNames is a "delegate of" (i.e., has been
// blessed by) any element in remoteNames, OR vice-versa.
for _, l := range localNames {
if BlessingPattern(l).MatchedBy(remoteNames...) {
// One of remoteNames is an extension of l.
return nil
}
}
for _, r := range remoteNames {
if BlessingPattern(r).MatchedBy(localNames...) {
// One of localNames is an extension of r.
return nil
}
}
return ErrorfAuthorizationFailed(ctx, "principal with blessings %v (rejected %v) is not authorized by principal with blessings %v", remoteNames, remoteErr, localNames)
}
// AllowEveryone returns an Authorizer which implements a policy of always
// allowing access - irrespective of any parameters of the call or the
// blessings of the caller.
func AllowEveryone() Authorizer {
return allowEveryone{}
}
type allowEveryone struct{}
func (allowEveryone) Authorize(*context.T, Call) error { return nil }
// PublicKeyAuthorizer only authorizes principals with a specific public key.
//
// Normally, authorizations in Vanadium should be based on blessing names and not
// public keys, since the former are resilient to key rotations and process
// replication. However, in rare circumstances it may be possible that blessing names
// cannot be used (for example, if the local end does not recognize the remote end's
// blessing root), and the PublicKey might be usable instead.
func PublicKeyAuthorizer(key PublicKey) Authorizer {
return publicKeyAuthorizer{key}
}
type publicKeyAuthorizer struct{ key PublicKey }
func (a publicKeyAuthorizer) Authorize(ctx *context.T, call Call) error {
remote := call.RemoteBlessings().PublicKey()
if remote == nil {
return ErrorfPublicKeyNotAllowed(ctx, "peer has no public key (%v), the authorized public key %v", "", a.key.String())
}
if !reflect.DeepEqual(remote, a.key) {
return ErrorfPublicKeyNotAllowed(ctx, "peer has public key %v, not the authorized public key %v", remote.String(), a.key.String())
}
return nil
}
// EndpointAuthorizer authorizes principals iff they present blessings that
// match those specified in call.RemoteEndpoint().
func EndpointAuthorizer() Authorizer {
return endpointAuthorizer{}
}
type endpointAuthorizer struct{}
func (endpointAuthorizer) Authorize(ctx *context.T, call Call) error {
patterns := call.RemoteEndpoint().BlessingNames()
if len(patterns) == 0 {
return nil
}
names, rejected := RemoteBlessingNames(ctx, call)
for _, p := range patterns {
if BlessingPattern(p).MatchedBy(names...) {
return nil
}
}
return ErrorfEndpointAuthorizationFailed(ctx, "blessings in endpoint %v not matched by blessings presented: %v (rejected %v)", call.RemoteEndpoint().String(), names, rejected)
}