casLogoRecently, I was given the assignment to help coordinate the single sign-on efforts between a new partner and our University.  Like many Universities, we use a single sign-on solution called CAS, or Central Authentication System.  CAS is an open source project sponsored by Jasig{{1}}.

CAS supports an open standard called SAML {{2}} that allows us to provide both authentication and authorization information to our partners (and internally) without the need to share our user’s credentials.  Now I myself am not an expert in this area, but this assignment finally forced me to pay a little more attention to how our CAS infrastructure works, and more specifically to its implementation of SAML.

The first thing I wanted to know was what our SAML assertions (the user data exchanged through the protocol) looked like and whether they provided the right information to our partner.  Since CAS is a system that leverages HTTP, I figured it should be simple to make a few calls using a web browser and a simple tool–that allows me to make HTTP post requests–to manually create some calls that return my own personal SAML assertions back from CAS.

I began my experiment with my primary research mechanism, ask our experts.  However our experts (including our CAS engineers) had no clue how to make the simple web calls I needed.  How is that possible you ask?  Well they are all programmers and as programmers they rely on the nice Jasig libraries which, as designed, abstract away the necessary calls into the CAS system.

So what next?  Well Google, of course (or for the sake of fairness Bing too).  Google brought up several posts, albeit a bit old, about using the samlValidate endpoint and a tool called SoapUI to make the calls.  Unfortunately none of these instructions worked as they appeared to use older versions of CAS.

My searching did bring me to the Jasig wiki{{3}} which started to point me in the right direction. But it still fell flat when it came to providing me the complete picture to make my request.  CAS itself was not offering any help either as all of my requests were met with 500 errors (I did talk to our engineers about this since I eventually discovered that the endpoint was running just fine and the only issue was a malformed request).

At last, I finally broke down and went to my third method of discovery, writing and debugging code.  I downloaded the .Net client code provided by jasig{{4}} and was happy to find that there was a great demo app included.  After some debugging and html packet sniffing I finally came across the secret sauce to making the calls I needed.  Here is a quick tutorial on how I was finally able to do what I needed.

First you need to initiate a login into the CAS system and provide a return URL.  You can do this in any browser.  I gave a bogus URL so that the redirect back from CAS would fail and expose to me a vital piece of information.

https://cas.school.edu/cas/login?TARGET=http://localhost/me

After a successful login, the CAS system will redirect the browser back to the specified URL with something called a SAML assertion artifact.  Oddly enough, this simple call was the root of all my previous issues.  A typical (non-SAML) call into CAS uses the query string parameter “service” instead of “TARGET”.   Using that parameter you get back a service ticket instead of a SAML assertion artifact.  And as you can now expect, a service ticket does not work on the SAML endpoints.

The redirect came back looking something like this:

http://localhost/me?TARGET=http://localhost/me&SAMLart=AAFSsPYAkNKN6Mb0Q6Li8D8gawrtLAw8EOp7nTpQZubeRcCfh51EmhS3

At this point, all that the originating system has received about the authenticated is this SAML artifact.  So now, in order to complete the process, a simple HTTP POST call back to the CAS system will return whatever information, about the user, that CAS deems necessary (usually at least a primary identifier).  To create the POST call, I like to use a tool called Fiddler{{5}}.  It’s simple, yet very powerful.  Note that this call requires a SOAP body in addition to the properly formed URL.

The URL looks like this:

https://cas.school.edu/cas/samlValidate?TARGET=http://localhost/me&SAMLart=AAFSsPYAkNKN6Mb0Q6Li8D8gawrtLAw8EOp7nTpQZubeRcCfh51EmhS3

and the body looks like this:

<SOAP-ENV:Envelope xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”>
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<samlp:Request xmlns:samlp=”urn:oasis:names:tc:SAML:1.0:protocol”
MajorVersion=”1″ MinorVersion=”1″ RequestID=”_192.168.16.51.1024506224022″
IssueInstant=”2002-06-19T17:03:44.022Z”>
<samlp:AssertionArtifact>AAFSsPYAkNKN6Mb0Q6Li8D8gawrtLAw8EOp7nTpQZubeRcCfh51EmhS3
</samlp:AssertionArtifact>
</samlp:Request>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Notice the assertion artifact exists in both the URL and the SOAP body.  This is the only thing that differs in the body from request to request.  After making this call, you get back a SOAP envelope containing all the appropriate SAML assertions for the user in question.  At this point the originating systems has verified, through CAS, that the user did indeed know their credentials and was able to retrieve all of the relevant user data that CAS was configured to return (username, firstname, lastname, email, etc.).

[[1]]http://www.jasig.org/cas[[1]]

[[2]]http://en.wikipedia.org/wiki/Security_Assertion_Markup_Language[[2]]

[[3]]https://wiki.jasig.org/display/CASUM/SAML+1.1[[3]]

[[4]]https://wiki.jasig.org/display/CASC/.Net+Cas+Client[[4]]

[[5]]http://www.fiddler2.com/fiddler2/[[5]]