Thursday 1 August 2013

OpenLDAP ldap backend: SASL authentication

The problem

The OpenLDAP ldap backend acts as a reverse proxy to a LDAP server containing real data. The simple binds are simply verbatim transferred to the data server and users don't even feel there is a proxy in-between.
The problem is with SASL. With a SASL bind the proxy doesn't have a password to forward to the data server. Even if proxy authenticates user with GSSAPI or EXTERNAL, proxy obtains a dn but no password. So it has to perform an anonymous bind which is different from an authenticated one. This behaviour is warned by the log line:
ldap_back_dobind_int: DN="cn=admin,dc=example,dc=org" without creds, binding anonymously

Overview

The solution uses the id_assert directive in the ldap badabase section on the proxy in order to bind to the data server with a defined principal who then proxies to the original client identity thanks to the authzTo attribute.
The OpenLDAP need three modifies:
  • id_assert section in ldap database (proxy server)
  • creation of the id_assert principal with the authzTo attribute (data server)
  • enable authzPolicy to in cn=config (data server)

ldifs needed

To enable authzPolicy on the data server: This is necessary because OpenLDAP disregards authzTo attribute in a entry unless the global olcAuthzPolicy is set.
To enable id_assert on ldap database on proxy server: The id_assert is in effect only for authenticated users to avoid using a privileged bind for anonymous users.
The proxy user is defined as follow:

Check log entries

This is a log entry for the user "a_user" bound with GSSAPI requesting his own entry:
Log on proxy:
Log on data server: Note bind is performed by cn=proxy,ou=agents,dc=example,dc=org but then authorization is performed on behalf to "a_user".

Wednesday 24 July 2013

OpenLDAP ldap backend as a proxy

Ldap backend works as a proxy: when a client searches data, proxy forwards request to ldap servers with real data, which are served to client. This is useful for:
  • high availability: ldap backend spots faulty servers and picks the first working in a list
  • firewalling: clients connect to a single IP no matter how many ldap server are involved.
Before using ldap backend, you have to enable it: create a ldif named 'add_module_ldap.ldif' and apply with: sudo ldapadd -H ldapi:/// -Y EXTERNAL -f add_module_ldap.ldif Now you are ready to create to database by inserting the following ldif. Now queries matching the basename "dc=example,dc=org" are forwarded to the first available server between ldap1.example.org or ldap2.example.org. The proxy might take some time to spot faulty server (maybe it has to wait for a timeout), but since the next call it forwards to the last used server, the first working one. Please note:
  • the "allow all" acl is required because ldap backend perform authorization. A request is fulfilled if both the proxy and the data server allow it. Serious acl are supposed to be on the data server only (it helps sanity);
  • remember to encrypt connection between proxy and data server with 'olcDbStartTLS: start'

Tuesday 23 July 2013

pkcs11 ssh authentication

This post is about using ssh without password, with a certificate stored on a smartcard. I think it could be really useful with notebooks. You can securely connect to ssh servers without storing the ssh secret key on the notebook, which can be stolen, can be lost etc.

Setup

Of course you have to be able to read the certificate on the smartcard so:
  • get a smartcard reader; be sure it is supported. We lost a lot of time because ACR38UR didn't work (ACR38UC works fine);
  • install pcscd;
  • get the crypto api for yor smartcard. 'opensc' should work fine, sometimes the certificate issuer require other libraries (Italian CNS work with libbit4ipki.so -- you can find it with the software 'dike').

Get public keys

$ ssh-keygen -D /usr/lib/libbit4ipki.so
ssh-rsa AAAAB3NzaC1yc2[...]J6KIcjjROKtdJ2CHOftZExSkNyNNQ==
ssh-rsa AAAAB3NzaC1yc2[...]kRxbZfOVWb8X5C4X++iiXS4UDpWhQ==
Copy one of the line beginning with "ssh-rsa" to the '.ssh/authorized_keys' on the ssh server (chmod 600).

Load private keys

$ ssh-agent /bin/bash
$ ssh-add -s /usr/lib/libbit4ipki.so
Enter passphrase for PKCS#11:
Card added: /usr/lib/libbit4ipki.so
$ ssh-add -l
1024 f8:8a:e3:[...]:cb:ab:db:67:da:3e /usr/lib/libbit4ipki.so (RSA)
1024 bc:9f:e9:[...]:27:7a:13:55:81:bf /usr/lib/libbit4ipki.so (RSA)
Then you can happily login to ssh server with a simple ssh command.

Wednesday 10 July 2013

OpenLDAP: force TLS on authentication only

Imagine your directory has public data which can be accessed anonymously. Suppose there are also confidential data whose access requires authentication.

You want authenticated access to be on the secure channel (to protect both password and data from sniffing) while you don't want to enforce TLS to anonymous access to public data (maybe some clients are hard to configure properly for TLS).

Setting:
olcSecurity: ssf=36
in cn=config would require all user to use TLS: otherwise OpenLDAP issues a "confidentiality required" error. This setting is maybe overkill.

TLS can be enforced with ACL as well.

Create a ldif file named "add_tls_for_auth.ldif" as following: and apply to config with:
ldapmodify -H ldapi:/// -Y EXTERNAL -f add_tls_for_auth.ldif
(this code assumes the default acl setup by Debian).

Explanation

The break keyword means that if you match that rule you should check next rule for the same what. So, if your ssf is strong enought or your IP is 127.0.0.1 you are allowed to check next rule about access to attrs=userPassword,shadowLastChange. Otherwise the none means userPassword is not returned so no authentication can ever succeed.
In short the break keyword is a kind on logical AND between two rules.

