fix(authorization): subject wildcard domain rule not matching (#4187)
This fixes an issue where the subject wildcard domain rules (those containing {user} and {group}) are not considered matches even though they may be once a user authenticates. Fixes #4186pull/4167/head^2
parent
bcdbedee11
commit
a4edf21320
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewAccessControlDomain creates a new SubjectObjectMatcher that matches the domain as a basic string.
|
// NewAccessControlDomain creates a new SubjectObjectMatcher that matches the domain as a basic string.
|
||||||
func NewAccessControlDomain(domain string) AccessControlDomain {
|
func NewAccessControlDomain(domain string) (subjcets bool, rule AccessControlDomain) {
|
||||||
m := &AccessControlDomainMatcher{}
|
m := &AccessControlDomainMatcher{}
|
||||||
domain = strings.ToLower(domain)
|
domain = strings.ToLower(domain)
|
||||||
|
|
||||||
|
@ -19,15 +19,15 @@ func NewAccessControlDomain(domain string) AccessControlDomain {
|
||||||
m.Name = domain[1:]
|
m.Name = domain[1:]
|
||||||
case strings.HasPrefix(domain, "{user}"):
|
case strings.HasPrefix(domain, "{user}"):
|
||||||
m.UserWildcard = true
|
m.UserWildcard = true
|
||||||
m.Name = domain[7:]
|
m.Name = domain[6:]
|
||||||
case strings.HasPrefix(domain, "{group}"):
|
case strings.HasPrefix(domain, "{group}"):
|
||||||
m.GroupWildcard = true
|
m.GroupWildcard = true
|
||||||
m.Name = domain[8:]
|
m.Name = domain[7:]
|
||||||
default:
|
default:
|
||||||
m.Name = domain
|
m.Name = domain
|
||||||
}
|
}
|
||||||
|
|
||||||
return AccessControlDomain{m}
|
return m.UserWildcard || m.GroupWildcard, AccessControlDomain{m}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAccessControlDomainRegex creates a new SubjectObjectMatcher that matches the domain either in a basic way or
|
// NewAccessControlDomainRegex creates a new SubjectObjectMatcher that matches the domain either in a basic way or
|
||||||
|
@ -65,11 +65,19 @@ func (m AccessControlDomainMatcher) IsMatch(domain string, subject Subject) (mat
|
||||||
case m.Wildcard:
|
case m.Wildcard:
|
||||||
return strings.HasSuffix(domain, m.Name)
|
return strings.HasSuffix(domain, m.Name)
|
||||||
case m.UserWildcard:
|
case m.UserWildcard:
|
||||||
return domain == fmt.Sprintf("%s.%s", subject.Username, m.Name)
|
if subject.IsAnonymous() && strings.HasSuffix(domain, m.Name) {
|
||||||
case m.GroupWildcard:
|
return true
|
||||||
prefix, suffix := domainToPrefixSuffix(domain)
|
}
|
||||||
|
|
||||||
return suffix == m.Name && utils.IsStringInSliceFold(prefix, subject.Groups)
|
return domain == fmt.Sprintf("%s%s", subject.Username, m.Name)
|
||||||
|
case m.GroupWildcard:
|
||||||
|
if subject.IsAnonymous() && strings.HasSuffix(domain, m.Name) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
i := strings.Index(domain, ".")
|
||||||
|
|
||||||
|
return domain[i:] == m.Name && utils.IsStringInSliceFold(domain[:i], subject.Groups)
|
||||||
default:
|
default:
|
||||||
return strings.EqualFold(domain, m.Name)
|
return strings.EqualFold(domain, m.Name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ func NewAccessControlRules(config schema.AccessControlConfiguration) (rules []*A
|
||||||
func NewAccessControlRule(pos int, rule schema.ACLRule, networksMap map[string][]*net.IPNet, networksCacheMap map[string]*net.IPNet) *AccessControlRule {
|
func NewAccessControlRule(pos int, rule schema.ACLRule, networksMap map[string][]*net.IPNet, networksCacheMap map[string]*net.IPNet) *AccessControlRule {
|
||||||
r := &AccessControlRule{
|
r := &AccessControlRule{
|
||||||
Position: pos,
|
Position: pos,
|
||||||
Domains: schemaDomainsToACL(rule.Domains),
|
|
||||||
Methods: schemaMethodsToACL(rule.Methods),
|
Methods: schemaMethodsToACL(rule.Methods),
|
||||||
Networks: schemaNetworksToACL(rule.Networks, networksMap, networksCacheMap),
|
Networks: schemaNetworksToACL(rule.Networks, networksMap, networksCacheMap),
|
||||||
Subjects: schemaSubjectsToACL(rule.Subjects),
|
Subjects: schemaSubjectsToACL(rule.Subjects),
|
||||||
|
@ -33,6 +32,7 @@ func NewAccessControlRule(pos int, rule schema.ACLRule, networksMap map[string][
|
||||||
r.HasSubjects = true
|
r.HasSubjects = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ruleAddDomain(rule.Domains, r)
|
||||||
ruleAddDomainRegex(rule.DomainsRegex, r)
|
ruleAddDomainRegex(rule.DomainsRegex, r)
|
||||||
ruleAddResources(rule.Resources, r)
|
ruleAddResources(rule.Resources, r)
|
||||||
|
|
||||||
|
|
|
@ -151,17 +151,17 @@ func (s *AuthorizerSuite) TestShouldCheckDynamicDomainRules() {
|
||||||
WithDefaultPolicy(deny).
|
WithDefaultPolicy(deny).
|
||||||
WithRule(schema.ACLRule{
|
WithRule(schema.ACLRule{
|
||||||
Domains: []string{"{user}.example.com"},
|
Domains: []string{"{user}.example.com"},
|
||||||
Policy: bypass,
|
Policy: oneFactor,
|
||||||
}).
|
}).
|
||||||
WithRule(schema.ACLRule{
|
WithRule(schema.ACLRule{
|
||||||
Domains: []string{"{group}.example.com"},
|
Domains: []string{"{group}.example.com"},
|
||||||
Policy: bypass,
|
Policy: oneFactor,
|
||||||
}).
|
}).
|
||||||
Build()
|
Build()
|
||||||
|
|
||||||
tester.CheckAuthorizations(s.T(), UserWithGroups, "https://john.example.com/", "GET", Bypass)
|
tester.CheckAuthorizations(s.T(), UserWithGroups, "https://john.example.com/", "GET", OneFactor)
|
||||||
tester.CheckAuthorizations(s.T(), UserWithGroups, "https://dev.example.com/", "GET", Bypass)
|
tester.CheckAuthorizations(s.T(), UserWithGroups, "https://dev.example.com/", "GET", OneFactor)
|
||||||
tester.CheckAuthorizations(s.T(), UserWithGroups, "https://admins.example.com/", "GET", Bypass)
|
tester.CheckAuthorizations(s.T(), UserWithGroups, "https://admins.example.com/", "GET", OneFactor)
|
||||||
tester.CheckAuthorizations(s.T(), UserWithGroups, "https://othergroup.example.com/", "GET", Denied)
|
tester.CheckAuthorizations(s.T(), UserWithGroups, "https://othergroup.example.com/", "GET", Denied)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,12 +70,16 @@ func schemaSubjectToACLSubject(subjectRule string) (subject SubjectMatcher) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func schemaDomainsToACL(domainRules []string) (domains []AccessControlDomain) {
|
func ruleAddDomain(domainRules []string, rule *AccessControlRule) {
|
||||||
for _, domainRule := range domainRules {
|
for _, domainRule := range domainRules {
|
||||||
domains = append(domains, NewAccessControlDomain(domainRule))
|
subjects, r := NewAccessControlDomain(domainRule)
|
||||||
}
|
|
||||||
|
|
||||||
return domains
|
rule.Domains = append(rule.Domains, r)
|
||||||
|
|
||||||
|
if !rule.HasSubjects && subjects {
|
||||||
|
rule.HasSubjects = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ruleAddDomainRegex(exps []regexp.Regexp, rule *AccessControlRule) {
|
func ruleAddDomainRegex(exps []regexp.Regexp, rule *AccessControlRule) {
|
||||||
|
|
Loading…
Reference in New Issue