CAS validate

My first program pushed up to npm turned out to be a javascript CAS (www.jasig.org/cas) library I wrote for our portal at http://www.ctmlabs.net. The main think holding me up pushing anything to npm was the lack of tests. While I never run tests on packages downloaded from npm (one area where CPAN is definitely better than npm…all tests are run by CPAN on install), I felt that I couldn’t claim that a package was “eligible” for adding to npm until I could prove to myself that it worked like I thought it did.

The tests turned out to be a lot harder to write than I expected. I used Mocha, and excellent test framework, and should, a handy assertion library. But the hard part was getting a session with CAS server to work.

The way CAS works is to establish single sign on via the client. So when a client logs into my website, I check and see whether I have a valid session cookie for them from the CAS server, and if not, my code redirects the client back to the CAS server to get a single use service ticket (ST). That redirect is then redirected back to my site, with the ST, and I can use that ST to independently go to the CAS server and verify that the service ticket is valid.

So for a test, the client inside of the test has to be able to handle redirects and cookies and so on. My first attempt was to use superagent, figuring to keep within the mocha/should/express family. But I didn’t see how to handle cookies and redirects from within superagent. So I switched back to my usual standby, request (https://github.com/mikeal/request). I did everything right, setting up a single cookie jar for every request, enabling the following of redirects, etc., but my test kept choking on the CAS server. Using curl to hit the CAS redirect url worked fine, but using request kept getting an error page.

Eventually I figured out that the CAS server throws an error if it doesn’t know its client. So the solution is to lie. Because sometimes I wanted to test cookies and sometimes not, I wrote the following wrapper to generate a request instance:

function _setup_request(cb){
    // make sure CAS can talk to request and not die a horrible death of a confused tomcat
    // clear the cookies for the next test
    jar = request.jar()
    var rq = request.defaults( {jar:jar
                                ,headers:{'User-Agent':'Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/12.0'}})
    cb(null,rq)
}

In a nutshell, I create a cookie jar, and then create a request instance that defaults to that cookie jar and to spoofing the user agent header to look like a recent version of Firefox.

To use this code effectively, I turned to another standby library, async (https://github.com/caolan/async), leveraging the waterfall function as follows:


it('should redirect when no session is established'
   ,function(done){
        async.waterfall([function(cb){
                             _setup_request(cb)
                         }
                        ,function(rq,cb){
                             rq({url:'http://'+ testhost +':'+testport+'/'
                                ,followRedirect:false}
                               ,function(e,r,b){
                                    r.statusCode.should.equal(307)
                                    r.headers.location.should.equal(casurl+'?service=http%3A%2F%2F'+ testhost +'%3A'+testport+'%2Findex.html')
                                    should.not.exist(b)
                                    cb()
                                })
                         }]
                       ,done
        )
})

The waterfall function collects the output of each asyncronous function and passes that output along to the next function in the stack, along with a callback function to call when the next asyncronous function is done. My setup request function returns a request instance, which is then passed on to the test itself. In this case I am *not* following redirects, but in other tests I do, and that spoofed header is vital to making things work.

Hopefully, now that I’ve published one program, I can start to push out more in the future.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s