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:], ".")
|
||
|
}
|