LDAP pre-sessions for SAML auth are created without `ou` field, thus failing `replayProtection` check
Concerned version
Version: 2.0.14
Platform: Apache
Summary
When creating a pre-session for SAML authentication before redirecting to the IdP, using the LDAP session storage, the entry created does not contain an ou
field. When coming back to LemonLDAP, the replayProtection searches for a SAML session containing the relaystate in _assert_id, but the searchOn
method appends ${ldapAttributeIndex}=*
to the query, which by default is ou=*
. This means no session is returned.
The filter is hardcoded here with a note from 12 years ago saying it's necessary. https://github.com/LemonLDAPNG/Apache-Session-Browseable/blob/1288c777a2be536bb4742a6dc998742ade9d20cc/lib/Apache/Session/Browseable/LDAP.pm#L129-L131
I don't understand why the library uses ou
for this, but it seems like LemonLDAP is not creating an entry compatible with it.
Logs
I couldn't find logs of the pre-session creation so the relevant logs are very sparse (with LogLevel perl:debug notice
):
[Tue Aug 2 13:54:15 2022] [LLNG:3465786] [warn] No assertion session found for request ID _3C4F63E74BA5AC41A8AA108D1D52C76D
[Tue Aug 2 13:54:15 2022] [LLNG:3465786] [error] Message _3C4F63E74BA5AC41A8AA108D1D52C76D already used or expired, replay authentication
OpenLDAP relevant logs
# pre-session
ADD dn="cn=77a48ee4034c5e858b6f6b68763d51ff2c3494fdb231c047f2e8c805207460c7,ou=sessions,ou=lemonldap,ou=appconfig,dc=liege,dc=be"
MOD dn="cn=77a48ee4034c5e858b6f6b68763d51ff2c3494fdb231c047f2e8c805207460c7,ou=sessions,ou=lemonldap,ou=appconfig,dc=liege,dc=be"
# entry created
dn: cn=77a48ee4034c5e858b6f6b68763d51ff2c3494fdb231c047f2e8c805207460c7,ou=s
essions,ou=lemonldap,ou=appconfig,dc=liege,dc=be
cn: 77a48ee4034c5e858b6f6b68763d51ff2c3494fdb231c047f2e8c805207460c7
description: {"_utime":1659444039,"_session_kind":"SAML","_assert_id":"_18EE
4400C21515007FC2816B0E794006","_session_id":"77a48ee4034c5e858b6f6b68763d51
ff2c3494fdb231c047f2e8c805207460c7","type":"assertion"}
objectclass: applicationProcess
# return from IdP
SRCH base="ou=sessions,ou=lemonldap,ou=appconfig,dc=liege,dc=be" scope=2 deref=2 filter="(&(objectClass=applicationProcess)(ou=*))"
Backends used
globalStorageOption 'type' => 'LDAP' with default options. Setting 'ldapAttributeIndex' => 'cn'
fixes the problem.
Possible fixes
Either correctly setting the ou
field, or defaulting to 'ldapAttributeIndex' => 'cn'
.