test(authorization): add missing tests (#5478)
Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>pull/5479/head
parent
b1109203ab
commit
e784a72735
|
@ -66,13 +66,13 @@ func (m AccessControlDomainMatcher) IsMatch(domain string, subject Subject) (mat
|
||||||
return strings.HasSuffix(domain, m.Name)
|
return strings.HasSuffix(domain, m.Name)
|
||||||
case m.UserWildcard:
|
case m.UserWildcard:
|
||||||
if subject.IsAnonymous() && strings.HasSuffix(domain, m.Name) {
|
if subject.IsAnonymous() && strings.HasSuffix(domain, m.Name) {
|
||||||
return true
|
return len(domain) > len(m.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return domain == fmt.Sprintf("%s%s", subject.Username, m.Name)
|
return domain == fmt.Sprintf("%s%s", subject.Username, m.Name)
|
||||||
case m.GroupWildcard:
|
case m.GroupWildcard:
|
||||||
if subject.IsAnonymous() && strings.HasSuffix(domain, m.Name) {
|
if subject.IsAnonymous() && strings.HasSuffix(domain, m.Name) {
|
||||||
return true
|
return len(domain) > len(m.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
i := strings.Index(domain, ".")
|
i := strings.Index(domain, ".")
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package authorization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccessControlDomain_IsMatch(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
have *AccessControlDomainMatcher
|
||||||
|
domain string
|
||||||
|
subject Subject
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"ShouldMatchDomainSuffixUserWildcard",
|
||||||
|
&AccessControlDomainMatcher{
|
||||||
|
Name: "-user.domain.com",
|
||||||
|
UserWildcard: true,
|
||||||
|
},
|
||||||
|
"a-user.domain.com",
|
||||||
|
Subject{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ShouldMatchDomainSuffixGroupWildcard",
|
||||||
|
&AccessControlDomainMatcher{
|
||||||
|
Name: "-group.domain.com",
|
||||||
|
GroupWildcard: true,
|
||||||
|
},
|
||||||
|
"a-group.domain.com",
|
||||||
|
Subject{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ShouldNotMatchExactDomainWithUserWildcard",
|
||||||
|
&AccessControlDomainMatcher{
|
||||||
|
Name: "-user.domain.com",
|
||||||
|
UserWildcard: true,
|
||||||
|
},
|
||||||
|
"-user.domain.com",
|
||||||
|
Subject{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ShouldMatchWildcard",
|
||||||
|
&AccessControlDomainMatcher{
|
||||||
|
Name: "user.domain.com",
|
||||||
|
Wildcard: true,
|
||||||
|
},
|
||||||
|
"abc.user.domain.com",
|
||||||
|
Subject{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tc.expected, tc.have.IsMatch(tc.domain, tc.subject))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package authorization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewAccessControlQuery(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
have [][]schema.ACLQueryRule
|
||||||
|
expected []AccessControlQuery
|
||||||
|
matches [][]Object
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"ShouldSkipInvalidTypeEqual",
|
||||||
|
[][]schema.ACLQueryRule{
|
||||||
|
{
|
||||||
|
{Operator: operatorEqual, Key: "example", Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]AccessControlQuery{{Rules: []ObjectMatcher(nil)}},
|
||||||
|
[][]Object{{{}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ShouldSkipInvalidTypePattern",
|
||||||
|
[][]schema.ACLQueryRule{
|
||||||
|
{
|
||||||
|
{Operator: operatorPattern, Key: "example", Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]AccessControlQuery{{Rules: []ObjectMatcher(nil)}},
|
||||||
|
[][]Object{{{}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ShouldSkipInvalidOperator",
|
||||||
|
[][]schema.ACLQueryRule{
|
||||||
|
{
|
||||||
|
{Operator: "nop", Key: "example", Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]AccessControlQuery{{Rules: []ObjectMatcher(nil)}},
|
||||||
|
[][]Object{{{}}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
actual := NewAccessControlQuery(tc.have)
|
||||||
|
assert.Equal(t, tc.expected, actual)
|
||||||
|
|
||||||
|
for i, rule := range actual {
|
||||||
|
for _, object := range tc.matches[i] {
|
||||||
|
assert.True(t, rule.IsMatch(object))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package authorization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccessControlRule_MatchesSubjectExact(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
have *AccessControlRule
|
||||||
|
subject Subject
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"ShouldNotMatchAnonymous",
|
||||||
|
&AccessControlRule{
|
||||||
|
Subjects: []AccessControlSubjects{
|
||||||
|
{[]SubjectMatcher{schemaSubjectToACLSubject("user:john")}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Subject{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tc.expected, tc.have.MatchesSubjectExact(tc.subject))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,8 @@ type RegexpGroupStringSubjectMatcher struct {
|
||||||
|
|
||||||
// IsMatch returns true if the underlying pattern matches the input given the subject.
|
// IsMatch returns true if the underlying pattern matches the input given the subject.
|
||||||
func (r RegexpGroupStringSubjectMatcher) IsMatch(input string, subject Subject) (match bool) {
|
func (r RegexpGroupStringSubjectMatcher) IsMatch(input string, subject Subject) (match bool) {
|
||||||
if !r.Pattern.MatchString(input) {
|
matches := r.Pattern.FindStringSubmatch(input)
|
||||||
|
if matches == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,16 +25,11 @@ func (r RegexpGroupStringSubjectMatcher) IsMatch(input string, subject Subject)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
matches := r.Pattern.FindAllStringSubmatch(input, -1)
|
if r.SubexpNameUser != -1 && !strings.EqualFold(subject.Username, matches[r.SubexpNameUser]) {
|
||||||
if matches == nil {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.SubexpNameUser != -1 && !strings.EqualFold(subject.Username, matches[0][r.SubexpNameUser]) {
|
if r.SubexpNameGroup != -1 && !utils.IsStringInSliceFold(matches[r.SubexpNameGroup], subject.Groups) {
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.SubexpNameGroup != -1 && !utils.IsStringInSliceFold(matches[0][r.SubexpNameGroup], subject.Groups) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package authorization
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegexpGroupStringSubjectMatcher_IsMatch(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
have *RegexpGroupStringSubjectMatcher
|
||||||
|
input string
|
||||||
|
subject Subject
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"Abc",
|
||||||
|
&RegexpGroupStringSubjectMatcher{
|
||||||
|
MustCompileRegexNoPtr(`^(?P<User>[a-zA-Z0-9]+)\.regex.com$`),
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
"example.com",
|
||||||
|
Subject{Username: "a-user"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tc.expected, tc.have.IsMatch(tc.input, tc.subject))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustCompileRegexNoPtr(input string) regexp.Regexp {
|
||||||
|
out := regexp.MustCompile(input)
|
||||||
|
|
||||||
|
return *out
|
||||||
|
}
|
|
@ -85,3 +85,33 @@ func TestShouldCleanURL(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRuleMatchResult_IsPotentialMatch(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
have RuleMatchResult
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"ShouldNotMatch",
|
||||||
|
RuleMatchResult{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ShouldMatch",
|
||||||
|
RuleMatchResult{nil, true, true, true, true, true, true, true, false},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ShouldMatchExact",
|
||||||
|
RuleMatchResult{nil, true, true, true, true, true, true, true, true},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tc.expected, tc.have.IsPotentialMatch())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package authorization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -217,3 +218,76 @@ func TestIsAuthLevelSufficient(t *testing.T) {
|
||||||
assert.False(t, IsAuthLevelSufficient(authentication.OneFactor, TwoFactor))
|
assert.False(t, IsAuthLevelSufficient(authentication.OneFactor, TwoFactor))
|
||||||
assert.True(t, IsAuthLevelSufficient(authentication.TwoFactor, TwoFactor))
|
assert.True(t, IsAuthLevelSufficient(authentication.TwoFactor, TwoFactor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStringSliceToRegexpSlice(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
have []string
|
||||||
|
expected []regexp.Regexp
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"ShouldNotParseBadRegex",
|
||||||
|
[]string{`\q`},
|
||||||
|
[]regexp.Regexp(nil),
|
||||||
|
"error parsing regexp: invalid escape sequence: `\\q`",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
actual, theError := stringSliceToRegexpSlice(tc.have)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.expected, actual)
|
||||||
|
|
||||||
|
if tc.err == "" {
|
||||||
|
assert.NoError(t, theError)
|
||||||
|
} else {
|
||||||
|
assert.EqualError(t, theError, tc.err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSchemaNetworksToACL(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
have []string
|
||||||
|
globals map[string][]*net.IPNet
|
||||||
|
cache map[string]*net.IPNet
|
||||||
|
expected []*net.IPNet
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"ShouldLoadFromCache",
|
||||||
|
[]string{"192.168.0.0/24"},
|
||||||
|
nil,
|
||||||
|
map[string]*net.IPNet{"192.168.0.0/24": MustParseCIDR("192.168.0.0/24")},
|
||||||
|
[]*net.IPNet{MustParseCIDR("192.168.0.0/24")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
if tc.globals == nil {
|
||||||
|
tc.globals = map[string][]*net.IPNet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.cache == nil {
|
||||||
|
tc.cache = map[string]*net.IPNet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := schemaNetworksToACL(tc.have, tc.globals, tc.cache)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.expected, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustParseCIDR(input string) *net.IPNet {
|
||||||
|
_, out, err := net.ParseCIDR(input)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue