Fork me on GitHub

n. Slang a rough lawless young Kuali developer.
[perhaps variant of Houlihan, Irish surname]
kualiganism n

Blog of an rSmart Java Developer. Full of code examples, solutions, best practices, et al.

Tuesday, April 3, 2012

LDAP CAS Implementation

Overview

This is a companion post to Rice KIM LDAP and Embedded Apache DS.

CAS is the phenominal JA-SIG single sign-on (SSO) web application that Kuali is standardizing with. We already know of ways to implement LDAP with Kuali applications. Once you get your KIM integration, then where do you? You still need your users in the KRIM_PRNCPL_T table if you want to login. How do you setup CAS to know about your LDAP directory service?

Kuali CAS LDAP Implementation on GitHub

I put together another github project called kuali-cas. It is a maven project that easily will configure your CAS server for development and possibly even production CAS installations.

1 Checkout kuali-cas

% git clone https://github.com/r351574nc3/kuali-cas.git
% cd kuali-cas

2 Modify custom.properties

To configure CAS to talk to your LDAP server, you need to configure the src/main/resource/custom.properties file. It looks something like:



You want to configure it somewhat the same way you have setup your LDAP configuration with your Kuali Application.

3 Build the cas.war Package

% mvn package

4 Copy the war to Your Appserver

% cp target/cas.war $CATALINA_HOME/webapps/

That is it. Now when you browse your kuali application and it redirects you to CAS, the CAS server will be connected to your LDAP server.

What About admin?

That's right! The admin user is probably not going to exist in your production LDAP directory, so what do you do about admins in development and in production?

Well, you could login as a regular user and backdoor. In production you will not have a backdoor, so then what?

Backdoor CAS Instance

I suggest running another CAS instance that connects to KIM RDBMS and name it backdoor-cas.
  1. Create backdoor-cas.war (normal kuali-cas war file).
  2. Install it in the same place as your cas.war (Now you should have 2 cas servers running on the same appserver.)
  3. Create a backdoor.jsp:



  4. Map the backdoor cas filter to backdoor.jsp (note this is in
    addition to the other cas.



Using backdoor.jsp

  1. Login by going to http://localhost:8080/kfs-dev/portal.do. This will connect you through LDAP.
  2. Suppose then you want to login as admin. Now that you are logged in as williamh, you cannot login again. So now what? http://localhost:8080/cas/logout will log out out.
  3. You can then go to http://localhost:8080/kfs-dev/backdoor.jsp. This will trigger the backdoor filter and force you into http://localhost:8080/backdoor-cas/login and http://localhost:8080/backdoor-cas/validate which will log you in using KIM RDBMS. As a result you can login as admin. Yay!

What you get is ldap login everywhere except for backdoor.jsp. When
you hit backdoor.jsp, it will force KIM RDBMS login, then redirect to
index.jsp

It's a little hacky, but it will get you both logins.

Rice KIM LDAP and Embedded Apache DS

Overview

While KIM supports LDAP Integration for identity management, it is difficult for developers to work in a similar environment to that the code will actually be deployed to. For example, if my DEV, TST, STG, and PRD environments all connect to LDAP and there is a problem with the actual LDAP mappings, it is a hassle to test or develop a fix because my local development environment does not connect to LDAP. I would have to configure it to do that. Once it did, I probably do not have the same datasource that is being used. How can I test?

KIM LDAP Integration Test

Recently the Rice team came up with this integration test (see LDAPIdentityServiceImplTest.java) that will test the LDAP Integration. It runs against a sample dataset. The trouble is, it is started entirely using the spring LdapTestUtils. See below:



That's not very handy if you want to use this for development. You could just run your integration tests I suppose. I thought to myself though, that it would be really nice to be able to have a running LDAP Reference Implementation within my development environment anyway. I also thought that the java approach used by the KIM LDAP Integration test was a little excessive and bootstrapping Spring in the integration test would be much more preferred. I decided it would be worth a shot. That way the integration tests and a reference implementation can all run out of a common setup.

Embedded Apache DS

What I did was, I modified my KFS Overlay Reference Implementation, to include an embedded Apache DS instance.

apacheds Profile

The first thing I did was create an apacheds profile in my pom.xml

You can see that I have a dependency on apacheds 1.5.7. I'm not actually using this...yet. I currently use the Spring ldap utils. 1.5.7 is a transitional version to the new apacheds 2.0. apacheds is kinda going through the same thing as what Rice went through. After 1.0.2, they created this thing called the BBB (Big Bang Branch). They are basically rewriting the software that will be released in 2.0. Sounds familiar, right? Anyway, back from the tangent. The plan is eventually using 1.5.7 and 2.0, but for now I stick with 1.0.2. If it is good enough for Spring, it is good enough for me.
As I mentioned, I use the spring ldap utils and of course, I had to add a dependency to rice-ldap. See below:


I added a few files to the core module:
core/
    \->src/
        \->main
            \->java
            |   \->com
            |       \->rsmart
            |           \->kuali
            |               \->rice
            |                   \->kim
            |                       \->ldap
            |                           \->KimPrincipalInfoMapper.java 
            |                           |->service
            |                               \->impl
            |                                   \->ApacheDsEmbeddedServer.java
            \->resources
                \->com
                    \->rsmart
                        \->kuali
                            \->rice
                                \->kim
                                    \->ldap
                                        \->config
                                        |   \->KIMLdapServerSpringBeans.xml
                                        |   |-> KIMLdapSpringBeans.xml
                          |->demo.ks
                           |->demo.ldif
                                  |->eduMember.ldif
                                    |->eduOrg.ldif 
                                        |->eduperson.ldif

ApacheDsEmbeddedServer.java

This is really just configuration. It is loaded into spring at startup and handles loading bootstrap data as well as starting the server. No big deal. I set it to configure in the KIMLdapServerSpringBeans.xml.

KIMLdapServerSpringBeans.xml

There are just 2 beans setup here.
  • embeddedLdapServer
  • configuration
. One is our ApacheDsEmbeddedServer. The other is a MutableServerStartupConfiguration. The MutableServerStartupConfiguration is what is actually starting the apacheds. You can see that configuration is actually a reference that is applied to the embeddedLdapServer. The ApacheDsEmbeddedServer.java needs the configuration and connection information because it actually connects to the running apacheds instance to load data stored in the demo.ldif.

ldap.properties

You may notice there are some properties set within the ${} tags. These properties are defined in 2 ldap.properties files. One is located in web/src/main/filters/ldap.properties and the other is in config/src/main/filters/ldap.properties.

web/src/main/filters/ldap.properties


These properties are later added to the configuration.properties file at build time. You can see my mappings are setup here. You want this to look exactly how your production environment will work.

config/src/main/filters/ldap.properties


These properties are later added to the security.properties file at build time. You can see that this is where I setup my credentials.

Running it

The command I have been using to kick build a kfs-dev.war with an embedded ldap server is:
% mvn -Pmysql,apacheds clean package

If I want to build a war without an LDAP server and ignore all my ldap settings, I just use:
% mvn -Pmysql clean package

Getting it

If you want to setup something like this for yourself, just refer to this blog post and you can always pull/fork my code from KFS Overlay Reference Implementation