@@ -0,0 +1,106 @@
1+package authorization
2+
3+import (
4+ "net"
5+ "net/http"
6+
7+ "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
8+)
9+
10+type AuthorizationPolicy int
11+
12+const (
13+ NonePolicy AuthorizationPolicy = iota
14+ AllowPolicy
15+ DenyPolicy
16+)
17+
18+type RuleSet interface {
19+ Matches(req *http.Request) AuthorizationPolicy
20+}
21+
22+type rule struct {
23+ conditions []condition
24+ policy AuthorizationPolicy
25+}
26+
27+func (r rule) matches(req *http.Request) AuthorizationPolicy {
28+ for _, condition := range r.conditions {
29+ if !condition.matches(req) {
30+ // One of the conditions didn't match so this rule does not apply
31+ return NonePolicy
32+ }
33+ }
34+ // If all conditions match, return the configured rule policy
35+ return r.policy
36+}
37+
38+func newRule(authRule options.AuthorizationRule, getClientIPFunc func(*http.Request) net.IP) (rule, error) {
39+ // This function should add the conditions in order of complexity, least complex first
40+ conditions := []condition{}
41+
42+ if len(authRule.Methods) > 0 {
43+ conditions = append(conditions, newMethodCondition(authRule.Methods))
44+ }
45+
46+ if len(authRule.Path) > 0 {
47+ condition, err := newPathCondition(authRule.Path)
48+ if err != nil {
49+ return rule{}, err
50+ }
51+ conditions = append(conditions, condition)
52+ }
53+
54+ if len(authRule.IPs) > 0 {
55+ condition, err := newIPCondition(authRule.IPs, getClientIPFunc)
56+ if err != nil {
57+ return rule{}, err
58+ }
59+ conditions = append(conditions, condition)
60+ }
61+
62+ var policy AuthorizationPolicy
63+ switch authRule.Policy {
64+ case options.AllowPolicy:
65+ policy = AllowPolicy
66+ case options.DenyPolicy:
67+ policy = DenyPolicy
68+ default:
69+ // This shouldn't be the case and should be prevented by validation
70+ policy = NonePolicy
71+ }
72+
73+ return rule{
74+ conditions: conditions,
75+ policy: policy,
76+ }, nil
77+}
78+
79+type ruleSet struct {
80+ rules []rule
81+}
82+
83+func (r ruleSet) Matches(req *http.Request) AuthorizationPolicy {
84+ for _, rule := range r.rules {
85+ if policy := rule.matches(req); policy != NonePolicy {
86+ // The rule applies to this request, return its policy
87+ return policy
88+ }
89+ }
90+ // No rules matched
91+ return NonePolicy
92+}
93+
94+func NewRuleSet(requestRules options.RequestRules, getClientIPFunc func(*http.Request) net.IP) (RuleSet, error) {
95+ rules := []rule{}
96+ for _, requestRule := range requestRules {
97+ r, err := newRule(requestRule, getClientIPFunc)
98+ if err != nil {
99+ return nil, err
100+ }
101+ rules = append(rules, r)
102+ }
103+ return ruleSet{
104+ rules: rules,
105+ }, nil
106+}