[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: Certificate authentication and back-ldap proxy



> Hi,
>
>    We have some problems with certificate authentication when the master
> server is behind a back-ldap proxy.
>
>    We have openldap 2.4.21 on Suse Linux Enterprise Server  10 SP3 and
> these are the details of our scenario:
>
>    The master server: server1.example.com has the following slapd.conf
> file:
>
> access to dn.base=""
>         by * read
>
> access to dn.base="cn=Subschema"
>         by * read
>
> access to attrs=userPassword,userPKCS12
>         by self write
>         by dn.exact="CN=admin_w_cert,O=Internet Widgits Pty
> Ltd,ST=Some-State,C=AU" read
>         by *
> auth
>
> access to attrs=shadowLastChange
>         by self write
>         by * read
>
> access to *
>         by * read
>
> #
> # Security SSL
> #
> TLSCipherSuite HIGH:MEDIUM:+SSLv3
> TLSCertificateFile /etc/ssl/certs/server1.example.com.pem
> TLSCertificateKeyFile /etc/ssl/private/server1.example.com.key
> TLSCACertificatePath /etc/ssl/cacerts/
> TLSVerifyClient demand
>
> #
> #Log level
> #
> loglevel 256
>
> # Require authentication
> require authc
>
> #######################################################################
> # HDB database definitions
> #######################################################################
>
> database        hdb
> suffix          "dc=example,dc=com"
> checkpoint      1024    5
> cachesize       10000
> rootdn          "cn=Manager,dc=example,dc=com"
>
> rootpw          secret
>
> # Indices to maintain
> index   objectClass     eq
>
> # Overlay ppolicy
> overlay ppolicy
>
> ----------------------
>
>    Authentication is required, and we give access to the user passwords
> for the dn of a certificate.
>
>    When we search for passwords using the certificate we get the
> following:
>
> root# ldapsearch -LLL -b 'uid=user_w_pass,ou=people,dc=example,dc=com'
> -H ldaps://server1.example.com userPassword
>
> SASL/EXTERNAL authentication started
> SASL username: CN=admin_w_cert,O=Internet Widgits Pty
> Ltd,ST=Some-State,C=AU
> SASL SSF: 0
> dn: uid=user_w_pass,ou=people,dc=example,dc=com
> userPassword:: e2NyeXB0fTcyMXpQbU4waWdKaU0=
>
> -----------------------
>
>   The root user (ldap client) has a ~/.ldaprc file with:
> TLS_CACERTDIR /etc/ssl/cacerts/
> TLS_CERT /etc/ssl/certs/admin_w_cert.pem
> TLS_KEY /etc/ssl/private/admin_w_cert.key
> TLS_REQCERT demand
> SASL_MECH EXTERNAL
>
>    In /var/log/messages we get:
> ldap-master[22358]: conn=1000 fd=11 ACCEPT from
> IP=server1.example.com:40899 (IP=server1.example.com:636)
> ldap-master[22358]: conn=1000 fd=11 TLS established tls_ssf=256 ssf=256
> ldap-master[22358]: conn=1000 op=0 BIND dn="" method=163
> ldap-master[22358]: conn=1000 op=0 BIND
> authcid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> authzid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> ldap-master[22358]: conn=1000 op=0 BIND dn="cn=admin_w_cert,o=internet
> widgits pty ltd,st=some-state,c=au" mech=EXTERNAL sasl_ssf=0 ssf=256
> ldap-master[22358]: conn=1000 op=0 RESULT tag=97 err=0 text=
> ldap-master[22358]: conn=1000 op=1 SRCH
> base="uid=user_w_pass,ou=people,dc=example,dc=com" scope=2 deref=0
> filter="(objectClass=*)"
> ldap-master[22358]: conn=1000 op=1 SRCH attr=userPassword
> ldap-master[22358]: conn=1000 op=1 SEARCH RESULT tag=101 err=0
> nentries=1 text=
> ldap-master[22358]: conn=1000 op=2 UNBIND
> ldap-master[22358]: conn=1000 fd=11 closed
>
>    This is the correct behavior for us. The problem appears when we
> introduce a back-ldap proxy between the client and the master.
>    The proxy server (proxy-server1.example.com) is listening in port
> 1636 and its slapd.conf file is:
>
> #
> # Security SSL
> #
> TLSCipherSuite HIGH:MEDIUM:+SSLv3
> TLSCACertificatePath /etc/ssl/cacerts/
> TLSCertificateFile /etc/ssl/certs/proxy-server1.example.com.pem
> TLSCertificateKeyFile /etc/ssl/private/proxy-server1.example.com.key
> TLSVerifyClient demand
>
> # Log level
> loglevel 256
>
> #######################################################################
> # Database definitions
> #######################################################################
> database        ldap
>
> rebind-as-user  true
>
> suffix          "dc=example,dc=com"
>
> uri             "ldaps://server1.example.com"
> tls             ldaps
>                 tls_cert=/etc/ssl/certs/proxy-server1.example.com.pem
>                 tls_key=/etc/ssl/private/proxy-server1.example.com.key
>                 tls_cacertdir=/etc/ssl/cacerts/
>
> ----------------------
>
>    If we search for passwords through the proxy we get:
> root # ldapsearch -LLL -b 'uid=user_w_pass,ou=people,dc=example,dc=com'
> -H ldaps://proxy-server1.example.com:1636 userPassword
>
> SASL/EXTERNAL authentication started
> SASL username: CN=admin_w_cert,O=Internet Widgits Pty
> Ltd,ST=Some-State,C=AU
> SASL SSF: 0
> Server is unwilling to perform (53)
> Additional information: authentication required
>
>     In the /var/log/messages the following messages appear:
> ldap-proxy[22802]: conn=1001 fd=8 ACCEPT from
> IP=proxy-server1.example.com:60712 (IP=proxy-server1.example.com:1636)
> ldap-proxy[22802]: conn=1001 fd=8 TLS established tls_ssf=256 ssf=256
> ldap-proxy[22802]: conn=1001 op=0 BIND dn="" method=163
> ldap-proxy[22802]: conn=1001 op=0 BIND
> authcid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> authzid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> ldap-proxy[22802]: conn=1001 op=0 BIND dn="cn=admin_w_cert,o=internet
> widgits pty ltd,st=some-state,c=au" mech=EXTERNAL sasl_ssf=0 ssf=256
> ldap-proxy[22802]: conn=1001 op=0 RESULT tag=97 err=0 text=
> ldap-proxy[22802]: conn=1001 op=1 SRCH
> base="uid=user_w_pass,ou=people,dc=example,dc=com" scope=2 deref=0
> filter="(objectClass=*)"
> ldap-proxy[22802]: conn=1001 op=1 SRCH attr=userPassword
>
> ldap-master[22358]: conn=1008 op=2 SRCH
> base="uid=user_w_pass,ou=people,dc=example,dc=com" scope=2 deref=0
> filter="(objectClass=*)"
> ldap-master[22358]: conn=1008 op=2 SRCH attr=userPassword
> ldap-master[22358]: conn=1008 op=2 SEARCH RESULT tag=101 err=53
> nentries=0 text=authentication required
>
> ldap-proxy[22802]: conn=1001 op=1 SEARCH RESULT tag=101 err=53
> nentries=0 text=authentication required
> ldap-proxy[22802]: conn=1001 op=2 UNBIND
> ldap-proxy[22802]: conn=1001 fd=8 closed
>
>    The /root/.ldaprc file is the same than the previous one.
>
>    When we increase the logging level we discover this:
> ....
> ldap-proxy[23008]: conn=1000 op=0 do_bind
> ldap-proxy[23008]: >>> dnPrettyNormal: <>
> ldap-proxy[23008]: <<< dnPrettyNormal: <>, <>
> ldap-proxy[23008]: conn=1000 op=0 BIND dn="" method=163
> ldap-proxy[23008]: do_bind: dn () SASL mech EXTERNAL
> ldap-proxy[23008]: ==> sasl_bind: dn="" mech=EXTERNAL datalen=0
> ldap-proxy[23008]: SASL Canonicalize [conn=1000]:
> authcid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> ldap-proxy[23008]: slap_sasl_getdn: conn 1000
> id=cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au [len=61]
> ldap-proxy[23008]: ==>slap_sasl2dn: converting SASL name
> cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au to a DN
> ldap-proxy[23008]: <==slap_sasl2dn: Converted SASL name to <nothing>
> ldap-proxy[23008]: SASL Canonicalize [conn=1000]:
> slapAuthcDN="cn=admin_w_cert,o=internet widgits pty
> ltd,st=some-state,c=au"
> ldap-proxy[23008]: SASL proxy authorize [conn=1000]:
> authcid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> authzid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> ldap-proxy[23008]: conn=1000 op=0 BIND
> authcid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> authzid="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> ldap-proxy[23008]: SASL Authorize [conn=1000]:  proxy authorization
> allowed authzDN=""
> ldap-proxy[23008]: send_ldap_sasl: err=0 len=-1
> ldap-proxy[23008]: conn=1000 op=0 BIND dn="cn=admin_w_cert,o=internet
> widgits pty ltd,st=some-state,c=au" mech=EXTERNAL sasl_ssf=0 ssf=256
> ldap-proxy[23008]: do_bind: SASL/EXTERNAL bind:
> dn="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> sasl_ssf=0
> ldap-proxy[23008]: send_ldap_response: msgid=1 tag=97 err=0
> ldap-proxy[23008]: conn=1000 op=0 RESULT tag=97 err=0 text=
> ldap-proxy[23008]: <== slap_sasl_bind: rc=0
> ....
> ldap-proxy[23008]: conn=1000 op=1 SRCH
> base="uid=user_w_pass,ou=people,dc=example,dc=com" scope=2 deref=0
> filter="(objectClass=*)"
> ldap-proxy[23008]: conn=1000 op=1 SRCH attr=userPassword
> ldap-proxy[23008]: ==> limits_get: conn=1000 op=1
> self="cn=admin_w_cert,o=internet widgits pty ltd,st=some-state,c=au"
> this="uid=user_w_pass,ou=people,dc=example,dc=com"
> ldap-master[22983]: daemon: activity on 1 descriptor
> ldap-master[22983]: daemon: activity on:
> ldap-master[22983]:
> ldap-master[22983]: slap_listener_activate(7):
> ldap-master[22983]: daemon: epoll: listen=7 busy
> ldap-master[22983]: >>> slap_listener(ldaps://server1.example.com)
> .....
> ldap-master[22983]: conn=1000 op=0 do_bind
> ldap-master[22983]: >>> dnPrettyNormal: <>
> ldap-master[22983]: <<< dnPrettyNormal: <>, <>
> ldap-master[22983]: conn=1000 op=0 BIND dn="" method=128
> ldap-master[22983]: do_bind: version=3 dn="" method=128
> ldap-master[22983]: send_ldap_result: conn=1000 op=0 p=3
> ldap-master[22983]: send_ldap_result: err=0 matched="" text=""
> ldap-master[22983]: send_ldap_response: msgid=1 tag=97 err=0
> ldap-master[22983]: conn=1000 op=0 RESULT tag=97 err=0 text=
> ldap-master[22983]: do_bind: v3 anonymous bind
>
> ----------------
>
> Therefore the proxy is binding anonymously in the master, instead of
> using the dn of the certificate.
>
> Is there any  problem with the SASL EXTERNAL method?
>
> If we use SIMPLE authentication through the proxy, there is no problem:
> root # ldapsearch -LLL -x -b
> 'uid=user_w_pass,ou=people,dc=example,dc=com' -H
> ldaps://proxy-server1.example.com:1636 -D
> 'uid=user_w_pass,ou=people,dc=example,dc=com' -W  userPassword
> Enter LDAP Password:
>
> dn: uid=user_w_pass,ou=people,dc=example,dc=com
> userPassword:: e2NyeXB0fTcyMXpQbU4waWdKaU0=

The problem is that you probably do not realize that the proxy cannot do a
cert-based authentication on behalf of the client because it doesn't have
the client's private key (which is correct).  You need the proxy perform
an identity assertion: bind to the remote server with its own identity,
and then assert the client's identity using proxy authorization.

To do this, you need to:

a) define some means for the proxy to bind to the remote server, e.g.
using cert-based SASL EXTERNAL, or simple bind under TLS, or whatever;

b) configure the remote server so that the proxy's identity defined in (a)
is allowed to proxy authz as whatever client's identity you want to
accept; this requires to use the directive "authz-policy"; you may need to
use the "authz-regexp" if you intend to map the client's identity; and
you'll need to populate the "authzTo" operational attribute of the entry
corresponding to the proxy's identity.

c) add to the proxy configuration the directive

idassert-bind bindmethod=<what you chose for (a)>
    <bind parameters for (a)>
    mode=self

This way, the proxy will:

- authc the client locally

- authc as itself with respect to the remote host

- proxy operations adding the proxyAuthz control with the identity of the
client

See slapd-ldap(5) for details on the syntax of the idassert-* directives.

p.