mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
72a3f1e0d7
When no rule is set to two_factor in ACL configuration, 2FA is considered disabled. Therefore, when a user cannot be redirected correctly because no target URL is provided or the URL is unsafe, the user is either redirected to the default URL or to the 'already authenticated' view instead of the second factor view. Fixes #683
123 lines
3.3 KiB
Go
123 lines
3.3 KiB
Go
package authorization
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/authelia/authelia/internal/configuration/schema"
|
|
"github.com/authelia/authelia/internal/logging"
|
|
)
|
|
|
|
const userPrefix = "user:"
|
|
const groupPrefix = "group:"
|
|
|
|
// Authorizer the component in charge of checking whether a user can access a given resource.
|
|
type Authorizer struct {
|
|
configuration schema.AccessControlConfiguration
|
|
}
|
|
|
|
// NewAuthorizer create an instance of authorizer with a given access control configuration.
|
|
func NewAuthorizer(configuration schema.AccessControlConfiguration) *Authorizer {
|
|
return &Authorizer{
|
|
configuration: configuration,
|
|
}
|
|
}
|
|
|
|
// Subject subject who to check access control for.
|
|
type Subject struct {
|
|
Username string
|
|
Groups []string
|
|
IP net.IP
|
|
}
|
|
|
|
func (s Subject) String() string {
|
|
return fmt.Sprintf("username=%s groups=%s ip=%s", s.Username, strings.Join(s.Groups, ","), s.IP.String())
|
|
}
|
|
|
|
// Object object to check access control for
|
|
type Object struct {
|
|
Domain string
|
|
Path string
|
|
}
|
|
|
|
// selectMatchingSubjectRules take a set of rules and select only the rules matching the subject constraints.
|
|
func selectMatchingSubjectRules(rules []schema.ACLRule, subject Subject) []schema.ACLRule {
|
|
selectedRules := []schema.ACLRule{}
|
|
|
|
for _, rule := range rules {
|
|
if isSubjectMatching(subject, rule.Subject) && isIPMatching(subject.IP, rule.Networks) {
|
|
selectedRules = append(selectedRules, rule)
|
|
}
|
|
}
|
|
|
|
return selectedRules
|
|
}
|
|
|
|
func selectMatchingObjectRules(rules []schema.ACLRule, object Object) []schema.ACLRule {
|
|
selectedRules := []schema.ACLRule{}
|
|
|
|
for _, rule := range rules {
|
|
if isDomainMatching(object.Domain, rule.Domain) &&
|
|
isPathMatching(object.Path, rule.Resources) {
|
|
selectedRules = append(selectedRules, rule)
|
|
}
|
|
}
|
|
return selectedRules
|
|
}
|
|
|
|
func selectMatchingRules(rules []schema.ACLRule, subject Subject, object Object) []schema.ACLRule {
|
|
matchingRules := selectMatchingSubjectRules(rules, subject)
|
|
return selectMatchingObjectRules(matchingRules, object)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// IsSecondFactorEnabled return true if at least one policy is set to second factor.
|
|
func (p *Authorizer) IsSecondFactorEnabled() bool {
|
|
if PolicyToLevel(p.configuration.DefaultPolicy) == TwoFactor {
|
|
return true
|
|
}
|
|
|
|
for _, r := range p.configuration.Rules {
|
|
if PolicyToLevel(r.Policy) == TwoFactor {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// GetRequiredLevel retrieve the required level of authorization to access the object.
|
|
func (p *Authorizer) GetRequiredLevel(subject Subject, requestURL url.URL) Level {
|
|
logging.Logger().Tracef("Check authorization of subject %s and url %s.",
|
|
subject.String(), requestURL.String())
|
|
|
|
matchingRules := selectMatchingRules(p.configuration.Rules, subject, Object{
|
|
Domain: requestURL.Hostname(),
|
|
Path: requestURL.Path,
|
|
})
|
|
|
|
if len(matchingRules) > 0 {
|
|
return PolicyToLevel(matchingRules[0].Policy)
|
|
}
|
|
logging.Logger().Tracef("No matching rule for subject %s and url %s... Applying default policy.",
|
|
subject.String(), requestURL.String())
|
|
|
|
return PolicyToLevel(p.configuration.DefaultPolicy)
|
|
}
|