Connecting iOS, Drupal and CAS

Mobile Development Comments (4)

Our sister company, The Iona Group,  just finished a highly innovative project for Loyola Marymount University in Los Angeles. The project is centered around student interaction (sending messages, uploading photos/video, etc.) with the expectation that a bulk of the interaction will come from students on their mobile devices. As part of their larger digital communications strategy and technical infrastructure, we worked with them to understand the audience’s primary device platform and deliver a solution that fit in with their campus technology landscape. The primary user base was identified as iOS devices, since, as with many university campuses nationwide, Apple products are very popular at LMU. This did present some wrinkles to our initial plan to use the mobile web to interact with the installation. Due to the inability to upload files through Mobile Safari on iOS devices, we had to create an iPhone application that bridged the gap.

Moving from initial strategy to implementation planning it was uncovered that LMU is transitioning towards using CAS (Central Authentication Service) in all their web applications. CAS is a single sign-on protocol developed by Yale University and is now a project of Jasig. The content management for this newly developed project by Iona is handled entirely by Drupal. Fortunately, there is a Drupal module (appropriately named CAS) which integrates the wonderful phpCAS library with the Drupal authentication system. Our task was to find a way to integrate CAS authentication into our iPhone application and pass that authentication off to Drupal. It wasn’t immediately clear on how to stitch the various pieces together, and we see alot of applicability of this code, especially in academic settings, so let’s examine how this works. Maybe you’ll find this useful in getting an app up and running for your users!

Step 1: Getting a Service Ticket

CAS is primarily designed to provide a single sign-on service to web applications. Fortunately, CAS also has a RESTful API that allows our iOS application to access it and authenticate for another service. This process involves passing the username and password to the CAS service, obtaining a ticket-granting ticket (letting us know that the login was successful), and using the ticket-granting ticket to generate a service ticket for a specified service (in this case, the URL to our Drupal site).

This process needs to happen within the iOS application. The user will enter his or her username and password and the iOS application needs to receive the ticket-granting ticket. We’re going to use ASIHTTPRequest, a wrapper for the CFNetwork API, because it makes communication with a server a lot easier to understand.

//Create the request
NSString *server = "https://example.com/cas/v1/tickets"; //The URL to REST on the CAS authentication server
NSString *theUsername = "username";
NSString *thePassword = "password";
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:server]];

//Format the credentials
NSString *credentials = [NSString stringWithFormat:"username=% && password=%",theUsername,thePassword];

//Add the credentials to the body of the request as per
//https://wiki.jasig.org/display/CASUM/RESTful+API#RESTfulAPI-RequestforaTicketGrantingTicketResource
[request appendPostData:[credentials dataUsingEncoding:NSUTF8StringEncoding]];
[request setRequestMethod:"POST"];
[request setValidatesSecureCertificate:NO];

//Start the request
[request startSynchronous];

If the request was successful, the server will redirect the request to http://www.example.com/cas/v1/tickets/{TGT}. Notice the last part of the URL is our ticket-granting ticket. To grab the ticket-granting ticket from that,

NSString *location = [[request responseHeaders] objectForKey:"Location"];
NSString *tgt = [[location componentsSeparatedByString:@"/"] lastObject];

Now that we have our ticket-granting ticket, we can use it to obtain the ticket for our service (in this case, the URL to CAS on our Drupal site).

NSString *service = @"http://drupal-site.com/?q=cas"; //The URL to the CAS module in Drupal (don't use the clean URL)

//Generate request for ticket
//https://wiki.jasig.org/display/CASUM/RESTful+API#RESTfulAPI-RequestforaServiceTicket
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@",server,tgt]];
request = [ASIHTTPRequest requestWithURL:url];

[request appendPostData:[[NSString stringWithFormat:@"service=%",service] dataUsingEncoding:NSUTF8StringEncoding]];
[request setValidatesSecureCertificate:NO];

//Start the request
[request startSynchronous];

Now the service ticket will be the body of the response from this request.

NSString *st = [request responseString];

We have our service ticket! Hang on to this…we’ll be using this in step 3.

This code isn’t specific to iOS/Drupal communication. In fact, it can be used with any iOS application that you want to use with CAS. We’ve refined the code above and created a little CAS class for you to use in your iOS applications. All you need is the ASIHTTPRequest library.

Step 2: Connecting our iPhone App to Drupal

We’re not going into detail about connecting your iPhone app to Drupal outside of recommending the use of the Drupal/iOS SDK by Kyle Browning. This SDK provides a way to send requests to Drupal through the Services module using binary plists for fast communication. The documentation provided in the SDK and the example application are more than enough to get you started.

