mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
ddea31193b
OpenID connect has become a standard when it comes to authentication and in order to fix a security concern around forwarding authentication and authorization information it has been decided to add support for it. This feature is in beta version and only enabled when there is a configuration for it. Before enabling it in production, please consider that it's in beta with potential bugs and that there are several production critical features still missing such as all OIDC related data is stored in configuration or memory. This means you are potentially going to experience issues with HA deployments, or when restarting a single instance specifically related to OIDC. We are still working on adding the remaining set of features before making it GA as soon as possible. Related to #189 Co-authored-by: Clement Michaud <clement.michaud34@gmail.com>
193 lines
4.9 KiB
Go
193 lines
4.9 KiB
Go
package authorization
|
|
|
|
import (
|
|
"net"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/authelia/authelia/internal/authentication"
|
|
"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:], ".")
|
|
}
|
|
|
|
// IsAuthLevelSufficient returns true if the current authenticationLevel is above the authorizationLevel.
|
|
func IsAuthLevelSufficient(authenticationLevel authentication.Level, authorizationLevel Level) bool {
|
|
switch authorizationLevel {
|
|
case Denied:
|
|
return false
|
|
case OneFactor:
|
|
return authenticationLevel >= authentication.OneFactor
|
|
case TwoFactor:
|
|
return authenticationLevel >= authentication.TwoFactor
|
|
}
|
|
|
|
return true
|
|
}
|