public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Stefan Sterz <s.sterz@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH access-control] ldap: fix ldap distinguished names regex
Date: Wed, 17 May 2023 15:39:31 +0200	[thread overview]
Message-ID: <20230517133931.148634-1-s.sterz@proxmox.com> (raw)

according to the current specification of the string representation of
ldap distinguished names (DN) presented by RFC 4514 [1] the current
regex checking ldap DNs still prevents users from entering valid
DNs.

for example we do not allow multi-valued RelativeDistinguishedNames as
these are separated by a '+'. this was already reported as an issue in
the subscription support.

escaped sequences in unquoted AttributeValues are also not allowed.
this includes commas (',') and quotes ('"'). for example, the
following does not work even though the RFC explicitly mentions it as
a valid example ([1], section 4):

CN=James \"Jim\" Smith\, III,DC=example,DC=net

while this may not be usable as a valid username, as argued
previously [2], it seems arbitrary to allow this for quoted
AttributeValues but not for unquoted ones.

this commit also adds a test file that tests the regex against a
number of common pitfalls. including distinguished names that are
structurally similar to those reported as erroneously forbidden
earlier. these tests should help avoid regressions in the future.

[1]: https://datatracker.ietf.org/doc/html/rfc4514
[2]: https://git.proxmox.com/?p=pve-access-control.git;h=1aa2355a

Signed-off-by: Stefan Sterz <s.sterz@proxmox.com>
---
would really appreciate another pair of eyes here. given the recent
churn related to this regex. it's very likely i missed something too.

 src/PVE/Auth/LDAP.pm      |  9 +++++--
 src/test/Makefile         |  1 +
 src/test/dn-regex-test.pl | 54 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 2 deletions(-)
 create mode 100755 src/test/dn-regex-test.pl

diff --git a/src/PVE/Auth/LDAP.pm b/src/PVE/Auth/LDAP.pm
index fc82a17..ccc6864 100755
--- a/src/PVE/Auth/LDAP.pm
+++ b/src/PVE/Auth/LDAP.pm
@@ -10,8 +10,13 @@ use PVE::Tools;
 
 use base qw(PVE::Auth::Plugin);
 
-my  $dn_part_regex = qr!("[^"]+"|[^ ,+"/<>;=#][^,+"/<>;=]*[^ ,+"/<>;=]|[^ ,+"/<>;=#])!;
-our $dn_regex = qr!\w+=${dn_part_regex}(,\s*\w+=${dn_part_regex})*!;
+my $escaped  = qr!\\(?:[ "#+,;<=>\\]|[0-9a-fA-F]{2})!;
+my $start    = qr!(?:${escaped}|[^"+,;<>\\\0 #])!;
+my $middle   = qr!(?:${escaped}|[^"+,;<>\\\0])!;
+my $end      = qr!(?:${escaped}|[^"+,;<>\\\0 ])!;
+my $attr_val = qr!("[^"]+"|${start}(?:${middle}*${end})?)!;
+
+our $dn_regex = qr!\w+=${attr_val}([,\+]\s*\w+=${attr_val})*!;
 
 sub type {
     return 'ldap';
diff --git a/src/test/Makefile b/src/test/Makefile
index 859a84b..b4c05eb 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -13,3 +13,4 @@ check:
 	perl -I.. perm-test7.pl
 	perl -I.. perm-test8.pl
 	perl -I.. realm_sync_test.pl
+	perl -I.. dn-regex-test.pl
diff --git a/src/test/dn-regex-test.pl b/src/test/dn-regex-test.pl
new file mode 100755
index 0000000..a2410af
--- /dev/null
+++ b/src/test/dn-regex-test.pl
@@ -0,0 +1,54 @@
+
+use strict;
+use warnings;
+
+use PVE::Auth::LDAP;
+
+# this test file attempts to check whether the ldap distinguished name regex
+# defined in `PVE::Auth::LDAP` complies with RFC 4514.
+# 
+# see: https://datatracker.ietf.org/doc/html/rfc4514
+
+my @pass = (
+    "ou=a",			# single AttributeTypeValue 
+    "ou=orga,dc=com,cn=name",	# multiple RelativeDistinguishedNames
+    "STREET=a,cn=a,C=c",	# single character AttributeValues
+    "UID=tt,cn=\"#+,;<>\\ \"",	# forbidden characters are allowed when quoted
+    "c=\\\"\\#\\+\\;\\<\\=\\>",	# specific characters allowed when escaped
+    "a=\\\\",			# escaped backslashes are allowed
+    "ST=a,cn=\"Test, User\"",	# allow un-escaped commas in quoted AttributeValues
+    "o2u=bc,cn=Test\\, User",	# allow escaped commas
+    "T2=a #b",			# spaces (' ') and '#' are allowed in the middle of AttributeValues
+    "word4word=ab#",		# allow '#' at the end of an AttributeValue
+    "ou=orga+sub=ab",		# allow '+' as separators for multi-valued RelativeDistinguishedName
+    "dc=\\f0\\Ac\\93",		# allow escaping hex values in unquoted AttributeValues
+
+    # regression tests
+    "ou=adf-bd,dc=abcd+efOuId=BL:BL:sldkf:704004,dc=or,dc=com",
+    "gvGid=DE:8A:wordCaps,ou=Service,dc=alsdkj+abOuId=UK:A8:137100,dc=edu,dc=de",
+);
+
+my @fail = (
+    "",				# no empty distinguished name
+    "ou=a,",			# no empty AttributeTypeAndValue
+    "ou=a+",			# no multi-valued RelativeDistinguishedName with empty second part
+    "ou",			# missing separator and AttributeValue
+    "ou=",			# no 'empty' AttributeValue
+    "ou=+",			# forbidden character '+' in AttributeValue
+    "ou= or",			# no space at the beginning of an AttributeValue
+    "ou=orgs ",			# no space at the end of an AttributeValue
+    "ou=#value",		# no '#' at the beginning an AttributeValue
+    "ou=\"+,;<>\\\0",		# no un-escaped forbidden characters in unquoted AttributeValues
+    "ou=name\0",		# no null value in AttributeValue
+    "ou=zy\\xw\\v"		# no unescaped backslashes that are not escaping specific characters
+);
+
+for my $test_case (@pass) {
+    die "\'" . $test_case . "\' unexpectedly did not match the ldap dn_regex\n"
+	if !($test_case =~ m/^$PVE::Auth::LDAP::dn_regex$/);
+}
+
+for my $test_case (@fail) {
+    die "\'" . $test_case . "\' unexpectedly did match the the ldap dn_regex\n"
+	if $test_case =~ m/^$PVE::Auth::LDAP::dn_regex$/;
+}
-- 
2.30.2





             reply	other threads:[~2023-05-17 13:40 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-17 13:39 Stefan Sterz [this message]
2023-05-17 13:42 ` Stefan Sterz
2023-05-28 17:50   ` Thomas Lamprecht
2023-05-23  6:58 ` Christoph Heiss
2023-05-23  8:56   ` Stefan Sterz
2023-05-23 10:12     ` Christoph Heiss
2023-05-23 12:17       ` Stefan Sterz
2023-05-25  9:52         ` Christoph Heiss

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230517133931.148634-1-s.sterz@proxmox.com \
    --to=s.sterz@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal