authelia/internal/authorization/authorizer.go

103 lines
3.0 KiB
Go
Raw Normal View History

package authorization
import (
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/logging"
)
// Authorizer the component in charge of checking whether a user can access a given resource.
type Authorizer struct {
defaultPolicy Level
rules []*AccessControlRule
mfa bool
configuration *schema.Configuration
}
// NewAuthorizer create an instance of authorizer with a given access control configuration.
func NewAuthorizer(configuration *schema.Configuration) (authorizer *Authorizer) {
authorizer = &Authorizer{
defaultPolicy: StringToLevel(configuration.AccessControl.DefaultPolicy),
rules: NewAccessControlRules(configuration.AccessControl),
configuration: configuration,
}
if authorizer.defaultPolicy == TwoFactor {
authorizer.mfa = true
return authorizer
}
for _, rule := range authorizer.rules {
if rule.Policy == TwoFactor {
authorizer.mfa = true
return authorizer
}
}
if authorizer.configuration.IdentityProviders.OIDC != nil {
for _, client := range authorizer.configuration.IdentityProviders.OIDC.Clients {
if client.Policy == twoFactor {
authorizer.mfa = true
return authorizer
}
}
}
return authorizer
}
// IsSecondFactorEnabled return true if at least one policy is set to second factor.
func (p Authorizer) IsSecondFactorEnabled() bool {
return p.mfa
}
// GetRequiredLevel retrieve the required level of authorization to access the object.
func (p Authorizer) GetRequiredLevel(subject Subject, object Object) (bool, Level) {
logger := logging.Logger()
logger.Debugf("Check authorization of subject %s and object %s (method %s).",
subject.String(), object.String(), object.Method)
for _, rule := range p.rules {
if rule.IsMatch(subject, object) {
logger.Tracef(traceFmtACLHitMiss, "HIT", rule.Position, subject.String(), object.String(), object.Method)
return len(rule.Subjects) > 0, rule.Policy
}
logger.Tracef(traceFmtACLHitMiss, "MISS", rule.Position, subject.String(), object.String(), object.Method)
}
logger.Debugf("No matching rule for subject %s and url %s... Applying default policy.",
subject.String(), object.String())
return false, p.defaultPolicy
}
// GetRuleMatchResults iterates through the rules and produces a list of RuleMatchResult provided a subject and object.
func (p Authorizer) GetRuleMatchResults(subject Subject, object Object) (results []RuleMatchResult) {
skipped := false
results = make([]RuleMatchResult, len(p.rules))
for i, rule := range p.rules {
results[i] = RuleMatchResult{
Rule: rule,
Skipped: skipped,
MatchDomain: isMatchForDomains(subject, object, rule),
MatchResources: isMatchForResources(subject, object, rule),
MatchMethods: isMatchForMethods(object, rule),
MatchNetworks: isMatchForNetworks(subject, rule),
MatchSubjects: isMatchForSubjects(subject, rule),
MatchSubjectsExact: isExactMatchForSubjects(subject, rule),
}
skipped = skipped || results[i].IsMatch()
}
return results
}