Many Shibboleth IdP adopters use LDAP as an authentication provider and an attribute source. There is always the question of "do we need to configure TLS/SSL for the IdP's connection to the LDAP server(s)?" My response is "always," because we need to protect the user's credentials even in the most trusted network. My question back to the client is, "Why wouldn't you?" Often the response is somewhere between "we've tried and we got it to work once, but then it broke sometime" and "we could never get it to work." My goal with this post is to take the mystery out of configuring the IdP to use TLS when connecting to an LDAP Server. It should be noted that all of these concepts apply to things like CAS Server as well.
TLS Connection Types
The IdP supports two TLS connection types. The first is straight TLS, and is usually called SSL in the IdP configs, etc. This is generally what we think about when we think of SSL (now deprecated) and TLS. With straight TLS (or SSL), the LDAP Server has a dedicated port for the TLS connection. Usually, it is TCP/636. A typical connection config in conf/ldap.properties would look like:
## Connection properties ## idp.authn.LDAP.ldapURL = ldaps://ldap.organization.edu:636 idp.authn.LDAP.useStartTLS = false idp.authn.LDAP.useSSL = true
The ldapURL protocol is changed to "ldaps" and the port set to ":636". useStartTLS is set to "false" and useSSL is set to "true".
The second connection type is called StartTLS. With StartTLS, the connection starts out as clear text communication over the standard port (TCP/389). The client tells the LDAP Server to convert the session to a secure TLS connection, and TLS negotiation starts up like it does under a standard TLS-only connection. Personally, I like StartTLS because you can use the same TCP port for both clear text and secured traffic. It makes firewall rules much easier, but alas, because it requires protocol enhancements to the widely adopted spectrum of Internet services, it didn't gain much traffic... But many LDAP servers do support it. The config looks something like:
## Connection properties ## idp.authn.LDAP.ldapURL = ldap://ldap.organization.edu:389 idp.authn.LDAP.useStartTLS = true idp.authn.LDAP.useSSL = false
The ldapURL protocol is "ldap" and the port set to ":389", or just left off altogether. useStartTLS is set to "true" and useSSL is set to "false".
Trust Types
So now that we have told the IdP's LDAP client to use TLS, when it connects the LDAP server is going to present one or more X.509 certificates. The server's certificate is used to identify the server and contains additional information about the certificates validity period. Unless the certificate is self-signed, the certificate also has a signer that is used to link to another certificate. These additional certificates form a chain back to a certificate authority's (CA) root certificate. Windows, browsers and even the Oracle JVM come with a set of trusted root CAs pre-installed. The IdP's LDAP client usually needs to be told what certificate to trust. This can either be the server's certificate or the CA that signed the server certificate's root certificate. I prefer to use the CA root cert since that allows the LDAP Server Admin to revoke, renew, etc the LDAP server cert without affecting the IdP... as long as the CA does not change its root certificate.
Either way, sometimes getting these certificates from the LDAP Admin can be difficult. So here's an easy way to get them.. use OpenSSL:
openssl s_client -connect ldap.organization.edu:636 -showcerts
This will dump a bunch of stuff, but what we are concerned about are the big blocks of text that start and end with "-----". Each one of those blocks is a certificates in PEM format. The first one will usually be the server certificate. The last one is usually the root. You can tell a root certificate because the issuer and the "s:" and "i:" values before it are the same. If the LDAP server uses a self-signed certificate, then there will just be one entry and the "s:" and "i:" will be the same. Here's an example of the root cert response currently used by standard InCommon certs:
s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE-----
Which ever certificate style you want to use, grab the appropriate block. Be sure to include the "-----" lines at the beginning and end of the block. Save it to a file. Next, you need to tell the IdP where the file is stored. By default, the IdP will look in "%{idp.home}/credentials/ldap-server.crt". I would recommend placing the file there. Maybe you want to change the name, particularly if you are using a root. You can change the path by changing trustCertificates in "conf/ldap.properties".
## SSL configuration, either jvmTrust, certificateTrust, or keyStoreTrust #idp.authn.LDAP.sslConfig = certificateTrust ## If using certificateTrust above, set to the trusted certificate's path idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt ## If using keyStoreTrust above, set to the truststore path idp.authn.LDAP.trustStore = %{idp.home}/credentials/ldap-server.truststore
You maybe noticing the trustStore property. Well that's the method that uses the Java Keystore technology that I blame for stumping many TLS/SSL configurers. If you want to use that method, go for it, but I'm not going to tell you how, because using the PEM file is way, way easier than anything with the keystore. Just trust me... If you do want to self-inflict pain and use the keystore method (against my advice) you'll want to uncomment the sslConfig property and set it to "keyStoreTrust" and point the trustStore property to that keystore.
Hopefully, you can see that configuring the Shibboleth IdP (or CAS Server 4.1+)'s LDAP connection to use TLS is very straight forward and will only take you a few minutes of effort.