Skip to content

Commit acdecd3

Browse files
committed
initital
0 parents  commit acdecd3

File tree

9 files changed

+558
-0
lines changed

9 files changed

+558
-0
lines changed

.github/workflows/test.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test_unit:
9+
name: Unit tests
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v3
13+
- run: go test -v

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vscode

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# LDAP filter
2+
3+
A work-in-progress [RFC4515](https://datatracker.ietf.org/doc/html/rfc4515) ldap filter parser
4+
5+
Only a few filters are implemented at the moment (And, Or, Equality)
6+
7+
## Usage
8+
9+
```go
10+
import "github.com/janstuemmel/go-ldap-filter"
11+
12+
filter, err := ldapfilter.NewParser("|(name=Jon)(name=Foo)").Parse()
13+
14+
if err != nil {
15+
panic(err)
16+
}
17+
18+
ok := filter.Match(map[string][]string{
19+
"name": {"Jon"}
20+
})
21+
22+
fmt.Println(ok)
23+
```

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/janstuemmel/go-ldap-filter
2+
3+
go 1.18

go.sum

Whitespace-only changes.

ladapfilter_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package ldapfilter
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestFilterAnd(t *testing.T) {
9+
input := Input{
10+
"foo": {"bar", "baz"},
11+
}
12+
filter := AndFilter{}
13+
filter.Append(&AndFilter{})
14+
res := filter.Match(input)
15+
assert(t, true, res)
16+
}
17+
18+
func TestFilterOr(t *testing.T) {
19+
input := Input{
20+
"foo": {"bar", "baz"},
21+
}
22+
filter := &OrFilter{
23+
Children: []Filter{
24+
&AndFilter{},
25+
&AndFilter{},
26+
},
27+
}
28+
res := filter.Match(input)
29+
assert(t, true, res)
30+
}
31+
32+
func TestFilterEquality(t *testing.T) {
33+
filter := EqualityFilter{
34+
Key: "foo",
35+
Value: "baz",
36+
}
37+
38+
t.Run("should match", func(t *testing.T) {
39+
input := Input{
40+
"foo": {"bar", "baz"},
41+
}
42+
res := filter.Match(input)
43+
assert(t, true, res)
44+
})
45+
46+
t.Run("should not match", func(t *testing.T) {
47+
input := Input{
48+
"foo": {"bar"},
49+
}
50+
res := filter.Match(input)
51+
assert(t, false, res)
52+
})
53+
}
54+
55+
func TestFilter(t *testing.T) {
56+
57+
testData := []struct {
58+
expr string
59+
ok bool
60+
inp Input
61+
}{
62+
{
63+
expr: "(name=Jon)",
64+
inp: Input{"name": {"Jon"}},
65+
ok: true,
66+
},
67+
{
68+
expr: "|(name=Jon)(name=Foo)",
69+
inp: Input{"name": {"Jon"}},
70+
ok: true,
71+
},
72+
{
73+
expr: "|(name=Jon)(alt=Foo)",
74+
inp: Input{"alt": {"Foo"}},
75+
ok: true,
76+
},
77+
}
78+
79+
for _, test := range testData {
80+
t.Run("", func(t *testing.T) {
81+
filter, err := NewParser(test.expr).Parse()
82+
assert(t, nil, err)
83+
assert(t, test.ok, filter.Match(test.inp))
84+
})
85+
}
86+
}
87+
88+
// helper
89+
90+
func assert(t *testing.T, want interface{}, have interface{}) {
91+
t.Helper()
92+
if !reflect.DeepEqual(want, have) {
93+
t.Errorf("Assertion failed for %s\n\twant:\t%+v\n\thave:\t%+v", t.Name(), want, have)
94+
}
95+
}

ldapfilter.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package ldapfilter
2+
3+
type Input = map[string][]interface{}
4+
5+
type Filter interface {
6+
Match(input Input) bool
7+
Append(filter Filter)
8+
}
9+
10+
// AND
11+
12+
type AndFilter struct {
13+
Type string
14+
Children []Filter
15+
}
16+
17+
func NewAndFilter() *AndFilter {
18+
return &AndFilter{Type: "and"}
19+
}
20+
21+
func (f *AndFilter) Match(input Input) bool {
22+
for _, filter := range f.Children {
23+
if !filter.Match(input) {
24+
return false
25+
}
26+
}
27+
return true
28+
}
29+
30+
func (f *AndFilter) Append(filter Filter) {
31+
f.Children = append(f.Children, filter)
32+
}
33+
34+
// OR
35+
36+
type OrFilter struct {
37+
Type string
38+
Children []Filter
39+
}
40+
41+
func NewOrFilter() *OrFilter {
42+
return &OrFilter{Type: "or"}
43+
}
44+
45+
func (f *OrFilter) Match(input Input) bool {
46+
if len(f.Children) == 0 {
47+
return true
48+
}
49+
for _, filter := range f.Children {
50+
if filter.Match(input) {
51+
return true
52+
}
53+
}
54+
return false
55+
}
56+
57+
func (f *OrFilter) Append(filter Filter) {
58+
f.Children = append(f.Children, filter)
59+
}
60+
61+
// EQUALITY
62+
63+
type EqualityFilter struct {
64+
Type string
65+
Key string
66+
Value string
67+
}
68+
69+
func NewEqualityFilter() *EqualityFilter {
70+
return &EqualityFilter{Type: "equality"}
71+
}
72+
73+
func (f *EqualityFilter) Match(input Input) bool {
74+
if values, ok := input[f.Key]; ok {
75+
for _, value := range values {
76+
if value == f.Value {
77+
return true
78+
}
79+
}
80+
}
81+
return false
82+
}
83+
84+
func (f *EqualityFilter) Append(filter Filter) {}

0 commit comments

Comments
 (0)