2021-03-05 11:18:31 +07:00
|
|
|
package authorization
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-04-01 18:38:49 +07:00
|
|
|
"regexp"
|
2021-03-05 11:18:31 +07:00
|
|
|
"strings"
|
|
|
|
|
2021-08-11 08:04:35 +07:00
|
|
|
"github.com/authelia/authelia/v4/internal/utils"
|
2021-03-05 11:18:31 +07:00
|
|
|
)
|
|
|
|
|
2022-04-01 18:38:49 +07:00
|
|
|
// NewAccessControlDomain creates a new SubjectObjectMatcher that matches the domain as a basic string.
|
|
|
|
func NewAccessControlDomain(domain string) SubjectObjectMatcher {
|
|
|
|
d := AccessControlDomain{}
|
|
|
|
|
|
|
|
domain = strings.ToLower(domain)
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case strings.HasPrefix(domain, "*."):
|
|
|
|
d.Wildcard = true
|
|
|
|
d.Name = domain[1:]
|
|
|
|
case strings.HasPrefix(domain, "{user}"):
|
|
|
|
d.UserWildcard = true
|
|
|
|
d.Name = domain[7:]
|
|
|
|
case strings.HasPrefix(domain, "{group}"):
|
|
|
|
d.GroupWildcard = true
|
|
|
|
d.Name = domain[8:]
|
|
|
|
default:
|
|
|
|
d.Name = domain
|
|
|
|
}
|
|
|
|
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
2021-03-05 11:18:31 +07:00
|
|
|
// AccessControlDomain represents an ACL domain.
|
|
|
|
type AccessControlDomain struct {
|
|
|
|
Name string
|
|
|
|
Wildcard bool
|
|
|
|
UserWildcard bool
|
|
|
|
GroupWildcard bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsMatch returns true if the ACL domain matches the object domain.
|
2022-04-01 18:38:49 +07:00
|
|
|
func (acl AccessControlDomain) IsMatch(subject Subject, object Object) (match bool) {
|
2021-03-05 11:18:31 +07:00
|
|
|
switch {
|
2022-04-01 18:38:49 +07:00
|
|
|
case acl.Wildcard:
|
|
|
|
return strings.HasSuffix(object.Domain, acl.Name)
|
|
|
|
case acl.UserWildcard:
|
|
|
|
return object.Domain == fmt.Sprintf("%s.%s", subject.Username, acl.Name)
|
|
|
|
case acl.GroupWildcard:
|
2021-03-05 11:18:31 +07:00
|
|
|
prefix, suffix := domainToPrefixSuffix(object.Domain)
|
|
|
|
|
2022-04-01 18:38:49 +07:00
|
|
|
return suffix == acl.Name && utils.IsStringInSliceFold(prefix, subject.Groups)
|
2021-03-05 11:18:31 +07:00
|
|
|
default:
|
2022-04-01 18:38:49 +07:00
|
|
|
return object.Domain == acl.Name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns a string representation of the SubjectObjectMatcher rule.
|
|
|
|
func (acl AccessControlDomain) String() string {
|
|
|
|
return fmt.Sprintf("domain:%s", acl.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewAccessControlDomainRegex creates a new SubjectObjectMatcher that matches the domain either in a basic way or
|
|
|
|
// dynamic User/Group subexpression group way.
|
|
|
|
func NewAccessControlDomainRegex(pattern regexp.Regexp) SubjectObjectMatcher {
|
|
|
|
var iuser, igroup = -1, -1
|
|
|
|
|
|
|
|
for i, group := range pattern.SubexpNames() {
|
|
|
|
switch group {
|
|
|
|
case subexpNameUser:
|
|
|
|
iuser = i
|
|
|
|
case subexpNameGroup:
|
|
|
|
igroup = i
|
|
|
|
}
|
2021-03-05 11:18:31 +07:00
|
|
|
}
|
2022-04-01 18:38:49 +07:00
|
|
|
|
|
|
|
if iuser != -1 || igroup != -1 {
|
|
|
|
return AccessControlDomainRegex{Pattern: pattern, SubexpNameUser: iuser, SubexpNameGroup: igroup}
|
|
|
|
}
|
|
|
|
|
|
|
|
return AccessControlDomainRegexBasic{Pattern: pattern}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AccessControlDomainRegexBasic represents a basic domain regex SubjectObjectMatcher.
|
|
|
|
type AccessControlDomainRegexBasic struct {
|
|
|
|
Pattern regexp.Regexp
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsMatch returns true if the ACL regex matches the object domain.
|
|
|
|
func (acl AccessControlDomainRegexBasic) IsMatch(_ Subject, object Object) (match bool) {
|
|
|
|
return acl.Pattern.MatchString(object.Domain)
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns a text representation of a AccessControlDomainRegexBasic.
|
|
|
|
func (acl AccessControlDomainRegexBasic) String() string {
|
|
|
|
return fmt.Sprintf("domain_regex:%s", acl.Pattern.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
// AccessControlDomainRegex represents an ACL domain regex.
|
|
|
|
type AccessControlDomainRegex struct {
|
|
|
|
Pattern regexp.Regexp
|
|
|
|
SubexpNameUser int
|
|
|
|
SubexpNameGroup int
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsMatch returns true if the ACL regex matches the object domain.
|
|
|
|
func (acl AccessControlDomainRegex) IsMatch(subject Subject, object Object) (match bool) {
|
|
|
|
matches := acl.Pattern.FindAllStringSubmatch(object.Domain, -1)
|
|
|
|
if matches == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if acl.SubexpNameUser != -1 && !strings.EqualFold(subject.Username, matches[0][acl.SubexpNameUser]) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if acl.SubexpNameGroup != -1 && !utils.IsStringInSliceFold(matches[0][acl.SubexpNameGroup], subject.Groups) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns a text representation of a AccessControlDomainRegex.
|
|
|
|
func (acl AccessControlDomainRegex) String() string {
|
|
|
|
return fmt.Sprintf("domain_regex(subexp):%s", acl.Pattern.String())
|
2021-03-05 11:18:31 +07:00
|
|
|
}
|