Notes

There are two points to note:
  • Users are still allowed to try connection with clear text password on ldap://. Simply authntication never succeed so in a while they should stop;
  • To enable ldapi:/// authenticated connection you might need to set olcLocalSSF=128 in cn=config:

Tuesday 2 July 2013

Basic setup in Debian slapd package

After issuing apt-get install slapd a few steps are required in order to:
  • change basename suffix;
  • enable logging;
  • speed up admin authentication.
The Debian version is release 7 Wheezy.

Change basename suffix

Package creates a database with suffix aligned to domain name. Domain name is read from /etc/resolv.conf or the like. If you want to change it, the dpkg command can help you:
sudo dpkg-reconfigure slapd
The second time you can choose the domain name.

Enable logging

To enable logging, create a ldif modify file:
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: Stats
name it enable_log.ldif and apply to openLDAP with:
sudo ldapmodify -H ldapi:/// -Y EXTERNAL -f enable_log.ldif
Next ensure slapd sends log to a facility, for example local6. This is done in /etc/default/slapd:
# Additional options to pass to slapd
SLAPD_OPTIONS="-l local6"
(then restart slapd). By the way, to avoid filling the hard drive with openldap log, instruct logrotate to handle them: drop in /etc/logrotate.d/ a file called 'ldap':
/var/log/ldap.log
{
       rotate 90
       daily
       missingok
       notifempty
       delaycompress
       compress
}

Speed up admin authentication

In order to avoid typing admin password to populate directory, authorize SASL/EXTERNAL with root access to do that. Create a ldif file (enable_sasl_acl.ldif):
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external
 ,cn=auth manage by * break
and switch it on with:
sudo ldapmodify -H ldapi:/// -Y EXTERNAL -f enable_sasl_acl.ldif
Now you are able to add ou, users and groups without password as long you are root, with '-H ldapi:/// -Y EXTERNAL' switch.

Monday 24 June 2013

Securing the ActiveMQ 5.8.0 web console using LDAP based authentication with Ldaptive

This is a follow-up of the great post by Torsten Mielke, updated for the 5.8.0 activemq release with the great ldaptive ldap java library.
First of all, drop the ldaptive.jar in the ${activemq-home}/lib directory.
Next you need to edit two files:
  • login.config
  • jetty.xml
In jetty.xml, the key task is to substitute to the default securityLoginService based on a org.eclipse.jetty.security.HashLoginService a section like: where jetty-ldap has to match the label in login.config, and roleClassNames match the class role exported by ldaptive.
The property 'roles' should include the group names from ldap which define if a member is allowed to access web console. In this example, a user should be a member of the admins group.
Please note identityService has to be present even if it is default.
The login.config is: ldap1 and ldap2 are contacted via start_tls, with a ACTIVE_PASSIVE strategy, the groups are in the ou=groups,dc=test,dc=com and a authentication principal is required to browse them. "storepass=true" in the LdapLoginModule is required in order to allow to the filter 'memberUid={user}' to resolve the {user} placeholder.

The hardest part of this setup is the role mapping from group membership. These errors show up with the following error in web console following a successful login:
Problem accessing /. Reason:      !role
In this example groups/role mappings are in web.xml. They could be done in login.config as well with the following lines:
            roleFilter="(&(cn=admin_group)(memberUid={user}))"
     defaultRole="admin" 
If a user matches the filter (she's member of the admin_group group) is added to the admin role which in turn should match the roles property in securityConstraints.

The following lines in your logback.xml can help you a lot to spot errors:
Link to the complete jetty.xml.
Ldaptive jaas guide.

Thursday 23 May 2013

ldaptive 1.0 test

ldaptive is a java ldap library which replaces vt-ldap shipped with shibboleth and grouper.

There are some nice surprises, like the handling of the ldap extended operation of Password Modify and Password Policy, used by openldap to check if a user's password is locked or need to be changed.

I have tried a ldapsearch authenticated with SASL TLS/EXTERNAL:


Please note that the private key password (the one you set to create the pkcs12) and the keystore password have to be the same.

Friday 15 February 2013

Convert a openssl PEM RSA key to java keystore

Starting from jdk6, keytool allows importing pkcs12 bundles. The pkcs12 bundle includes key, certificate and CA chain so it is possible to require a certificate with openssl than using it with activemq, or other java projects.

The procedure is outlined the jetty ssl page, but there is a important point to note.

The keystore is password protected with the password set during keystore creation. The private key is password protected with the export password typed in openssl pkc12 command.

If a tool doesn't allow to specify both password, they must be the same.

The case is the activemq sslContext, which reads:

<sslContext>
                <sslContext 
                        keyStore="ateneo.store" keyStorePassword="bluehorror"
                        trustStore="client.ks" trustStorePassword="password"/>
        </sslContext>
The trick is to issue a keytool -keypasswd to align password. Failing to do that results in a:
Exception in thread "main" java.security.UnrecoverableKeyException: Cannot recover key
 at sun.security.provider.KeyProtector.recover(KeyProtector.java:311)
 at sun.security.provider.JavaKeyStore.engineGetKey(JavaKeyStore.java:121)
 at sun.security.provider.JavaKeyStore$JKS.engineGetKey(JavaKeyStore.java:38)
 at java.security.KeyStore.getKey(KeyStore.java:763)
Thanks to http://www.xinotes.org/notes/note/1395/

In case you want to follow the single steps, have a look at the puppet module to automatize certs export to keystore: https://github.com/francescm/certs