1

I am working on a third party Java application for which I need to authenticate its users using Active Directory.

This application is hosted on RHEL 6.5, and uses LDAP to authenticate with Windows Active Directory. The AD server has been set up, and is working fine with an earlier version of the application (which was configured to enable the integration).

For the newer version, the vendor has laid out some steps to modify/configure the application files to connect with the AD server, and which are expected to help us authenticate.

The application has one of its component as CAS, which is currently configured to use database as its authentication handler. When we enter the credentials - username: abcd, password: samplepswd, we are able to login successfully.

As the business requirement is that of authentication with Active Directory using LDAP, we have to modify the CAS properties file. As per instructions from the product vendor, we have changed the following properties to use ldap -

authenticationHandler.type=ldap
ldapSSLConfig.enabled=false
ldapContextSource.url=ldap://sample.ADserver.example.net:389
ldapContextSource.userDn=abcd
ldapContextSource.password=samplepswd
ldapAuthenticationHandler.filter=uid=%u
ldapAuthenticationHandler.searchBase=OU=DEF,OU=PQR,OU=XYZ,DC=ADserver,DC=example,DC=net

We also need to make changes in the casAuthConfig xml file for the following properties (as anonymous search is not supported): 1. anonymousReadOnly, value is set to false 2. java.naming.security.authentication, value is set to simple

There is provision to use ldap over SSL as well, but currently we are not using that. However, if we do use SSL, additional changes have to be made to the following properties:

ldapSSLConfig.enabled=true
ldapSSLConfig.trustStorePath=/home/dir1/subdir1/subdir2/keystorename.keystore
ldapSSLConfig.trustStoreType=jceks

These are the only configuration changes done on our (client) side; and in fact the only changes done. Nothing has been added/modified on the server (AD server), except another user, but that has no impact on the existing setup.

After restarting cas to reflect the changes, we encounter the error of bad credentials, although the values entered are correct:

2015-09-16 12:12:30,558 INFO [com.pqr.cas.authentication.support.DelegatingAuthenticationHandler] - Authenticating credential using handler 
com.pqr.cas.adaptors.ldappwd.BindLdapAuthenticationHandler 
2015-09-16 12:12:30,558 DEBUG [com.pqr.cas.authentication.support.DelegatingAuthenticationHandler] - credentials.getUsername() = abcd
2015-09-16 12:12:30,672 INFO [com.pqr.cas.adaptors.ldappwd.BindLdapAuthenticationHandler] - Search for cn=abcd returned 0 results. 
2015-09-16 12:12:30,672 INFO [org.jasig.cas.authentication.AuthenticationManagerImpl] - AuthenticationHandler: 

com.pqr.cas.authentication.support.DelegatingAuthenticationHandler failed to authenticate the user which provided the following credentials: 

[username: abcd] 
2015-09-16 12:12:30,676 ERROR [org.jasig.cas.integration.restlet.TicketResource] - error.authentication.credentials.bad 
org.jasig.cas.ticket.TicketCreationException: error.authentication.credentials.bad 
at org.jasig.cas.CentralAuthenticationServiceImpl.createTicketGrantingTicket_aroundBody10(CentralAuthenticationServiceImpl.java:423) 

Can anybody please help with this issue? Or possibly point in the right direction? Any help would be greatly appreciated.

Thank you.

rud_hp9
  • 13
  • 5

1 Answers1

1

I see a few potential problems in your configuration.

ldapContextSource.userDn and .password should be the credentials for an account in AD that has access to read all of the user accounts who would be logging into the application. They intend for the .userDn value to actually be an LDAP DN string (similar to what you have for .searchBase), but for Active Directory you can use the userPrincipalName (UPN) attribute instead (usually this is username@example.net). So the bad credentials error may simply be that you're not qualifying the username with anything. I always prefer to use UPN for LDAP integrations because the account can be moved within AD and the application doesn't care (unlike a DN that would change).

Assuming that gets worked out, your .filter value will likely be a problem as well. While the uid attribute does exist in Active Directory, it's not generally populated by default. You should change it to sAMAccountName instead if you want users to login with just their username.

When you get around to enabling LDAP over SSL (LDAPS), you'll need to have a TLS certificate on your domain controller(s) that the java application trusts. If it's a self-signed cert, that cert will need to go into the keystore their docs referenced. If it's a cert generated from a public or internal PKI infrastructure, you should instead add the CA certificate chain for that infrastructure. You'll also need to change the LDAP server URI to ldaps:// and port 636 (or 3269 for global catalog searches).

