We have an Active Directory domain with >6000 users and several hundred
groups. The group hierarchy is usually nested 4-5 levels deep.  Queries for
the full set of nested groups for a user take > 10 seconds each.  We have
an app (Nexus OSS) that asks for a user's nested groups on every
interaction (e.g. for each dependency needed to perform a maven build) and
does not perform local caching.

I am trying to implement a slapd + meta + pcache solution that will proxy
the LDAP query, cache the results, and significantly speed up user
interactions with this app.  I have tried many configurations.  I can
always proxy the request, but I haven't yet been able to fully cache the
results.  I have had the most success with the passthru module from
https://github.com/cbueche/openldap-passthru and rwm.  In this
configuration, slapd proxies inbound filters like "(member=CN=my
name,ou=users,dc=some,dc=structure)" and passes that on to AD as
"member:1.2.840.113556.1.4.1941:=CN=my
name,ou=userss,dc=some,dc=structure)".  AD returns the group DNs but slapd
partially caches the result.  The cached results are the direct group
memberships, not the complete set of nested groups.

Is what I want to do possible?  If so, can someone please point me in the
right direction?

Here is my slapd.conf file:
-----------------------------
### Logging
###################################################################
loglevel                -1
logfile /var/log/openldap.log

### Schema includes
###########################################################
include /etc/openldap/schema/microsoftattributetype.schema
include /etc/openldap/schema/microsoftattributetypestd.schema
include /etc/openldap/schema/corba.schema
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/duaconf.schema
include /etc/openldap/schema/dyngroup.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/java.schema
include /etc/openldap/schema/misc.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/ppolicy.schema
include /etc/openldap/schema/collective.schema
include /etc/openldap/schema/microsoftobjectclass.schema

## Module paths
##############################################################
modulepath              /usr/local/libexec/openldap
moduleload              back_meta
moduleload              back_ldap
moduleload              back_bdb
moduleload              mr_passthru
moduleload              pcache
moduleload              rwm

# Main settings
###############################################################
pidfile                 /var/run/openldap/slapd.pid
argsfile                /var/run/openldap/slapd.args

### Database definition (Proxy to AD)
#########################################
database                meta
chase-referrals yes
suffix                  "dc=some,dc=structure"
uri                     "ldap://a.b.c.d:3268/dc=some,dc=structure";
readonly                yes
protocol-version        3
rebind-as-user yes
rootdn "CN=zNexus,OU=Service Accounts,OU=myorg,DC=some,DC=structure"
rootpw "--obfuscated--"

idassert-bind binddn="CN=zNexus,OU=Service
Accounts,OU=myorg,DC=some,DC=structure"
                  credentials="--obfuscated--"
bindmethod=simple
mode=none
idassert-authzFrom "*"

rewriteEngine on
#rewrite searches
rewriteContext searchFilter
rewriteRule "member=(.*)" "(member:1.2.840.113556.1.4.1941:=%1" ":"
rewriteRule "memberOf=(.*)" "(memberOf:1.2.840.113556.1.4.1941:=%1" ":"

overlay pcache
pcache bdb 100000 2 10000 600
directory /var/tmp/openldap-cache
cachesize 20000
pcacheMaxQueries 10000
index objectClass                       eq,pres
index userAccountControl eq
index member eq
index memberOf eq
index ou,cn,mail,surname,givenname      eq,pres,sub
index objectCategory,sAMAccountName     eq,pres,sub


pcacheAttrset 0 cn
pcacheTemplate (&(objectClass=)(&(cn=)(member=))) 0 600 60
pcacheTemplate (member=) 0 600 60
pcacheTemplate (memberOf=) 0 600 60
pcacheTemplate (&(cn=*)(member=)) 0 600 60
pcacheTemplate
(&(objectClass=)(sAMAccountName=)(&(objectCategory=)(userAccountControl=)))
0 600 60

pcacheAttrset 1 sAMAccountName cn mail labeledUri memberOf member
objectClass
pcacheTemplate
(&(objectClass=)(sAMAccountName=)(&(objectCategory=)(userAccountControl=)))
1 600 60
pcacheTemplate
(&(objectClass=)(sAMAccountName=*)(&(objectCategory=)(userAccountControl=)))
1 600 60
-----------------------------

Here is what the client sees the first and second time the query is run for
a user that is directly in one group but in many groups via nesting.  (The
group DNs have been obfuscated but in reality they are all unique.)  On the
first run, ldapsearch correctly returns 158 total (nested and direct)
groups.  On the second run, ldapsearch only returns the one direct group.

### RUN 1 ###
ldap_initialize( ldap://127.0.0.1 )
filter: (member=cn=Some User,ou=Users,ou=External,dc=some,dc=structure)
requesting: cn
dn: cn=TT-RndGroup-Read,ou=...,ou=External,dc=some,dc=structure
cn: TT-RndGroup-Read

dn: cn=IO-RndGroup-Read,ou=...,ou=External,dc=some,dc=structure
cn: IO-RndGroup-Read

dn: cn=Vi-RndGroup-Read,ou=...,ou=External,dc=some,dc=structure
cn: Vi-RndGroup-Read

dn: cn=SE-RndGroup-Read,ou=...,ou=External,dc=some,dc=structure
cn: SE-RndGroup-Read

<snip 154 more CNs....>

real 0m14.167s
user 0m0.003s
sys 0m0.025s

### RUN 2 ###
ldap_initialize( ldap://127.0.0.1 )
filter: (member=cn=Some User,ou=Users,ou=External,dc=some,dc=structure)
requesting: cn
dn: cn=Vi-RndGroup-Read,ou=...,ou=External,dc=some,dc=structure
cn: Vi-RndGroup-Read


real 0m4.310s
user 0m0.000s
sys 0m0.004s

-----------------------------

Thanks,
Ryan

Reply via email to