-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Event ACLs #1046
Event ACLs #1046
Changes from 14 commits
0c62435
d777105
6f309c3
3ef482d
d5e1328
6e084f6
beb27fb
5bde81b
1e5a2a8
90f5eb8
84a4794
71aae88
320ab14
7e63572
18715a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,6 +52,12 @@ type ACL interface { | |
// ServiceRead checks for permission to read a given service | ||
ServiceRead(string) bool | ||
|
||
// EventRead determines if a specific event can be queried. | ||
EventRead(string) bool | ||
|
||
// EventWrite determines if a specific event may be fired. | ||
EventWrite(string) bool | ||
|
||
// ACLList checks for permission to list all the ACLs | ||
ACLList() bool | ||
|
||
|
@@ -87,6 +93,14 @@ func (s *StaticACL) ServiceWrite(string) bool { | |
return s.defaultAllow | ||
} | ||
|
||
func (s *StaticACL) EventRead(string) bool { | ||
return s.defaultAllow | ||
} | ||
|
||
func (s *StaticACL) EventWrite(string) bool { | ||
return s.defaultAllow | ||
} | ||
|
||
func (s *StaticACL) ACLList() bool { | ||
return s.allowManage | ||
} | ||
|
@@ -136,6 +150,9 @@ type PolicyACL struct { | |
|
||
// serviceRules contains the service policies | ||
serviceRules *radix.Tree | ||
|
||
// eventRules contains the user event policies | ||
eventRules *radix.Tree | ||
} | ||
|
||
// New is used to construct a policy based ACL from a set of policies | ||
|
@@ -145,6 +162,7 @@ func New(parent ACL, policy *Policy) (*PolicyACL, error) { | |
parent: parent, | ||
keyRules: radix.New(), | ||
serviceRules: radix.New(), | ||
eventRules: radix.New(), | ||
} | ||
|
||
// Load the key policy | ||
|
@@ -156,6 +174,12 @@ func New(parent ACL, policy *Policy) (*PolicyACL, error) { | |
for _, sp := range policy.Services { | ||
p.serviceRules.Insert(sp.Name, sp.Policy) | ||
} | ||
|
||
// Load the event policy | ||
for _, ep := range policy.Events { | ||
p.eventRules.Insert(ep.Event, ep.Policy) | ||
} | ||
|
||
return p, nil | ||
} | ||
|
||
|
@@ -266,6 +290,37 @@ func (p *PolicyACL) ServiceWrite(name string) bool { | |
return p.parent.ServiceWrite(name) | ||
} | ||
|
||
// EventRead is used to determine if the policy allows for a | ||
// specific user event to be read. | ||
func (p *PolicyACL) EventRead(name string) bool { | ||
// Longest-prefix match on event names | ||
if _, rule, ok := p.eventRules.LongestPrefix(name); ok { | ||
switch rule { | ||
case EventPolicyRead: | ||
return true | ||
case EventPolicyWrite: | ||
return true | ||
default: | ||
return false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a normal case we can hit or a programming error if we get here? Oh nm - this is where "deny" falls through to. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hitting this "default" covers the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah sorry I realized that right after I made the comment :-) |
||
} | ||
} | ||
|
||
// Nothing matched, use parent | ||
return p.parent.EventRead(name) | ||
} | ||
|
||
// EventWrite is used to determine if new events can be created | ||
// (fired) by the policy. | ||
func (p *PolicyACL) EventWrite(name string) bool { | ||
// Longest-prefix match event names | ||
if _, rule, ok := p.eventRules.LongestPrefix(name); ok { | ||
return rule == EventPolicyWrite | ||
} | ||
|
||
// No match, use parent | ||
return p.parent.EventWrite(name) | ||
} | ||
|
||
// ACLList checks if listing of ACLs is allowed | ||
func (p *PolicyACL) ACLList() bool { | ||
return p.parent.ACLList() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,10 @@ func (s *HTTPServer) EventFire(resp http.ResponseWriter, req *http.Request) (int | |
return nil, nil | ||
} | ||
|
||
// Get the ACL token | ||
var token string | ||
s.parseToken(req, &token) | ||
|
||
// Get the filters | ||
if filt := req.URL.Query().Get("node"); filt != "" { | ||
event.NodeFilter = filt | ||
|
@@ -57,7 +61,13 @@ func (s *HTTPServer) EventFire(resp http.ResponseWriter, req *http.Request) (int | |
} | ||
|
||
// Try to fire the event | ||
if err := s.agent.UserEvent(dc, event); err != nil { | ||
if err := s.agent.UserEvent(dc, token, event); err != nil { | ||
if strings.Contains(err.Error(), permissionDenied) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see we do this in a few places and this code will work fine as-is. Is the the usual way of looking for a particular error or would a type assertion on the error sub-type be a little cleaner? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think at some point we need to do a pass-through and have some kind of error struct which provides its type. I agree this is sort of ghetto, we should definitely address that broadly in a separate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree it's out of scope for this change. |
||
resp.WriteHeader(403) | ||
resp.Write([]byte(permissionDenied)) | ||
return nil, nil | ||
} | ||
resp.WriteHeader(500) | ||
return nil, err | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought a little about whether write always implies read (do we want to enable clients to only be able to create events) but I think this is the right way to go.