mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
4dce8f9496
* adjust session refresh to always occur (for disabled users) * feat: adds filtering option for Request Method in ACL's * simplify flow of internal/authorization/authorizer.go's methods * implement query string checking * utilize authorizer.Object fully * make matchers uniform * add tests * add missing request methods * add frontend enhancements to handle request method * add request method to 1FA Handler Suite * add internal ACL representations (preparsing) * expand on access_control next * add docs * remove unnecessary slice for network names and instead just use a plain string * add warning for ineffectual bypass policy (due to subjects) * add user/group wildcard support * fix(authorization): allow subject rules to match anonymous users * feat(api): add new params * docs(api): wording adjustments * test: add request method into testing and proxy docs * test: add several checks and refactor schema validation for ACL * test: add integration test for methods acl * refactor: apply suggestions from code review * docs(authorization): update description
178 lines
4.4 KiB
Go
178 lines
4.4 KiB
Go
package authorization
|
|
|
|
import (
|
|
"net"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/authelia/authelia/internal/configuration/schema"
|
|
)
|
|
|
|
// PolicyToLevel converts a string policy to int authorization level.
|
|
func PolicyToLevel(policy string) Level {
|
|
switch policy {
|
|
case "bypass":
|
|
return Bypass
|
|
case "one_factor":
|
|
return OneFactor
|
|
case "two_factor":
|
|
return TwoFactor
|
|
case "deny":
|
|
return Denied
|
|
}
|
|
// By default the deny policy applies.
|
|
return Denied
|
|
}
|
|
|
|
func schemaSubjectToACLSubject(subjectRule string) (subject AccessControlSubject) {
|
|
if strings.HasPrefix(subjectRule, userPrefix) {
|
|
user := strings.Trim(subjectRule[len(userPrefix):], " ")
|
|
|
|
return AccessControlUser{Name: user}
|
|
}
|
|
|
|
if strings.HasPrefix(subjectRule, groupPrefix) {
|
|
group := strings.Trim(subjectRule[len(groupPrefix):], " ")
|
|
|
|
return AccessControlGroup{Name: group}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func schemaDomainsToACL(domainRules []string) (domains []AccessControlDomain) {
|
|
for _, domainRule := range domainRules {
|
|
domain := AccessControlDomain{}
|
|
|
|
domainRule = strings.ToLower(domainRule)
|
|
|
|
switch {
|
|
case strings.HasPrefix(domainRule, "*."):
|
|
domain.Wildcard = true
|
|
domain.Name = domainRule[1:]
|
|
case strings.HasPrefix(domainRule, "{user}"):
|
|
domain.UserWildcard = true
|
|
domain.Name = domainRule[7:]
|
|
case strings.HasPrefix(domainRule, "{group}"):
|
|
domain.GroupWildcard = true
|
|
domain.Name = domainRule[8:]
|
|
default:
|
|
domain.Name = domainRule
|
|
}
|
|
|
|
domains = append(domains, domain)
|
|
}
|
|
|
|
return domains
|
|
}
|
|
|
|
func schemaResourcesToACL(resourceRules []string) (resources []AccessControlResource) {
|
|
for _, resourceRule := range resourceRules {
|
|
resources = append(resources, AccessControlResource{regexp.MustCompile(resourceRule)})
|
|
}
|
|
|
|
return resources
|
|
}
|
|
|
|
func schemaMethodsToACL(methodRules []string) (methods []string) {
|
|
for _, method := range methodRules {
|
|
methods = append(methods, strings.ToUpper(method))
|
|
}
|
|
|
|
return methods
|
|
}
|
|
|
|
func schemaNetworksToACL(networkRules []string, networksMap map[string][]*net.IPNet, networksCacheMap map[string]*net.IPNet) (networks []*net.IPNet) {
|
|
for _, network := range networkRules {
|
|
if _, ok := networksMap[network]; !ok {
|
|
if _, ok := networksCacheMap[network]; ok {
|
|
networks = append(networks, networksCacheMap[network])
|
|
} else {
|
|
cidr, err := parseNetwork(network)
|
|
if err == nil {
|
|
networks = append(networks, cidr)
|
|
networksCacheMap[cidr.String()] = cidr
|
|
|
|
if cidr.String() != network {
|
|
networksCacheMap[network] = cidr
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
networks = append(networks, networksMap[network]...)
|
|
}
|
|
}
|
|
|
|
return networks
|
|
}
|
|
|
|
func parseSchemaNetworks(schemaNetworks []schema.ACLNetwork) (networksMap map[string][]*net.IPNet, networksCacheMap map[string]*net.IPNet) {
|
|
// These maps store pointers to the net.IPNet values so we can reuse them efficiently.
|
|
// The networksMap contains the named networks as keys, the networksCacheMap contains the CIDR notations as keys.
|
|
networksMap = map[string][]*net.IPNet{}
|
|
networksCacheMap = map[string]*net.IPNet{}
|
|
|
|
for _, aclNetwork := range schemaNetworks {
|
|
var networks []*net.IPNet
|
|
|
|
for _, networkRule := range aclNetwork.Networks {
|
|
cidr, err := parseNetwork(networkRule)
|
|
if err == nil {
|
|
networks = append(networks, cidr)
|
|
networksCacheMap[cidr.String()] = cidr
|
|
|
|
if cidr.String() != networkRule {
|
|
networksCacheMap[networkRule] = cidr
|
|
}
|
|
}
|
|
}
|
|
|
|
if _, ok := networksMap[aclNetwork.Name]; len(networks) != 0 && !ok {
|
|
networksMap[aclNetwork.Name] = networks
|
|
}
|
|
}
|
|
|
|
return networksMap, networksCacheMap
|
|
}
|
|
|
|
func parseNetwork(networkRule string) (cidr *net.IPNet, err error) {
|
|
if !strings.Contains(networkRule, "/") {
|
|
ip := net.ParseIP(networkRule)
|
|
if ip.To4() != nil {
|
|
_, cidr, err = net.ParseCIDR(networkRule + "/32")
|
|
} else {
|
|
_, cidr, err = net.ParseCIDR(networkRule + "/128")
|
|
}
|
|
} else {
|
|
_, cidr, err = net.ParseCIDR(networkRule)
|
|
}
|
|
|
|
return cidr, err
|
|
}
|
|
|
|
func schemaSubjectsToACL(subjectRules [][]string) (subjects []AccessControlSubjects) {
|
|
for _, subjectRule := range subjectRules {
|
|
subject := AccessControlSubjects{}
|
|
|
|
for _, subjectRuleItem := range subjectRule {
|
|
subject.AddSubject(subjectRuleItem)
|
|
}
|
|
|
|
if len(subject.Subjects) != 0 {
|
|
subjects = append(subjects, subject)
|
|
}
|
|
}
|
|
|
|
return subjects
|
|
}
|
|
|
|
func domainToPrefixSuffix(domain string) (prefix, suffix string) {
|
|
parts := strings.Split(domain, ".")
|
|
|
|
if len(parts) == 1 {
|
|
return "", parts[0]
|
|
}
|
|
|
|
return parts[0], strings.Join(parts[1:], ".")
|
|
}
|