Minimalistic LDAP proxy (via Simple-Bind) with Base-DN rewrite
Problem this snippet solves:
The outlined iRule can be used to access independent LDAP instances behind a single Virtual Server using a single Base-DN.
The iRule, will forward LDAP requests to an additional LDAP pool, if the Simple-Bind user account name matches the
$static::other_domains
list.
The iRule would then translate the original Base-DN to the Base-DN matching the additional LDAP instance.
Note1: The iRule doesn't adjust ASN.1/BER structures. So the original and changed Base-DN MUST have the same length. You may have to add SPACE paddings to allign the lenght of the Base-DNs.
Note2: The iRule wouldn't change the traffic for the default LDAP instance. The traffic is passed through after the Simple-Bind request is completed.
Note3: The iRule would translates just the LDAP requests destined to the Base-DN of the additional LDAP instance. The retrived results could then be accessed using their original DNs.
Cheers, Kai
How to use this snippet:
- Setup a standard Virtual Server for TCP:386.
- Apply SNAT and TCP profiles as needed.
- Assign the default LDAP instance as default_pool.
- Tweak the RULE_INIT event to match your environment.
Code :
when RULE_INIT { # # Minimalistic LDAP proxy (via Simple-Bind) with Base-DN rewrite # # Configuration of the other LDAP instance username prefix/suffixes set static::other_domains [list "itacs\\" "@itacs.de"];# List of lower case domain strings # Configuration of the other LDAP instance pool name set static::other_ldap_poolname OTHER_LDAP_POOL_NAME;# Value of the other pool name # Configuration of the Base-DN translation strings # # Important: The Base-DNs MUST have the same lenght. # You have to pad SPACES to match the length # binary scan "OU=xyz,DC=your-domain,DC=tld" H* temp(dn_default) ;# This is the default Base-DN binary scan "OU=f5-team, DC=itacs, DC=de" H* temp(dn_other);# This is the other Base-DN. Pad SPACES to match the length set static::other_base_dn_map [list $temp(dn_default) $temp(dn_other)] unset -nocomplain temp } when CLIENT_ACCEPTED { # TCP session init set session_binding_ldap 1 set session_other_active 0 # Collecting TCP data TCP::collect } when CLIENT_DATA { if { $session_binding_ldap } then { # Searching for simple Bind request to the other LDAP instance set session_binding_ldap 0 foreach temp(domain_string) $static::other_domains { if { [string tolower [TCP::payload]] contains $temp(domain_string) } then { # Forwarding the request to the other LDAP instance set session_other_active 1 pool $static::other_ldap_poolname log -noname local0.debug "LDAP simple bind request for other LDAP instance detected. Forwarding the connection to pool [LB::server pool]" break } } if { $session_other_active == 0 } then { # Forwarding the request to the default LDAP instance log -noname local0.debug "LDAP request for default LDAP instance detected. Forwarding the connection to pool [LB::server pool]" # Releasing TCP data TCP::release unset -nocomplain temp } } if { $session_other_active } then { # Translating Base-DNs for the other LDAP instance binary scan [TCP::payload] H* temp(hex_tcp_payload) set temp(new_tcp_payload) [binary format H* [string map $static::other_base_dn_map $temp(hex_tcp_payload)]] TCP::payload replace 0 [string length [TCP::payload]] $temp(new_tcp_payload) # Releasing TCP data TCP::release # Collecting further TCP data TCP::collect unset -nocomplain temp } }
Tested this on version:
12.0