This commit is contained in:
Alex 2020-01-26 21:03:18 +01:00
parent 0bd2aeef06
commit 8e4537d2ef
5 changed files with 21 additions and 11 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
gobottin gobottin
config.json

View file

@ -71,7 +71,7 @@ A rule is a string composed of five fields separated by `:`. The fields are the
1. The name of the user that must be bound (logged in) for the rule to apply. May contain wildcards such as `*` (see the format used by Go's `path.Match`). The special name `ANONYMOUS` applies to clients before they bind to an LDAP entity. 1. The name of the user that must be bound (logged in) for the rule to apply. May contain wildcards such as `*` (see the format used by Go's `path.Match`). The special name `ANONYMOUS` applies to clients before they bind to an LDAP entity.
2. The groups that the user must be a part of, separated by spaces. Wildcards may also be used. If several groups (or wildcard group patterns) are specified, for each pattern the user must be part of a group that matches it. 2. The groups that the user must be a part of, separated by spaces. Wildcards may also be used. If several groups (or wildcard group patterns) are specified, for each pattern the user must be part of a group that matches it.
3. The action, a subset of `read`, `add`, `delete`, `modify` separated by spaces. 3. The action, a subset of `bind`, `read`, `add`, `delete`, `modify` separated by spaces.
4. The target entity of the action as a pattern that may contain wildcards. The special word `SELF` is replaced by the entity name of the bound user before trying to match. 4. The target entity of the action as a pattern that may contain wildcards. The special word `SELF` is replaced by the entity name of the bound user before trying to match.
5. The allowed attributes for a read, add or modify operation. This is specified as a list of patterns to include and exclude attributes, separated by spaces. A pattern that starts by `!` is an exclude pattern, otherwise it is an include pattern. To read/write an attribute, it has to match at least one include pattern and not match any exclude pattern. Delete operations do not check for any attribute, thus as soon as `delete` is included in the allowed actions, the right to delete entities is granted. 5. The allowed attributes for a read, add or modify operation. This is specified as a list of patterns to include and exclude attributes, separated by spaces. A pattern that starts by `!` is an exclude pattern, otherwise it is an include pattern. To read/write an attribute, it has to match at least one include pattern and not match any exclude pattern. Delete operations do not check for any attribute, thus as soon as `delete` is included in the allowed actions, the right to delete entities is granted.

15
main.go
View file

@ -1,6 +1,7 @@
package main package main
// @FIXME: Panics if invalid keys are in consul (consulToDN in util.go) // @FIXME: Auto populate entryuuid creatorsname createtimestamp modifiersname modifytimestamp (uuid: github.com/google/uuid, timestamps: 20060102150405Z)
// @FIXME: Use memberof and not memberOf
// @FIXME: Implement missing search filters (in applyFilter) // @FIXME: Implement missing search filters (in applyFilter)
// @FIXME: Add an initial prefix to the consul key value // @FIXME: Add an initial prefix to the consul key value
@ -112,6 +113,8 @@ func readConfig() Config {
} }
func main() { func main() {
flag.Parse()
ldap.Logger = log.New(os.Stdout, "[ldapserver] ", log.LstdFlags) ldap.Logger = log.New(os.Stdout, "[ldapserver] ", log.LstdFlags)
config := readConfig() config := readConfig()
@ -739,7 +742,10 @@ func (server *Server) handleDeleteInternal(state *State, r *message.DelRequest)
return ldap.LDAPResultNoSuchObject, fmt.Errorf("Not found: %s", dn) return ldap.LDAPResultNoSuchObject, fmt.Errorf("Not found: %s", dn)
} }
for _, item := range items { for _, item := range items {
itemDN, _ := consulToDN(item.Key) itemDN, _, err := consulToDN(item.Key)
if err != nil {
continue
}
if itemDN != dn { if itemDN != dn {
return ldap.LDAPResultNotAllowedOnNonLeaf, fmt.Errorf( return ldap.LDAPResultNotAllowedOnNonLeaf, fmt.Errorf(
"Cannot delete %d as it has children", dn) "Cannot delete %d as it has children", dn)
@ -833,7 +839,10 @@ func (server *Server) handleModifyInternal(state *State, r *message.ModifyReques
prevEntry := Entry{} prevEntry := Entry{}
for _, item := range items { for _, item := range items {
itemDN, attr := consulToDN(item.Key) itemDN, attr, err := consulToDN(item.Key)
if err != nil {
continue
}
if itemDN != dn { if itemDN != dn {
panic("itemDN != dn in handleModifyInternal") panic("itemDN != dn in handleModifyInternal")
} }

14
util.go
View file

@ -3,7 +3,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"strings" "strings"
consul "github.com/hashicorp/consul/api" consul "github.com/hashicorp/consul/api"
@ -24,7 +23,7 @@ func dnToConsul(dn string) (string, error) {
return strings.Join(rdns, "/"), nil return strings.Join(rdns, "/"), nil
} }
func consulToDN(key string) (string, string) { func consulToDN(key string) (string, string, error) {
path := strings.Split(key, "/") path := strings.Split(key, "/")
dn := "" dn := ""
for _, cpath := range path { for _, cpath := range path {
@ -33,16 +32,14 @@ func consulToDN(key string) (string, string) {
} }
kv := strings.Split(cpath, "=") kv := strings.Split(cpath, "=")
if len(kv) == 2 && kv[0] == "attribute" { if len(kv) == 2 && kv[0] == "attribute" {
return dn, kv[1] return dn, kv[1], nil
} }
if dn != "" { if dn != "" {
dn = "," + dn dn = "," + dn
} }
dn = cpath + dn dn = cpath + dn
} }
// TODO don't panic, handle this return "", "", fmt.Errorf("Consul key %s does not end with attribute=something", key)
log.Panicf("Consul key %s does not end with attribute=something", key)
panic("unreachable")
} }
func parseValue(value []byte) ([]string, error) { func parseValue(value []byte) ([]string, error) {
@ -65,7 +62,10 @@ func parseConsulResult(data []*consul.KVPair) (map[string]Entry, error) {
aggregator := map[string]Entry{} aggregator := map[string]Entry{}
for _, kv := range data { for _, kv := range data {
dn, attr := consulToDN(kv.Key) dn, attr, err := consulToDN(kv.Key)
if err != nil {
continue
}
if _, exists := aggregator[dn]; !exists { if _, exists := aggregator[dn]; !exists {
aggregator[dn] = Entry{} aggregator[dn] = Entry{}
} }