From fd6a555216c82ac00f269c3ca3b7ab9b5d5184f0 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 14 Feb 2020 21:23:01 +0100 Subject: [PATCH] Ensure objects have an objectclass property --- README.md | 2 +- main.go | 1 + write.go | 15 +++++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b299aa..f37d884 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,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. 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 `bind`, `read`, `add`, `delete`, `modify` separated by spaces. +3. The action, a subset of `bind`, `read`, `add`, `delete`, `modify`, `modifyAdd` separated by spaces. `modifyAdd` is a special value that only authorizes modifications that add new values to a given attribute. This can be used to allow users to add other users to a group but not remove users from the group. 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. diff --git a/main.go b/main.go index b085e2f..70fad65 100644 --- a/main.go +++ b/main.go @@ -27,6 +27,7 @@ const ATTR_CREATORSNAME = "creatorsname" const ATTR_CREATETIMESTAMP = "createtimestamp" const ATTR_MODIFIERSNAME = "modifiersname" const ATTR_MODIFYTIMESTAMP = "modifytimestamp" +const ATTR_OBJECTCLASS = "objectclass" type ConfigFile struct { Suffix string `json:"suffix"` diff --git a/write.go b/write.go index 24fdc1a..7a71465 100644 --- a/write.go +++ b/write.go @@ -103,6 +103,9 @@ func (server *Server) handleAddInternal(state *State, r *message.AddRequest) (in } } + if _, ok := entry[ATTR_OBJECTCLASS]; !ok { + entry[ATTR_OBJECTCLASS] = []string{"top"} + } entry[ATTR_CREATORSNAME] = []string{state.login.user} entry[ATTR_CREATETIMESTAMP] = []string{genTimestamp()} entry[ATTR_ENTRYUUID] = []string{genUuid()} @@ -263,7 +266,8 @@ func (server *Server) handleModifyInternal(state *State, r *message.ModifyReques } // First permission check with no particular attributes - if !server.config.Acl.Check(&state.login, "modify", dn, []string{}) { + if !server.config.Acl.Check(&state.login, "modify", dn, []string{}) && + !server.config.Acl.Check(&state.login, "modifyAdd", dn, []string{}) { return ldap.LDAPResultInsufficientAccessRights, nil } @@ -316,7 +320,9 @@ func (server *Server) handleModifyInternal(state *State, r *message.ModifyReques } // Check for permission to modify this attribute - if !server.config.Acl.Check(&state.login, "modify", dn, []string{attr}) { + if !(server.config.Acl.Check(&state.login, "modify", dn, []string{attr}) || + (change.Operation() == ldap.ModifyRequestChangeOperationAdd && + server.config.Acl.Check(&state.login, "modifyAdd", dn, []string{attr}))) { return ldap.LDAPResultInsufficientAccessRights, nil } @@ -415,6 +421,11 @@ func (server *Server) handleModifyInternal(state *State, r *message.ModifyReques addMembers[i] = addMem } + if v, ok := newEntry[ATTR_OBJECTCLASS]; ok && len(v) == 0 { + return ldap.LDAPResultInsufficientAccessRights, fmt.Errorf( + "Cannot remove all objectclass values") + } + // Now, the modification has been processed and accepted and we want to commit it newEntry[ATTR_MODIFIERSNAME] = []string{state.login.user} newEntry[ATTR_MODIFYTIMESTAMP] = []string{genTimestamp()}