Step 3: Authenticating the User

We have a way to connect iOS and CAS as well as iOS and Drupal. What we’re missing is some communication between Drupal and CAS. We have the CAS module, but we need a way to pass the authentication we performed in step 1 and get a Drupal user. The Services API relies a lot on a session ID as well as user information (e.g.: the username and the user ID). Normally, we would use the user.login service to obtain this information, but the user is not a Drupal user, he/she is a CAS user. We need to create a new service that accepts a service ticket and returns the user information (similar to how the user.login service returns user information). We’ll also need to create an addition to the DiOS SDK that can communicate with our new service.

At the time of this writing, the CAS module doesn’t provide an easy way of simply reusing one of its functions to pass along a service ticket and receive an authenticated user. We had to get a little creative using the PHP cURL library. We thought this would be helpful to others in the Drupal community (especially as CAS gains popularity among universities) so we’ve submitted our module to the Drupal module repository. It’s not available for download from Drupal yet, but we attached the source code below.

The final piece to the puzzle is an additional class for the DiOS SDK. This involves subclassing the DIOSUser class (creating a DIOSCASUser class) and adding one new method:

- (NSDictionary *) loginWithServiceTicket:(NSString*)st
{
[self setMethod:@"user.cas_login"];
[self addParam:st forKey:@"ticket"];
[self runMethod];
[self setSessid:[[self.connResult objectForKey:@"#data"] objectForKey:@"sessid"]];
[self setUserInfo:[[self.connResult objectForKey:@"#data"] objectForKey:@"user"]];
return [self connResult];
}

This takes the response from the user.cas_login service and sets the proper properties in the DIOSConnect instance. The DIOSConnect instance now has session information for the user we logged in using CAS.

Source Code

In addition to our brief overview in this post, we’re providing all the code you need to get started implementing an iOS application with your Drupal/CAS set up.

Source Description Dependencies
iOS CAS class A class to obtain a CAS service ticket with iOS.
Drupal User CAS Service module Creates a new service for the Services API for authenticating a user with a service ticket.
DIOSCASUser class Provides a way to connect to our new service using the DIOS SDK.

To implement the source code above, all you need to do is,

//Create connection to CAS
CAS *cas = [[CAS alloc] initWithServer:@"https://example.com/cas/v1/tickets" withUsername:@"username" andPassword:@"pasword"];

//Get ST
NSString *st = [cas generateServiceTicketForService:@"http://drupal-site.com/?q=cas"]; //Don't use the clean URL

//Pass service ticket to Drupal
DIOSCASUser *user = [DIOSCASUser new];
[user loginWithServiceTicket:st];

//Do whatever you want with user and CAS

//And don't forget to free up the memory
[cas release];
[user release];

And now user has all the session information for the logged in user! You can check it out by adding

NSLog(@"User: %@", user);

Of course, that needs to come before you release the user object.

We’d love to hear how you implement this code in your own applications. Let us know by adding a comment!

And, of course, if you’re interested in developing a project like this, please don’t hesitate to contact us.

Follow Float
The following two tabs change content below.

» Mobile Development » Connecting iOS, Drupal and CAS
On January 30, 2011
By
, , , , ,

4 Responses to Connecting iOS, Drupal and CAS

  1. Thibaut says:

    Hi,

    Thanks you for this article, it helps me to implement CAS into an iPhone app.

    However, i have a problem, obtain a TGT and a ST operate successfully but when i want to validate my ST to access to a php page, i always obtain “no” by the CAS like if the ST isn’t valid.

    I use the following code to try validation :

    NSString * theService = @”http://myWebSite.com”;

    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@”https://cas.mywebsite.com/cas/validate”]];

    NSString *credentials = [NSString stringWithFormat:@”service=%@&ticket=%@”,theService,st];

    [request appendPostData:[credentials dataUsingEncoding:NSUTF8StringEncoding]];
    [request setRequestMethod:@”POST”];
    [request setValidatesSecureCertificate:NO];

    [request startSynchronous];

    Someone have an idea to resolved my issue ? or can help me ? plz

    Cordially Thibaut

  2. ferolo.com says:

    […] infrastructure and authenticates through their CAS system. You can read more about Dan’s awesome work at Float Mobile Learning. He did some amazing work on the CMS and is managing the entire corpus of data that is submitted by […]

  3. J Garcia says:

    Thanks for the info, but was unable to download the iOS CAS class
    permission error.

Leave a Reply

Your email address will not be published. Required fields are marked *

« »