mysql-setup.sh \
openresty-setup.sh \
ldap-setup.sh \
+ ldap2-setup.sh \
redis-setup.sh; do
script="./scripts/ci/$i"
SQL_POSTGRESQL_TEST_SERVER: 127.0.0.1
LDAP_TEST_SERVER: 127.0.0.1
LDAP_TEST_SERVER_PORT: 3890
+ LDAP_TEST_SERVER_SSL_PORT: 6360
REST_TEST_SERVER: 127.0.0.1
REST_TEST_SERVER_PORT: 8080
REST_TEST_SERVER_SSL_PORT: 8443
#
# ldap_debug:: Debug flags for libldap (see OpenLDAP documentation).
+ # Set this to enable debugging output from different code areas within libldap.
#
- # .Please see the option 'ldap_debug'
+ # NOTE: These debugging options can produce significant amounts of logging output.
#
-# ldap_debug = 0x0000
+ # [options="header,autowidth"]
+ # |===
+ # | Option | Value
+ # | LDAP_DEBUG_TRACE | 0x0001
+ # | LDAP_DEBUG_PACKETS | 0x0002
+ # | LDAP_DEBUG_ARGS | 0x0004
+ # | LDAP_DEBUG_CONNS | 0x0008
+ # | LDAP_DEBUG_BER | 0x0010
+ # | LDAP_DEBUG_FILTER | 0x0020
+ # | LDAP_DEBUG_CONFIG | 0x0040
+ # | LDAP_DEBUG_ACL | 0x0080
+ # | LDAP_DEBUG_STATS | 0x0100
+ # | LDAP_DEBUG_STATS2 | 0x0200
+ # | LDAP_DEBUG_SHELL | 0x0400
+ # | LDAP_DEBUG_PARSE | 0x0800
+ # | LDAP_DEBUG_SYNC | 0x4000
+ # | LDAP_DEBUG_NONE | 0x8000
+ # | LDAP_DEBUG_ANY | (-1)
+ # |===
+ #
+ # e.g:
+ #
+ # If you want to see the LDAP logs only for `trace` and `parse`,
+ # facilities you should use:
+ #
+ # (LDAP_DEBUG_TRACE + LDAP_DEBUG_PARSE) = 0x0801
+ #
+ # Setting the `ldap_debug` configuration item as follows:
+ #
+ # ldap_debug = 0x0801
+ #
+ # Default: 0x0000 (no debugging messages)
+ #
+ ldap_debug = 0x0000
}
#
# NOTE: `LDAP_OPT_X_KEEPALIVE_INTERVAL` is set to this value.
#
interval = 3
-
- #
- # ldap_debug:: Debug flags for libldap (see OpenLDAP documentation).
- # Set this to enable debugging output from different code areas within libldap.
- #
- # NOTE: These debugging options can produce significant amounts of logging output.
- #
- # [options="header,autowidth"]
- # |===
- # | Option | Value
- # | LDAP_DEBUG_TRACE | 0x0001
- # | LDAP_DEBUG_PACKETS | 0x0002
- # | LDAP_DEBUG_ARGS | 0x0004
- # | LDAP_DEBUG_CONNS | 0x0008
- # | LDAP_DEBUG_BER | 0x0010
- # | LDAP_DEBUG_FILTER | 0x0020
- # | LDAP_DEBUG_CONFIG | 0x0040
- # | LDAP_DEBUG_ACL | 0x0080
- # | LDAP_DEBUG_STATS | 0x0100
- # | LDAP_DEBUG_STATS2 | 0x0200
- # | LDAP_DEBUG_SHELL | 0x0400
- # | LDAP_DEBUG_PARSE | 0x0800
- # | LDAP_DEBUG_SYNC | 0x4000
- # | LDAP_DEBUG_NONE | 0x8000
- # | LDAP_DEBUG_ANY | (-1)
- # |===
- #
- # e.g:
- #
- # If you want to see the LDAP logs only for `trace` and `parse`,
- # facilities you should use:
- #
- # (LDAP_DEBUG_TRACE + LDAP_DEBUG_PARSE) = 0x0801
- #
- # Setting the `ldap_debug` configuration item as follows:
- #
- # ldap_debug = 0x0801
- #
- # Default: 0x0000 (no debugging messages)
- #
- ldap_debug = 0x0000
}
#
--- /dev/null
+#
+###### SAMPLE 1 - SIMPLE DIRECTORY ############
+#
+# NOTES: inetorgperson picks up attributes and objectclasses
+# from all three schemas
+#
+# NB: RH Linux schemas in /etc/openldap
+#
+include /tmp/ldap2/schema/core.schema
+include /tmp/ldap2/schema/cosine.schema
+include /tmp/ldap2/schema/inetorgperson.schema
+include /tmp/ldap2/schema/nis.schema
+include doc/schemas/ldap/openldap/freeradius.schema
+include doc/schemas/ldap/openldap/freeradius-clients.schema
+pidfile /tmp/slapd2.pid
+
+# enable a lot of logging - we might need it
+# but generates huge logs
+loglevel -1
+
+# MODULELOAD definitions
+# not required (comment out) before version 2.3
+moduleload back_mdb.la
+
+database config
+rootdn "cn=admin,cn=config"
+rootpw secret
+
+#
+# Certificates for SSL/TLS connections
+# Note - these will not match the host name so clients need to use
+# the "allow" option when checking certificates
+#
+TLSCACertificateFile /tmp/ldap2/certs/cacert.pem
+TLSCertificateFile /tmp/ldap2/certs/servercert.pem
+TLSCertificateKeyFile /tmp/ldap2/certs/serverkey.pem
+
+#######################################################################
+# mdb database definitions
+#
+# replace example and com below with a suitable domain
+#
+# If you don't have a domain you can leave it since example.com
+# is reserved for experimentation or change them to my and inc
+#
+#######################################################################
+
+database mdb
+suffix "dc=nodomain"
+
+# root or superuser
+rootdn "cn=admin,dc=nodomain"
+rootpw secret
+# The database directory MUST exist prior to running slapd AND
+# change path as necessary
+directory /tmp/ldap2/db/
+
+# other database parameters
+# read more in slapd.conf reference section
+checkpoint 128 15
+
--- /dev/null
+#!/bin/sh
+
+# Allow setup script to work with homebrew too
+export PATH="/usr/local/opt/openldap/libexec:$PATH"
+
+# Clean out any existing DB
+rm -rf /tmp/ldap2/db
+# Create directory we can write DB files to
+mkdir -p /tmp/ldap2/db/
+
+# Change db location to /tmp as we can't write to /var
+sed -i -e 's/\/var\/lib\/ldap/\/tmp\/ldap2\/db/' src/tests/salt-test-server/salt/ldap/base2.ldif
+
+# Create a directory we can link schema files into
+if [ -d /tmp/ldap2/schema ]; then
+ echo "Schema dir already linked"
+# Debian
+elif [ -d /etc/ldap/schema ]; then
+ ln -fs /etc/ldap/schema /tmp/ldap2/schema
+# Redhat
+elif [ -d /etc/openldap/schema ]; then
+ ln -fs /etc/openldap/schema /tmp/ldap2/schema
+# macOS (homebrew)
+elif [ -d /usr/local/etc/openldap/schema ]; then
+ ln -fs /usr/local/etc/openldap/schema /tmp/ldap2/schema
+else
+ echo "Can't locate OpenLDAP schema dir"
+ exit 1
+fi
+
+# Clean out any old certificates
+rm -rf /tmp/ldap2/certs
+# Create certificate directory
+mkdir -p /tmp/ldap2/certs
+
+# Copy certificates - whilst not stricltly LDAP certs they work fine for these tests
+cp src/tests/certs/rsa/ca.pem /tmp/ldap2/certs/cacert.pem
+cp src/tests/certs/rsa/server.pem /tmp/ldap2/certs/servercert.pem
+# OpenLDAP wants an un-encrypted key
+openssl rsa -in src/tests/certs/rsa/server.key -out /tmp/ldap2/certs/serverkey.pem -passin pass:whatever
+
+# Start slapd
+slapd -h "ldap://127.0.0.1:3891/ ldaps://127.0.0.1:6360" -f scripts/ci/ldap/slapd2.conf &
+
+# Wait for LDAP to start
+sleep 1
+
+# Add test data
+count=0
+while [ $count -lt 10 ] ; do
+ if ldapadd -x -H ldap://127.0.0.1:3891/ -D "cn=admin,cn=config" -w secret -f src/tests/salt-test-server/salt/ldap/base2.ldif ; then
+ break 2
+ else
+ count=$((count+1))
+ sleep 1
+ fi
+done
+
+if [ $? -ne 0 ]; then
+ echo "Error configuring server"
+ exit 1
+fi
+
#
ldap.accounting {
}
-if (ok) {
- test_pass
-}
-else {
+if (!ok) {
test_fail
}
if (&Tmp-String-0 != "User john is online") {
test_fail
}
-else {
- test_pass
-}
+
+test_pass
if (&control.NAS-IP-Address != 1.2.3.4) {
test_fail
}
-else {
- test_pass
-}
if (&control.Reply-Message != "Hello world") {
test_fail
}
-else {
- test_pass
-}
# Cmp operator means Framed-IP-Address is ignored
if (&control.Framed-IP-Address) {
test_fail
}
-else {
- test_pass
-}
# IP netmask defined in profile1 should overwrite radprofile value.
if (&reply.Framed-IP-Netmask != 255.255.0.0) {
test_fail
}
-else {
- test_pass
-}
if (&reply.Acct-Interim-Interval != 1800) {
test_fail
}
-else {
- test_pass
-}
if (&reply.Idle-Timeout != 3600) {
test_fail
}
-else {
- test_pass
-}
if (&reply.Session-Timeout != 7200) {
test_fail
}
-else {
- test_pass
-}
if ("%(pairs:reply.)" == "") {
test_fail
}
+# Attempt a bind authentication
+ldap.authenticate
+
ldap.post-auth
update {
if (&Tmp-String-0 != "User %{User-Name} authenticated") {
test_fail
}
-else {
- test_pass
-}
+
+test_pass
--- /dev/null
+#
+# Input packet
+#
+Packet-Type = Access-Request
+User-Name = "fred"
+User-Password = "password"
+NAS-IP-Address = 1.2.3.5
+
+#
+# Expected answer
+#
+Packet-Type == Access-Accept
+Idle-Timeout == 3600
+Session-Timeout == 7200
--- /dev/null
+#
+# Run the "ldapssl" module - an instance of ldap using an ssl conneciton
+#
+ldapssl
+
+if (&control.NAS-IP-Address != 1.2.3.4) {
+ test_fail
+}
+
+# Cmp operator means Framed-IP-Address is ignored
+if (&control.Framed-IP-Address) {
+ test_fail
+}
+
+if (&reply.Idle-Timeout != 3600) {
+ test_fail
+}
+
+if (&reply.Session-Timeout != 7200) {
+ test_fail
+}
+
+if ("%(pairs:reply.)" == "") {
+ test_fail
+}
+
+# Attempt a bind authentication
+ldapssl.authenticate
+
+ldapssl.post-auth
+
+update {
+ &Tmp-String-0 := "%{ldapssl:ldaps:///uid=fred,ou=people,dc=subdept,dc=example,dc=com?description}"
+}
+
+if (&Tmp-String-0 != "User %{User-Name} authenticated") {
+ test_fail
+}
+
+test_pass
--- /dev/null
+#
+# Input packet
+#
+Packet-Type = Access-Request
+User-Name = "fred"
+User-Password = "password"
+NAS-IP-Address = 1.2.3.5
+
+#
+# Expected answer
+#
+Packet-Type == Access-Accept
+Idle-Timeout == 3600
+Session-Timeout == 7200
--- /dev/null
+#
+# Run the "ldapssl" module - an instance of ldap using an ssl conneciton
+#
+
+ldaptls
+
+if (&control.NAS-IP-Address != 1.2.3.4) {
+ test_fail
+}
+
+# Cmp operator means Framed-IP-Address is ignored
+if (&control.Framed-IP-Address) {
+ test_fail
+}
+
+if (&reply.Idle-Timeout != 3600) {
+ test_fail
+}
+
+if (&reply.Session-Timeout != 7200) {
+ test_fail
+}
+
+if ("%(pairs:reply.)" == "") {
+ test_fail
+}
+
+# Attempt a bind authentication
+ldaptls.authenticate
+
+ldaptls.post-auth
+
+update {
+ &Tmp-String-0 := "%{ldaptls:ldap:///uid=fred,ou=people,dc=subdept,dc=example,dc=com?description}"
+}
+
+if (&Tmp-String-0 != "User %{User-Name} authenticated") {
+ test_fail
+}
+
+test_pass
#
# Resolve using group name attribute
#
-if (&LDAP-Group == 'foo') {
- test_pass
-}
-else {
+if (&LDAP-Group != 'foo') {
test_fail
}
#
# Resolve using group DN
#
-if (&LDAP-Group == 'cn=foo,ou=groups,dc=example,dc=com') {
- test_pass
-}
-else {
+if (&LDAP-Group != 'cn=foo,ou=groups,dc=example,dc=com') {
test_fail
}
#
# Check we have these values cached
#
-if (&control.LDAP-Cached-Membership[*] == 'foo') {
- test_pass
-}
-else {
+if (&control.LDAP-Cached-Membership[*] != 'foo') {
test_fail
}
-if (&control.LDAP-Cached-Membership[*] == 'cn=foo,ou=groups,dc=example,dc=com') {
- test_pass
-}
-else {
+if (&control.LDAP-Cached-Membership[*] != 'cn=foo,ou=groups,dc=example,dc=com') {
test_fail
}
+
+test_pass
&Tmp-String-1 += 'entryDN'
}
-if (updated) {
- test_pass
-} else {
+if (!updated) {
test_fail
}
-if (&request.Tmp-String-0 == '255.255.255.0') {
- test_pass
-}
-else {
+if (&request.Tmp-String-0 != '255.255.255.0') {
test_fail
}
-if (&request.Tmp-String-1[0] == 'cn=radprofile,ou=profiles,dc=example,dc=com') {
- test_pass
-}
-else {
+if (&request.Tmp-String-1[*] != 'cn=radprofile,ou=profiles,dc=example,dc=com') {
test_fail
}
-if (&request.Tmp-String-1[1] == 'cn=profile1,ou=profiles,dc=example,dc=com') {
- test_pass
-}
-else {
+if (&request.Tmp-String-1[*] != 'cn=profile1,ou=profiles,dc=example,dc=com') {
test_fail
}
&Tmp-String-1 += 'entryDN'
}
-#
-# Uncomment when map return codes work properly
-#
-#if (notfound) {
-# test_pass
-#} else {
-# test_fail
-#}
+if (!notfound) {
+ test_fail
+}
+
+test_pass
# realm = 'example.org'
}
+ global {
+ # ldap_debug: debug flag for LDAP SDK
+ # (see OpenLDAP documentation). Set this to enable
+ # huge amounts of LDAP debugging on the screen.
+ # You should only use this if you are an LDAP expert.
+ #
+ # default: 0x0000 (no debugging messages)
+ # Example:(LDAP_DEBUG_FILTER+LDAP_DEBUG_CONNS)
+ ldap_debug = 0x0801
+ }
+
#
# Generic valuepair attribute
#
#
chase_referrals = yes
rebind = yes
+ referral_depth = 2
# Seconds to wait for LDAP query to finish. default: 20
timeout = 10
# LDAP_OPT_X_KEEPALIVE_INTERVAL
interval = 3
- # ldap_debug: debug flag for LDAP SDK
- # (see OpenLDAP documentation). Set this to enable
- # huge amounts of LDAP debugging on the screen.
- # You should only use this if you are an LDAP expert.
- #
- # default: 0x0000 (no debugging messages)
- # Example:(LDAP_DEBUG_FILTER+LDAP_DEBUG_CONNS)
- ldap_debug = 0x0028
}
#
# or increase lifetime/idle_timeout.
}
}
+
+#
+# Second LDAP connection using SSL
+#
+ldap ldapssl {
+ server = "ldaps://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_SSL_PORT}/"
+
+ identity = 'cn=admin,dc=example,dc=com'
+ password = secret
+
+ base_dn = 'dc=subdept,dc=example,dc=com'
+
+ sasl {
+ }
+
+ global {
+ ldap_debug = 0x0801
+ }
+
+ valuepair_attribute = 'radiusAttribute'
+
+ update {
+ &control.Password.With-Header += 'userPassword'
+ &reply.Idle-Timeout := 'radiusIdleTimeout'
+ &reply.Framed-IP-Netmask := 'radiusFramedIPNetmask'
+
+ &control += 'radiusControlAttribute'
+ &request += 'radiusRequestAttribute'
+ &reply += 'radiusReplyAttribute'
+ }
+
+ user {
+ base_dn = "ou=people,${..base_dn}"
+
+ filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
+
+ sasl {
+ }
+ }
+
+ group {
+ base_dn = "ou=groups,${..base_dn}"
+ filter = '(objectClass=groupOfNames)'
+ scope = 'sub'
+ name_attribute = cn
+ membership_filter = "(|(member=%{control.Ldap-UserDn})(memberUid=%{%{Stripped-User-Name}:-%{User-Name}}))"
+ membership_attribute = 'memberOf'
+ cacheable_name = no
+ cacheable_dn = no
+ cache_attribute = 'LDAP-Cached-Membership'
+ }
+
+ profile {
+ filter = '(objectclass=radiusprofile)'
+ default = 'cn=radprofile,ou=profiles,dc=example,dc=com'
+ attribute = 'radiusProfileDn'
+ }
+
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}}"
+ type {
+ start {
+ update {
+ description := "User %{User-Name} is online"
+ }
+ }
+ interim-update {
+ update {
+ description := "Last seen at %S"
+ }
+ }
+ stop {
+ update {
+ description := "Offline at %S"
+ }
+ }
+ }
+ }
+
+ post-auth {
+ update {
+ description := "User %{User-Name} authenticated"
+ }
+ }
+
+ options {
+# dereference = 'always'
+
+ chase_referrals = yes
+ rebind = yes
+ referral_depth = 2
+
+ timeout = 10
+ timelimit = 3
+ idle = 60
+ probes = 3
+ interval = 3
+
+ }
+
+ tls {
+ require_cert = 'allow'
+ ca_file = 'src/tests/certs/rsa/ca.pem'
+ }
+
+ pool {
+ start = 1
+ min = 1
+ max = 4
+ spare = 0
+ uses = 0
+ lifetime = 0
+ idle_timeout = 60
+ retry_delay = 1
+ }
+}
+
+#
+# Third LDAP connection using StartTLS
+#
+ldap ldaptls {
+ server = "$ENV{LDAP_TEST_SERVER}"
+
+ port = 3891
+
+ identity = 'cn=admin,dc=example,dc=com'
+ password = secret
+
+ base_dn = 'dc=subdept,dc=example,dc=com'
+
+ sasl {
+ }
+
+ global {
+ ldap_debug = 0x0801
+ }
+
+ valuepair_attribute = 'radiusAttribute'
+
+ update {
+ &control.Password.With-Header += 'userPassword'
+ &reply.Idle-Timeout := 'radiusIdleTimeout'
+ &reply.Framed-IP-Netmask := 'radiusFramedIPNetmask'
+
+ &control += 'radiusControlAttribute'
+ &request += 'radiusRequestAttribute'
+ &reply += 'radiusReplyAttribute'
+ }
+
+ user {
+ base_dn = "ou=people,${..base_dn}"
+
+ filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
+
+ sasl {
+ }
+ }
+
+ group {
+ base_dn = "ou=groups,${..base_dn}"
+ filter = '(objectClass=groupOfNames)'
+ scope = 'sub'
+ name_attribute = cn
+ membership_filter = "(|(member=%{control.Ldap-UserDn})(memberUid=%{%{Stripped-User-Name}:-%{User-Name}}))"
+ membership_attribute = 'memberOf'
+ cacheable_name = no
+ cacheable_dn = no
+ cache_attribute = 'LDAP-Cached-Membership'
+ }
+
+ profile {
+ filter = '(objectclass=radiusprofile)'
+ default = 'cn=radprofile,ou=profiles,dc=example,dc=com'
+ attribute = 'radiusProfileDn'
+ }
+
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}}"
+ type {
+ start {
+ update {
+ description := "User %{User-Name} is online"
+ }
+ }
+ interim-update {
+ update {
+ description := "Last seen at %S"
+ }
+ }
+ stop {
+ update {
+ description := "Offline at %S"
+ }
+ }
+ }
+ }
+
+ post-auth {
+ update {
+ description := "User %{User-Name} authenticated"
+ }
+ }
+
+ options {
+# dereference = 'always'
+
+ chase_referrals = yes
+ rebind = yes
+ referral_depth = 2
+
+ timeout = 10
+ timelimit = 3
+ idle = 60
+ probes = 3
+ interval = 3
+
+ }
+
+ tls {
+ start_tls = yes
+ require_cert = 'allow'
+ ca_file = 'src/tests/certs/rsa/ca.pem'
+ }
+
+ pool {
+ start = 1
+ min = 1
+ max = 4
+ spare = 3
+ uses = 0
+ lifetime = 0
+ idle_timeout = 60
+ retry_delay = 1
+ }
+}
User-Name = "john"
User-Password = "password"
NAS-IP-Address = 1.2.3.5
+Tmp-String-9 = "(manager)"
#
# Expected answer
test_fail
}
+update request {
+ &Tmp-String-6 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_PORT}/ou=people,dc=example,dc=com?displayName?sub?(uid=john)}"
+}
+
+if (&Tmp-String-6 != "John Doe") {
+ test_fail
+}
+
+# Return multiple values - could be in any sequence
+update request {
+ &Tmp-String-7 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_PORT}/ou=clients,dc=example,dc=com?radiusClientIdentifier?sub?(objectClass=radiusClient)}"
+}
+
+if ((&Tmp-String-7 != "1.1.1.12.2.2.2") && (&Tmp-String-7 != "2.2.2.21.1.1.1")) {
+ test_fail
+}
+
+# Use tainted string in filter - with special characters
+update request {
+ &Tmp-String-8 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_PORT}/ou=people,dc=example,dc=com?cn?sub?(displayName=*%{Tmp-String-9}*)}"
+}
+
+if (&Tmp-String-8 != "Bob Smith") {
+ test_fail
+}
+
+# A query which should return no results
+update request {
+ &Tmp-String-0 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_PORT}/ou=people,dc=example,dc=com?displayName?sub?(uid=notknown)}"
+}
+
+if (&Tmp-String-0 != "") {
+ test_fail
+}
+
+# Request an invalid DN
+update request {
+ &Tmp-String-0 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_PORT}/ou=notthere?displayName?sub?(uid=john)}"
+}
+
+if (&Tmp-String-0 != "") {
+ test_fail
+}
+
+if (&Module-Failure-Message != "LDAP server returned an error: lib error: No such object (32)") {
+ test_fail
+}
+
+# Query within a dn which will prompt a referral
+update request {
+ &Tmp-String-0 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_PORT}/dc=subdept,dc=example,dc=com?displayName?sub?(uid=fred)}"
+}
+
+if (&Tmp-String-0 != "Fred Jones") {
+ test_fail
+}
+
+# Reference an alternative LDAP server in the xlat
+update request {
+ &Tmp-String-1 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:%{expr:$ENV{LDAP_TEST_SERVER_PORT} + 1}/dc=subdept,dc=example,dc=com?displayName?sub?(uid=fred)}"
+}
+
+if (&Tmp-String-1 != "Fred Jones") {
+ test_fail
+}
+
+# This query will follow 2 referrals, the second will present an alternate search base
+update request {
+ &Tmp-String-2 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_PORT}/ou=offsite,dc=subdept,dc=example,dc=com?displayName?sub?(uid=john)}"
+}
+
+if (&Tmp-String-2 != "John Doe") {
+ test_fail
+}
+
+# This query will follow 3 referrals - more than our max referral depth
+update request {
+ &Tmp-String-3 := "%{ldap:ldap://$ENV{LDAP_TEST_SERVER}:$ENV{LDAP_TEST_SERVER_PORT}/ou=bounce1,dc=subdept,dc=example,dc=com?displayName?sub?(uid=fred)}"
+}
+
+if (&Tmp-String-3 != "") {
+ test_fail
+}
+
+if (&Module-Failure-Message != "Maximum LDAP referral depth (2) exceeded") {
+ test_fail
+}
+
test_pass
olcDbIndex: objectClass eq
olcLastMod: TRUE
olcDbCheckpoint: 512 30
-olcAccess: to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by dn="cn=admin,cn=config" manage
olcAccess: to attrs=userPassword by dn="cn=admin,dc=example,dc=com" write by anonymous auth by self write by * none
+olcAccess: to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by dn="cn=admin,cn=config" manage
olcAccess: to attrs=shadowLastChange by self write by * read
olcAccess: to dn.base="" by * read
olcAccess: to * by dn="cn=admin,dc=example,dc=com" write by * read
radiusAttribute: control.NAS-IP-Address := 1.2.3.4
radiusProfileDN: cn=profile1,ou=profiles,dc=example,dc=com
+dn: uid=bob,ou=people,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: posixAccount
+objectClass: shadowAccount
+objectClass: radiusprofile
+uid: bob
+sn: Smith
+givenName: Bob
+cn: Bob Smith
+displayName: Bob Smith (manager)
+userPassword: testing
+uidNumber: 101
+gidNumber: 101
+homeDirectory: /home/bob
+radiusIdleTimeout: 7200
+
dn: ou=clients,dc=example,dc=com
objectClass: organizationalUnit
ou: clients
radiusClientType: cisco
radiusClientRequireMa: TRUE
radiusClientComment: Another test client
+
+dn: dc=subdept,dc=example,dc=com
+objectClass: referral
+objectClass: extensibleObject
+dc: subdept
+ref: ldap://127.0.0.1:3892/
+ref: ldap://127.0.0.1:3891/dc=subdept,dc=example,dc=com
+
+dn: ou=bounce2,dc=example,dc=com
+objectClass: referral
+objectClass: extensibleObject
+ou: bounce2
+ref: ldap://127.0.0.1:3891/dc=subdept,dc=example,dc=com??sub
--- /dev/null
+# Database settings
+dn: olcDatabase=mdb,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olcMdbConfig
+olcDatabase: {1}mdb
+olcSuffix: dc=example,dc=com
+olcDbDirectory: /tmp/ldap2/db
+olcRootDN: cn=admin,dc=example,dc=com
+olcRootPW: {SSHA}SgCZuAcGQA5HlgKi+g5xwVyI2NhXRFYh
+olcDbIndex: objectClass eq
+olcLastMod: TRUE
+olcDbCheckpoint: 512 30
+olcAccess: to attrs=userPassword by dn="cn=admin,dc=example,dc=com" write by anonymous auth by self write by * none
+olcAccess: to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by dn="cn=admin,cn=config" manage
+olcAccess: to attrs=shadowLastChange by self write by * read
+olcAccess: to dn.base="" by * read
+olcAccess: to * by dn="cn=admin,dc=example,dc=com" write by * read
+
+# Create top-level object in domain
+dn: dc=example,dc=com
+objectClass: top
+objectClass: dcObject
+objectclass: organization
+o: Example Organization
+dc: Example
+description: LDAP Example Two
+
+dn: dc=subdept,dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Sub org
+dc: subdept
+
+dn: ou=people,dc=subdept,dc=example,dc=com
+objectClass: organizationalUnit
+ou: people
+
+dn: ou=groups,dc=subdept,dc=example,dc=com
+objectClass: organizationalUnit
+ou: groups
+
+dn: ou=profiles,dc=subdept,dc=example,dc=com
+objectClass: organizationalUnit
+ou: profiles
+
+dn: cn=radprofile,ou=profiles,dc=subdept,dc=example,dc=com
+objectClass: radiusObjectProfile
+objectClass: radiusprofile
+cn: radprofile
+radiusFramedIPNetmask: 255.255.255.0
+
+dn: uid=fred,ou=people,dc=subdept,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: posixAccount
+objectClass: shadowAccount
+objectClass: radiusprofile
+uid: fred
+sn: Jones
+givenName: Fred
+cn: Fred Jones
+displayName: Fred Jones
+userPassword: password
+uidNumber: 100
+gidNumber: 100
+homeDirectory: /home/fred
+radiusIdleTimeout: 3600
+radiusAttribute: reply.Session-Timeout := 7200
+radiusAttribute: control.NAS-IP-Address := 1.2.3.4
+radiusProfileDN: cn=radprofile,ou=profiles,ou=subdept,dc=example,dc=com
+
+dn: ou=offsite,dc=subdept,dc=example,dc=com
+objectClass: referral
+objectClass: extensibleObject
+ou: offsite
+ref: ldap://127.0.0.1:3890/dc=example,dc=com??sub
+
+dn: ou=bounce1,dc=subdept,dc=example,dc=com
+objectClass: referral
+objectClass: extensibleObject
+ou: bounce1
+ref: ldap://127.0.0.1:3890/ou=bounce2,dc=example,dc=com??sub