switch to go vendoring
This commit is contained in:
+225
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2021 The LibreGraph Authors.
|
||||
*/
|
||||
|
||||
package ldif
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/armon/go-radix"
|
||||
"github.com/libregraph/idm/pkg/ldapserver"
|
||||
"github.com/spacewander/go-suffix-tree"
|
||||
)
|
||||
|
||||
var indexAttributes = map[string]string{
|
||||
"entryCSN": "eq",
|
||||
"entryUUID": "eq",
|
||||
"objectClass": "eq",
|
||||
"cn": "pres,eq,sub",
|
||||
"gidNumber": "eq",
|
||||
"mail": "pres,eq,sub",
|
||||
"memberUid": "eq",
|
||||
"ou": "eq",
|
||||
"uid": "eq",
|
||||
"uidNumber": "eq",
|
||||
"uniqueMember": "eq",
|
||||
|
||||
"sn": "pres,eq,sub",
|
||||
"givenName": "pres,eq,sub",
|
||||
|
||||
"mailAlternateAddress": "eq",
|
||||
|
||||
// Additional indexes for attributes usually used with AD.
|
||||
"objectGUID": "eq",
|
||||
"objectSID": "eq",
|
||||
"otherMailbox": "eq",
|
||||
"samAccountName": "eq",
|
||||
}
|
||||
|
||||
func AddIndexAttribute(name string, indices string) {
|
||||
indexAttributes[name] = indices
|
||||
}
|
||||
|
||||
func RemoveIndexAttribute(name string) {
|
||||
delete(indexAttributes, name)
|
||||
}
|
||||
|
||||
type Index interface {
|
||||
Add(name, op string, values []string, entry *ldifEntry) bool
|
||||
Load(name, op string, params ...string) ([]*ldifEntry, bool)
|
||||
}
|
||||
|
||||
type indexMap map[string][]*ldifEntry
|
||||
|
||||
func newIndexMap() indexMap {
|
||||
return make(indexMap)
|
||||
}
|
||||
|
||||
func (im indexMap) Add(name, op string, values []string, entry *ldifEntry) bool {
|
||||
for _, value := range values {
|
||||
value = strings.ToLower(value)
|
||||
im[value] = append(im[value], entry)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (im indexMap) Load(name, op string, value ...string) ([]*ldifEntry, bool) {
|
||||
entries := im[strings.ToLower(value[0])]
|
||||
return entries, true
|
||||
}
|
||||
|
||||
type indexSuffixTree struct {
|
||||
t *suffix.Tree
|
||||
}
|
||||
|
||||
func newIndexSuffixTree() *indexSuffixTree {
|
||||
return &indexSuffixTree{
|
||||
t: suffix.NewTree(),
|
||||
}
|
||||
}
|
||||
|
||||
func (ist indexSuffixTree) Add(name, op string, values []string, entry *ldifEntry) bool {
|
||||
for _, value := range values {
|
||||
sfx := []byte(value)
|
||||
var entries []*ldifEntry
|
||||
if v, ok := ist.t.Get(sfx); ok {
|
||||
entries = v.([]*ldifEntry)
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
ist.t.Insert(sfx, entries)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (ist indexSuffixTree) Load(name, op string, value ...string) ([]*ldifEntry, bool) {
|
||||
var entries []*ldifEntry
|
||||
sfx := []byte(value[0])
|
||||
ist.t.WalkSuffix(sfx, func(key []byte, value interface{}) bool {
|
||||
entries = append(entries, value.([]*ldifEntry)...)
|
||||
return false
|
||||
})
|
||||
return entries, true
|
||||
}
|
||||
|
||||
type indexRadixTree struct {
|
||||
t *radix.Tree
|
||||
}
|
||||
|
||||
func newIndexRadixTree() *indexRadixTree {
|
||||
return &indexRadixTree{
|
||||
t: radix.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func (irt *indexRadixTree) Add(name, op string, values []string, entry *ldifEntry) bool {
|
||||
for _, value := range values {
|
||||
pfx := value
|
||||
var entries []*ldifEntry
|
||||
if v, ok := irt.t.Get(pfx); ok {
|
||||
entries = v.([]*ldifEntry)
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
irt.t.Insert(pfx, entries)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (irt *indexRadixTree) Load(name, op string, value ...string) ([]*ldifEntry, bool) {
|
||||
var entries []*ldifEntry
|
||||
pfx := value[0]
|
||||
irt.t.WalkPrefix(pfx, func(key string, value interface{}) bool {
|
||||
entries = append(entries, value.([]*ldifEntry)...)
|
||||
return false
|
||||
})
|
||||
return entries, true
|
||||
}
|
||||
|
||||
type indexSubTree struct {
|
||||
pres indexMap
|
||||
irt *indexRadixTree
|
||||
ist *indexSuffixTree
|
||||
}
|
||||
|
||||
func newIndexSubTree() *indexSubTree {
|
||||
return &indexSubTree{
|
||||
pres: newIndexMap(),
|
||||
irt: newIndexRadixTree(),
|
||||
ist: newIndexSuffixTree(),
|
||||
}
|
||||
}
|
||||
|
||||
func (idx *indexSubTree) Add(name, op string, values []string, entry *ldifEntry) bool {
|
||||
ok0 := idx.pres.Add(name, op, []string{""}, entry)
|
||||
ok1 := idx.irt.Add(name, op, values, entry)
|
||||
ok2 := idx.ist.Add(name, op, values, entry)
|
||||
return ok0 || ok1 || ok2
|
||||
}
|
||||
|
||||
func (idx *indexSubTree) Load(name, op string, params ...string) ([]*ldifEntry, bool) {
|
||||
if len(params) != 2 {
|
||||
// Require one value and sub tag.
|
||||
return nil, false
|
||||
}
|
||||
tag, err := strconv.ParseInt(params[1], 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch tag {
|
||||
case ldapserver.FilterSubstringsAny:
|
||||
// TODO(longsleep): Find a suitable way for full text search substring
|
||||
// matching, for example with Knuth-Morris-Pratt algorithm. Currently
|
||||
// we just do a presence match.
|
||||
return idx.pres.Load(name, op, "")
|
||||
case ldapserver.FilterSubstringsInitial:
|
||||
return idx.irt.Load(name, op, params[0])
|
||||
case ldapserver.FilterSubstringsFinal:
|
||||
return idx.ist.Load(name, op, params[0])
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
type indexMapRegister map[string]Index
|
||||
|
||||
func newIndexMapRegister() indexMapRegister {
|
||||
imr := make(indexMapRegister)
|
||||
for name, ops := range indexAttributes {
|
||||
for _, op := range strings.Split(ops, ",") {
|
||||
switch op {
|
||||
case "sub":
|
||||
imr[imr.getKey(name, op)] = newIndexSubTree()
|
||||
case "pres":
|
||||
imr[imr.getKey(name, op)] = newIndexMap()
|
||||
case "eq":
|
||||
imr[imr.getKey(name, op)] = newIndexMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
return imr
|
||||
}
|
||||
|
||||
func (imr indexMapRegister) getKey(name, op string) string {
|
||||
return strings.ToLower(name) + "," + op
|
||||
}
|
||||
|
||||
func (imr indexMapRegister) Add(name, op string, values []string, entry *ldifEntry) bool {
|
||||
index, ok := imr[imr.getKey(name, op)]
|
||||
if !ok {
|
||||
// No matching index, refuse to add.
|
||||
return false
|
||||
}
|
||||
return index.Add(name, op, values, entry)
|
||||
}
|
||||
|
||||
func (imr indexMapRegister) Load(name, op string, params ...string) ([]*ldifEntry, bool) {
|
||||
index, ok := imr[imr.getKey(name, op)]
|
||||
if !ok {
|
||||
// No such index.
|
||||
return nil, false
|
||||
}
|
||||
return index.Load(name, op, params...)
|
||||
}
|
||||
Reference in New Issue
Block a user