mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-05-29 23:17:38 +02:00
Add request authorization ruleset
This commit is contained in:
parent
333e68637f
commit
0ce9ae756e
17
pkg/apis/options/authorization.go
Normal file
17
pkg/apis/options/authorization.go
Normal file
@ -0,0 +1,17 @@
|
||||
package options
|
||||
|
||||
type AuthorizationPolicy string
|
||||
|
||||
const (
|
||||
AllowPolicy AuthorizationPolicy = "Allow"
|
||||
DenyPolicy AuthorizationPolicy = "Deny"
|
||||
)
|
||||
|
||||
type AuthorizationRule struct {
|
||||
Policy AuthorizationPolicy
|
||||
Path string
|
||||
Methods []string
|
||||
IPs []string
|
||||
}
|
||||
|
||||
type RequestRules []AuthorizationRule
|
86
pkg/authorization/conditions.go
Normal file
86
pkg/authorization/conditions.go
Normal file
@ -0,0 +1,86 @@
|
||||
package authorization
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
|
||||
)
|
||||
|
||||
type condition interface {
|
||||
matches(*http.Request) bool
|
||||
}
|
||||
|
||||
type methodCondition struct {
|
||||
methods map[string]struct{}
|
||||
}
|
||||
|
||||
func (m methodCondition) matches(req *http.Request) bool {
|
||||
_, ok := m.methods[strings.ToUpper(req.Method)]
|
||||
return ok
|
||||
}
|
||||
|
||||
func newMethodCondition(methods []string) condition {
|
||||
methodMap := make(map[string]struct{})
|
||||
for _, method := range methods {
|
||||
methodMap[strings.ToUpper(method)] = struct{}{}
|
||||
}
|
||||
return methodCondition{
|
||||
methods: methodMap,
|
||||
}
|
||||
}
|
||||
|
||||
type pathCondition struct {
|
||||
pathRegexp *regexp.Regexp
|
||||
}
|
||||
|
||||
func (p pathCondition) matches(req *http.Request) bool {
|
||||
return p.pathRegexp.MatchString(req.URL.Path)
|
||||
}
|
||||
|
||||
func newPathCondition(path string) (condition, error) {
|
||||
exp, err := regexp.Compile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pathCondition{
|
||||
pathRegexp: exp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ipCondition struct {
|
||||
netSet *ip.NetSet
|
||||
getClientIP func(req *http.Request) net.IP
|
||||
}
|
||||
|
||||
func (i ipCondition) matches(req *http.Request) bool {
|
||||
ip := i.getClientIP(req)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
return i.netSet.Has(ip)
|
||||
}
|
||||
|
||||
func newIPCondition(rawIPs []string, getClientIPFunc func(req *http.Request) net.IP) (condition, error) {
|
||||
if getClientIPFunc == nil {
|
||||
return nil, errors.New("client IP function required for IP condition")
|
||||
}
|
||||
|
||||
netSet := ip.NewNetSet()
|
||||
for _, rawIP := range rawIPs {
|
||||
ipNet := ip.ParseIPNet(rawIP)
|
||||
if ipNet == nil {
|
||||
return nil, fmt.Errorf("could not parse IP network: %s", rawIP)
|
||||
}
|
||||
netSet.AddIPNet(*ipNet)
|
||||
}
|
||||
|
||||
return ipCondition{
|
||||
netSet: netSet,
|
||||
getClientIP: getClientIPFunc,
|
||||
}, nil
|
||||
}
|
106
pkg/authorization/rules.go
Normal file
106
pkg/authorization/rules.go
Normal file
@ -0,0 +1,106 @@
|
||||
package authorization
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||
)
|
||||
|
||||
type AuthorizationPolicy int
|
||||
|
||||
const (
|
||||
NonePolicy AuthorizationPolicy = iota
|
||||
AllowPolicy
|
||||
DenyPolicy
|
||||
)
|
||||
|
||||
type RuleSet interface {
|
||||
Matches(req *http.Request) AuthorizationPolicy
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
conditions []condition
|
||||
policy AuthorizationPolicy
|
||||
}
|
||||
|
||||
func (r rule) matches(req *http.Request) AuthorizationPolicy {
|
||||
for _, condition := range r.conditions {
|
||||
if !condition.matches(req) {
|
||||
// One of the conditions didn't match so this rule does not apply
|
||||
return NonePolicy
|
||||
}
|
||||
}
|
||||
// If all conditions match, return the configured rule policy
|
||||
return r.policy
|
||||
}
|
||||
|
||||
func newRule(authRule options.AuthorizationRule, getClientIPFunc func(*http.Request) net.IP) (rule, error) {
|
||||
// This function should add the conditions in order of complexity, least complex first
|
||||
conditions := []condition{}
|
||||
|
||||
if len(authRule.Methods) > 0 {
|
||||
conditions = append(conditions, newMethodCondition(authRule.Methods))
|
||||
}
|
||||
|
||||
if len(authRule.Path) > 0 {
|
||||
condition, err := newPathCondition(authRule.Path)
|
||||
if err != nil {
|
||||
return rule{}, err
|
||||
}
|
||||
conditions = append(conditions, condition)
|
||||
}
|
||||
|
||||
if len(authRule.IPs) > 0 {
|
||||
condition, err := newIPCondition(authRule.IPs, getClientIPFunc)
|
||||
if err != nil {
|
||||
return rule{}, err
|
||||
}
|
||||
conditions = append(conditions, condition)
|
||||
}
|
||||
|
||||
var policy AuthorizationPolicy
|
||||
switch authRule.Policy {
|
||||
case options.AllowPolicy:
|
||||
policy = AllowPolicy
|
||||
case options.DenyPolicy:
|
||||
policy = DenyPolicy
|
||||
default:
|
||||
// This shouldn't be the case and should be prevented by validation
|
||||
policy = NonePolicy
|
||||
}
|
||||
|
||||
return rule{
|
||||
conditions: conditions,
|
||||
policy: policy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ruleSet struct {
|
||||
rules []rule
|
||||
}
|
||||
|
||||
func (r ruleSet) Matches(req *http.Request) AuthorizationPolicy {
|
||||
for _, rule := range r.rules {
|
||||
if policy := rule.matches(req); policy != NonePolicy {
|
||||
// The rule applies to this request, return its policy
|
||||
return policy
|
||||
}
|
||||
}
|
||||
// No rules matched
|
||||
return NonePolicy
|
||||
}
|
||||
|
||||
func NewRuleSet(requestRules options.RequestRules, getClientIPFunc func(*http.Request) net.IP) (RuleSet, error) {
|
||||
rules := []rule{}
|
||||
for _, requestRule := range requestRules {
|
||||
r, err := newRule(requestRule, getClientIPFunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules = append(rules, r)
|
||||
}
|
||||
return ruleSet{
|
||||
rules: rules,
|
||||
}, nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user