diff --git a/changelog/unreleased/ldap-escape-dn.md b/changelog/unreleased/ldap-escape-dn.md
new file mode 100644
index 000000000..78e38cd5f
--- /dev/null
+++ b/changelog/unreleased/ldap-escape-dn.md
@@ -0,0 +1,6 @@
+Bugfix: Escape DN attribute value
+
+Escaped the DN attribute value on creating users and groups.
+
+
+https://github.com/owncloud/ocis/pull/4117
diff --git a/ocis-pkg/ldap/ldap.go b/ocis-pkg/ldap/ldap.go
index 8eceaf3cb..9276c4709 100644
--- a/ocis-pkg/ldap/ldap.go
+++ b/ocis-pkg/ldap/ldap.go
@@ -5,6 +5,7 @@ import (
"errors"
"io/ioutil"
"os"
+ "strings"
"time"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
@@ -15,6 +16,20 @@ const (
caCheckSleep = 2
)
+var (
+ dnEscaper = strings.NewReplacer(
+ "\\", "\\\\",
+ ",", "\\,",
+ "+", "\\+",
+ `"`, `\\"`,
+ "<", "\\<",
+ ">", "\\>",
+ ";", "\\;",
+ "=", "\\=",
+ "\000", "\\\000",
+ )
+)
+
func WaitForCA(log log.Logger, insecure bool, caCert string) error {
if !insecure && caCert != "" {
for i := 0; i < caCheckRetries; i++ {
@@ -38,3 +53,20 @@ func WaitForCA(log log.Logger, insecure bool, caCert string) error {
}
return nil
}
+
+// EscapeDNAttributeValue escapes special characters in an attribute value as [described in RFC4514](https://datatracker.ietf.org/doc/html/rfc4514).
+func EscapeDNAttributeValue(v string) string {
+ if v == "" {
+ return v
+ }
+
+ v = dnEscaper.Replace(v)
+
+ if strings.HasSuffix(v, " ") {
+ v = v[:len(v)-1] + "\\ "
+ }
+ if strings.HasPrefix(v, "#") || strings.HasPrefix(v, " ") {
+ v = "\\" + v
+ }
+ return v
+}
diff --git a/ocis-pkg/ldap/ldap_suite_test.go b/ocis-pkg/ldap/ldap_suite_test.go
new file mode 100644
index 000000000..3eee47856
--- /dev/null
+++ b/ocis-pkg/ldap/ldap_suite_test.go
@@ -0,0 +1,13 @@
+package ldap_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestLdap(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Ldap Suite")
+}
diff --git a/ocis-pkg/ldap/ldap_test.go b/ocis-pkg/ldap/ldap_test.go
new file mode 100644
index 000000000..6925facb7
--- /dev/null
+++ b/ocis-pkg/ldap/ldap_test.go
@@ -0,0 +1,25 @@
+package ldap_test
+
+import (
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/owncloud/ocis/v2/ocis-pkg/ldap"
+)
+
+var _ = Describe("ldap", func() {
+ DescribeTable("EscapeDNAttributeValue should escape special characters",
+ func(input, expected string) {
+ escaped := ldap.EscapeDNAttributeValue(input)
+ Expect(escaped).To(Equal(expected))
+ },
+ Entry("normal dn", "foobar", "foobar"),
+ Entry("including comma", "foo,bar", "foo\\,bar"),
+ Entry("including equals", "foo=bar", "foo\\=bar"),
+ Entry("beginning with number sign", "#foobar", "\\#foobar"),
+ Entry("beginning with space", " foobar", "\\ foobar"),
+ Entry("only one space", " ", "\\ "),
+ Entry("two spaces", " ", "\\ \\ "),
+ Entry("ending with space", "foobar ", "foobar\\ "),
+ Entry("containing multiple special chars", `f+o>o,bo\,b\