Ryan Bolger
  • 16,472
  • 3
  • 40
  • 59
  • Thanks Ryan. When you say that the userDn and password should be of the account that has access to read all of the user accounts, it would be an admin account, right? If so, we are already using an admin account. In other configurations that we tried, we have used the value of userDn as "uid=abcd,OU=DEF,OU=PQR,OU=XYZ,DC=ADserver,DC=example,DC=net" and "cn=abcd,OU=DEF,OU=PQR,OU=XYZ,DC=ADserver,DC=example,DC=net", and you are suggesting that I set it to abcd@ADserver.example.net. Also, I would have to change value of filter to sAMAccountName=%u, is that correct? I'm sorry, I'm quite new to this – rud_hp9 Sep 28 '15 at 12:59
  • It does not need to be an admin account. In fact, it doesn't need any permissions other than basic read access to AD which new accounts get by default unless the default AD permissions have been changed. If ADserver in your example is the hostname of a domain controller, then your domain's FQDN is example.net. Your userDn would be abcd@example.net. You can also look up the full DN value by looking at the Attributes tab on the account. The attribute is called distinguishedName. – Ryan Bolger Sep 28 '15 at 16:02
  • I have not mentioned the name of the domain controller in my example (as we have multiple DCs in the domain, and we attempt to connect to the domain, and not a single DC for redundancy). I am quite sure that the domain's FQDN is ADserver.example.net, so the userDn would be abcd@ADserver.example.net. I will try with that and let you know of the results. The full DN, as seen in the Attributes tab is: cn=abcd,OU=DEF,OU=PQR,OU=XYZ,DC=ADserver,DC=example,DC=net (the vendor has suggested to use this as userDn) We do have to connect this over SSL, but will work on that once current setup works. – rud_hp9 Sep 28 '15 at 17:51
  • My mistake. "ADserver" makes it sound like a single machine. – Ryan Bolger Sep 28 '15 at 17:53
  • Be wary of using the domain's FQDN as your LDAP server if you have domain controllers in multiple sites. Unless the application is smart enough to use DNS SRV records to find the closes domain controller (most aren't), the application will essentially be using round-robin DNS across all of your DCs to choose which one to authenticate against. – Ryan Bolger Sep 28 '15 at 17:54
  • You are a genius, thanks Ryan! I'm able to login and access both the back-end and the UI pages of the application; previously, I could not even open the back-end page, and login to UI page used to fail. Needless to say, the bad credentials error has disappeared. However, after logging in into the UI, I encounter an error, 'HTTP Status 500 - Unable to create XMLReader'. Details as follows: – rud_hp9 Sep 29 '15 at 12:38
  • description The server encountered an internal error that prevented it from fulfilling this request exception:java.lang.RuntimeException: Unable to create XMLReader (a lot of description statements are present, but unable to add those here due to length constraints) root cause org.xml.sax.SAXException:SAX2 driver class org.apache.xerces.parsers.SAXParser not found java.lang.ClassNotFoundException:org.apache.xerces.parsers.SAXParser Did a quick Google search, this is regarding some missing jar file but I'm not sure. Your take?This error persists even when I switch authentication type back to db – rud_hp9 Sep 29 '15 at 12:44
  • Glad to help. You should post a separate question about the new problem. And please mark this answer as accepted. – Ryan Bolger Sep 29 '15 at 14:27
  • Will do. Thanks a lot once again! Had struggled a lot to get to this. In talks with the vendor about this new issue we've run into, will post another question if it doesn't work. Also, will update here in case I am not able to get the authentication to work using LDAP over SSL. Thanks. – rud_hp9 Sep 29 '15 at 16:52
  • Hi Ryan, could you also help me with how can I use multiple search base for the same configuration? Currently I have set searchBase to OU=DEF,OU=PQR,OU=XYZ,DC=ADserver,DC=example,DC=net. But I have users in another branch as OU=ouOne,OU=ouTwo,DC=ADserver,DC=example,DC=net. Theoretically, I can use DC=ADserver,DC=example,DC=net but the scope is too wide and no users are not able to login when I set this as the searchBase. So is there any way I can set multiple search bases? Also, applying filter to userDn does not help. – rud_hp9 Sep 30 '15 at 12:14
  • Supporting multiple search bases is entirely dependent on the application to support. Most don't though. You will likely either need to use a higher level search base that encompasses all your users or reorganize your OU structure. The filter value can also help with speeding up searches as long as it's formatted correctly. Try something like this: `(&(sAMAccountName=%u)(sAMAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=2))` which will limit the result to user accounts that are not disabled. – Ryan Bolger Sep 30 '15 at 15:29
  • Hmm.. Using a higher level search base is not working out, and we can't even reorganize the OU structure as it is in production. Unfortunately, the filter value you have provided isn't working. I let the searchBase be `DC=ADserver,DC=example,DC=net` when using that filter value. The filter value I used was: `(&(|(&(ou=PQR)(ou=XYZ))(&(ou=ouOne)(ou=ouTwo)))(sAMAccountName=%u))`. Also, PQR, XYZ, ouOne, ouTwo are of 2 words each; so eg. PQR = One Example, and so on. I'm not including these in quotes - does that make any difference? – rud_hp9 Oct 01 '15 at 06:04
  • The filter you used has a lot wrong with it. Suffice it to say, you can't do what you appear to be trying to do which is use a filter to find users that live in a set of OUs. You could probably use a primer on writing LDAP queries. I'd start here. https://technet.microsoft.com/en-us/library/aa996205(v=exchg.65).aspx – Ryan Bolger Oct 01 '15 at 06:29
  • I went through the link and some others too, modified it to: `(&(sAMAccountName=%u)(|(ou=PQR,ou=XYZ)(ou=ouOne,ou=ouTwo)))` value of `ldapAuthenticationHandler.searchBase="dc=ADserver,dc=example,dc=net"` Still no result.. – rud_hp9 Oct 01 '15 at 13:08
  • There is no "OU" attribute on user objects. So you can't filter on it. You can only filter on attributes that exist for the user. – Ryan Bolger Oct 01 '15 at 17:29
  • Because your application doesn't explicitly support searching multiple baseDNs and you are unable to reorganize your OU structure, you need to base your searches on something other than the OU like a common group membership. If you add all of your users to a group, you can filter on that group membership instead. Something like *(memberOf=CN=mygroup,OU=mylocation,DC=ADserver,DC=example,DC=net)* – Ryan Bolger Oct 01 '15 at 17:33
  • Oh right, that slipped out of my mind. I spoke to the team that handles the AD side configuration but they were not too keen on creating the group as the server is in production, and they were also not completely sure of how they had to do it. Thankfully it turned out that we do not need to add another OU to the search base as all production users are in a single OU itself. So we're good with using that single OU in the search base. Thanks a lot for your time and help! Appreciate it. – rud_hp9 Oct 13 '15 at 11:33