Is there any way to use the idassert feature ONLY for anonymous connections,
while allowing all other binddns to be directly proxied as themselves?

I ask because we have root LDAP servers that have ACL configurations that work
for our purposes, and we don't want to change them. We also do not allow
anonymous binds to our root servers.  To be clear, we do not want to change
anything whatsoever on our root servers.

however, some clients do need to be able to bind anonymously.  We're ok with
this, as long as anonymous is allowed against LDAP proxies only, and not on our
root LDAP servers.  This way, we can control what anonymous user sees.

I am trying to make the proxy behave in the following ways:

  * authenticated non-admin Users may bind as themselves, they can see groups,
etc., (anything non-confidential) but can only see their own account (we have
this one working, but is an essential element of the larger picture)
  * anonymous users see all of the same non-sensitive material, but no user
accounts whatsoever
  * there are proxybind users in our DIT, one for read-ops and one for
write-ops.  The writer-proxybind user typically is needed for changing a users'
password, etc.  The read user is the one that performs lookups for strictly
read-only operations.  He can see all users.
  
If I set the idassert-bind to the read-only user, then no one can do writes.  If
i set it to the write-user, then everyone (even those who shouldn't) can do
writes (except anonymous, which is good).  The understanding I have is that we
should be setting the proxy user in slapd's proxy config to be the
highest-privileged user that we're ok with being "asserted".  For example, we're
not asserting to the rootdn or anything, rather we assert to a bind user that is
designed to read the very information that the proxy is designed to lookup.  

Here is our running config, though its been hacked up so much you should
understand its probably not perfect around the edges. Also ignore the comments
as they haven't been updated with the rest of the real parameters.

PS - I tried to upload as anonymous to your ftp and got this:

local: j-gropefruit-100114.txt remote: j-gropefruit-100114.txt
229 Entering Extended Passive Mode (|||60518|)
553 j-gropefruit-100114.txt: Permission denied.

So you'll just have to read it here:

###################################

include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/misc.schema
include /etc/ldap/schema/openldap.schema
include /etc/ldap/schema/duaconf.schema
include /etc/ldap/schema/dyngroup.schema
include /etc/ldap/schema/ppolicy.schema
include /etc/ldap/schema/sudo.schema
include /etc/ldap/schema/dhcp.schema
include /etc/ldap/schema/samba.schema
include /usr/share/doc/libpam-ldap/ldapns.schema
include /etc/ldap/schema/hdb.schema
include /etc/ldap/schema/uber.schema

pidfile         /var/run/slapd/slapd.pid
argsfile        /var/run/slapd/slapd.args

loglevel        stats stats2 conns parse
idletimeout	0

sizelimit	unlimited
timelimit	unlimited

defaultsearchbase	dc=fake,dc=example,dc=com

limits dn.regex="^uid=([^,]+).,cn=plain,*"
   time.soft=unlimited
   time.hard=unlimited
   size.soft=unlimited
   size.hard=unlimited

access to dn.base=""
  by * read

access to dn.base="cn=Subschema"
  by * read

## Load modules here

modulepath	/usr/lib/ldap
moduleload	back_relay
moduleload	back_ldap
moduleload	back_hdb
moduleload	pcache
moduleload	rwm.la

## SSL/TLS

TLSCertificateFile	/etc/ldap/ssl/wildcard.fake.example.com.crt
TLSCertificateKeyFile	/etc/ldap/ssl/wildcard.fake.example.com.key
TLSCACertificateFile	/etc/ldap/ssl/wildcard.fake.example.com.pem

## This is for SASL/GSSAPI authentication

sasl-realm	FAKE.EXAMPLE.COM
sasl-host	ds-fake-int.fake.example.com
authz-regexp	"uid=\(.*\),cn=FAKE.EXAMPLE.COM,cn=gssapi,cn=auth"
		"uid=$1,cn=plain,cn=auth,dc=real,dc=example,dc=com"
authz-regexp	"uid=\(.*\),cn=DEV.EXAMPLE.COM,cn=gssapi,cn=auth"
		"uid=$1,cn=plain,cn=auth,cn=dev,dc=real,dc=example,dc=com"

## Define the actual 'database', as referenced by the suffix.

database        ldap
uri		ldaps://10.9.8.7:636/
suffix          "dc=real,dc=example,dc=com"
rootdn          "uid=rootdn,cn=plain,cn=auth,dc=real,dc=example,dc=com"
overlay	rwm
rwm-rewriteEngine on
# all dataflow from server to client
rwm-rewriteContext searchEntryDN
rwm-rewriteRule "(.+,)?dc=real,dc=example,dc=com$"
"$1dc=fake,dc=example,dc=com"

## When proxying information, configure what identity to assert.

#acl-bind
#   bindmethod="simple"
#   binddn="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com"
#   credentials="pass"
#  starttls="no"
#  tls_reqcert="never"

idassert-bind
   bindmethod="simple"
   binddn="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com"
   credentials="pass"
   starttls="no"
   tls_reqcert="never"
   mode="legacy"
   flags="override,non-prescriptive"

idassert-authzFrom "dn.subtree:cn=plain,cn=auth,dc=real,dc=example,dc=com"
idassert-authzFrom "dn.subtree:cn=plain,cn=auth,dc=real,dc=example,dc=com"
idassert-authzFrom "dn.exact:"

chase-referrals	NO
rebind-as-user	NO

## Cache data for PERFORMANCE - this only works when the upstream proxy 
## is online.  There's no way to cache data in its entirety if the provider
## goes down (that's what actual replication is for).

overlay			pcache
proxycache		hdb 2000 5 100 1800
directory       	"/var/lib/ldap/cache"
dbconfig                set_cachesize 0 4097152 0
dbconfig                set_lg_regionmax 1048576
dbconfig                set_lg_max 1048576
dbconfig                set_lg_dir /var/lib/ldap/cache
dbconfig                set_tmp_dir /tmp
index			uid,cn,sn,givenName					eq,sub
index			uidNumber,gidNumber					eq
index			homeDirectory,loginShell,gecos,objectClass		eq
proxycachequeries 	10000
proxyattrset		0 uid userPassword uidNumber gidNumber cn homeDirectory loginShell
gecos description objectClass
proxytemplate		(&(objectclass=)(uidNumber=)) 0 1200
proxytemplate		(&(objectclass=)(uid=)) 0 1200
proxyattrset		1 objectclass
proxytemplate		(objectclass=) 1 1200
proxyattrset		2 uid
proxytemplate		(uid=) 2 1200
proxyattrset		3 cn nisNetgroupTriple memberNisNetgroup
proxytemplate		(&(objectClass=)(cn=)) 3 1200
proxyattrset		4 gidNumber
proxytemplate		(&(objectClass=)(memberUid=)) 4 1200

## Set a global rule to allow everything to our service/proxy users, then
forbid
## all others access, but BREAK the rule so it keeps processing the rest of the
rules,
## which are all much less-permissive ...

access to dn.subtree="dc=real,dc=example,dc=com"
   by group/groupOfUniqueNames/uniqueMember="cn=ldapadmin,cn=ldap,cn=groups,dc=real,dc=example,dc=com"
write
   by dn.regex="^uid=plain\(modify|change\),cn=plain,cn=auth,dc=real,dc=example,dc=com"
write
   by dn.regex="^uid=plain\(proxy|agent\),cn=plain,cn=auth,dc=real,dc=example,dc=com"
read
   by * none break

access to attrs=userPassword
   by self =w
   by * =x

## OMFGZZZZ the Solipsism rule - if you touch this I will kill you.
## This fixes the MUST-BIND-AS-SELF logic problem with Sun VDI

access to dn.regex="^uid=([^,]+),cn=plain,cn=auth,dc=real,dc=example,dc=com"
   by dn.base,expand="uid=$1,cn=plain,cn=auth,dc=real,dc=example,dc=com" read
   by * none break

########## Relay Instance for the "fake" zone

database                        relay
suffix                          dc=fake,dc=example,dc=com
relay                           dc=real,dc=example,dc=com
overlay                         rwm
rwm-suffixmassage               dc=real,dc=example,dc=com
rwm-rewriteEngine               on
rwm-normalize-mapped-attrs      yes
rwm-rewriteContext searchAttrDN
rwm-rewriteRule "(.+,)?dc=real,dc=example,dc=com$"
"$1dc=fake,dc=example,dc=com"

access to dn.subtree="dc=fake,dc=example,dc=com"
   by group/groupOfUniqueNames/uniqueMember="cn=ldapadmin,cn=ldap,cn=groups,dc=real,dc=example,dc=com"
write
   by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com"
read
   by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com"
read
   by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read
   by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read
   by * none break

access to dn.children="cn=plain,cn=auth,dc=fake,dc=example,dc=com"
 attrs=userPassword
  filter=(&(uid=*)(|(objectClass=posixAccount)(objectClass=simpleSecurityObject)(objectClass=shadowAccount)(objectClass=inetOrgPerson)(objectClass=account)))
   by self write
   by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com"
write
   by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com"
write
   by anonymous auth
   by * none break

access to dn.children="cn=plain,cn=auth,dc=fake,dc=example,dc=com"
  filter=(&(uid=*)(|(objectClass=posixAccount)(objectClass=simpleSecurityObject)(objectClass=shadowAccount)(objectClass=inetOrgPerson)(objectClass=account)))
   by self read
   by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com"
read
   by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com"
read
   by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read
   by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read
   by * none break

access to dn.subtree="cn=groups,dc=fake,dc=example,dc=com"
  filter=(|(objectClass=posixGroup)(objectClass=nisNetgroup)(objectClass=groupOfUniqueNames)(objectClass=groupOfNames)(objectClass=organizationalRole))
   by dn.exact="uid=plainmodify,cn=plain,cn=auth,dc=real,dc=example,dc=com"
read
   by dn.exact="uid=plainchange,cn=plain,cn=auth,dc=real,dc=example,dc=com"
read
   by dn.exact="uid=plainagent,cn=plain,cn=auth,dc=real,dc=example,dc=com" read
   by dn.exact="uid=plainproxy,cn=plain,cn=auth,dc=real,dc=example,dc=com" read
   by anonymous read
   by * none break

access to dn.onelevel="cn=gssapi,cn=auth,dc=fake,dc=example,dc=com"
   by dn="uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth" read
   by * none break

access to dn.onelevel="cn=FAKE.EXAMPLE.COM,cn=gssapi,cn=auth,dc=fake,dc=example,dc=com"
   by dn="uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth" write
   by * none break

access to dn.subtree="cn=sys,dc=fake,dc=example,dc=com"
   by * read

access to dn.subtree="cn=tester,dc=fake,dc=example,dc=com"
   by * read

access to dn.subtree="cn=dev,dc=fake,dc=example,dc=com"
   by * none

access to dn.subtree="cn=elements,dc=fake,dc=example,dc=com"
   by * none
###################################

The man pages and examples on OpenLDAP.org have helped tremendously, but I need some
living & breathing opinions.  Thanks

J