RESTful API

Table of Contents
Home
Overall Architecture
Authentication
Authentication Managers
Security Policy
TicketRegistry
Testing
Protocols
Advanced Features
Tutorials and HOWTOs
Troubleshooting
Services Management
Extensions

Purpose

Applications need to programmatically access CAS. Generally, proxying works for this. However, there are cases where an application needs to access a resource as itself, in which case proxying doesn't make any sense.

At Rutgers, we've implemented a relatively "heavyweight" SOAP based service via Axis. We're now looking at complementing that with a lightweight resource-driven architecture. This page details that proposed work.

This API works to expose a way to RESTfully obtain a Ticket Granting Ticket resource and then use that to obtain a Service Ticket.

Protocol

The RESTful API follows the same basic protocol as the original CAS2 protocol, augmented with some additional well-defined resource urls (though the protocol doesn't change so it should be just as secure).

Ticket Granting Ticket

The Ticket Granting Ticket is an exposed resource. It has a unique URI.

Request for a Ticket Granting Ticket Resource

POST /cas/tickets HTTP/1.0

username=battags&password=password&additionalParam1=paramvalue

Response for a Ticket Granting Ticket Resource

Successful Response

201 Created
Location: http://www.whatever.com/cas/tickets/{TGT id}

Unsuccessful Responses

If incorrect credentials are sent, CAS will respond with a 400 Bad Request error (will also respond for missing parameters, etc.). If you send a media type it does not understand, it will send the 415 Unsupported Media Type

Request for a Service Ticket

POST /cas/tickets/{TGT id} HTTP/1.0

service={form encoded parameter for the service url}

Response for Service Ticket

Successful Response

200 OK

ST-1-FFDFHDSJKHSDFJKSDHFJKRUEYREWUIFSD2132

Unsuccessful Responses

If parameters are missing, etc. CAS will send a 400 Bad Request. If you send a media type it does not understand, it will send the 415 Unsupported Media Type.

Logout of the Service

To log out, you merely need to delete the ticket.

DELETE /cas/tickets/TGT-fdsjfsdfjkalfewrihfdhfaie HTTP/1.0

Configuration

By default the CAS RESTful API is configured in the restlet-servlet.xml, which contains the routing for the tickets. It also defines the resources that will resolve the URLs. The TicketResource defined by default (which can be extended) accepts username/password.

To turn on the RESTful API, add the following to the web.xml:

<servlet>
	<servlet-name>restlet</servlet-name>
	<servlet-class>com.noelios.restlet.ext.spring.RestletFrameworkServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>restlet</servlet-name>
	<url-pattern>/v1/*</url-pattern>
</servlet-mapping>

Note, that in the above configuration example, we are explicitly versioning the RESTful API, so things would be accessed via /cas/v1/tickets/*, etc.

In the pom.xml file include the following:

<dependency>
	<groupId>org.jasig.cas</groupId>
	<artifactId>cas-server-integration-restlet</artifactId>
	<version>3.3-RC3</version>
	<type>jar</type>
</dependency>

where 3.3-RC3 is the version of CAS you are currently using (3.3 or higher).

Python REST Client Example

#!/usr/bin/python
import os.path
import httplib, urllib, urllib2, cookielib

# 1. Grab the Ticket Granting Ticket (TGT)

params = urllib.urlencode({'username': 'battags', 'password': 'password'})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
conn = httplib.HTTPSConnection("cas.acme.com")
conn.request("POST", "/cas/v1/tickets/", params, headers)
response = conn.getresponse()
print response.status, response.reason
data = response.read()
location = response.getheader('location')
#  Pull off the TGT from the end of the location, this works for CAS 3.3-FINAL
tgt = location[location.rfind('/') + 1:]
conn.close()

print location
print tgt
print "***"

# 2. Grab a service ticket (ST) for a CAS protected service

document = '/secure/blah.txt'
service  = 'http://docs.acme.com%s' % (document)

params = urllib.urlencode({'service': service })
conn = httplib.HTTPSConnection("cas.acme.com")
conn.request("POST", "/cas/v1/tickets/%s" % ( tgt ), params, headers)
response = conn.getresponse()
print response.status, response.reason
st = response.read()
conn.close()

print "service: %s" % (service)
print "st     : %s" % (st)
print "***"

# 3. Grab the protected document

#httplib.HTTPConnection.debuglevel = 1

url  = "%s?ticket=%s" % ( service, st )  # Use &ticket if service already has query parameters
print "url    : %s" % (url)

cj = cookielib.CookieJar()

# no proxies please
no_proxy_support = urllib2.ProxyHandler({})
# we need to handle session cookies AND redirects
cookie_handler = urllib2.HTTPCookieProcessor(cj)

opener = urllib2.build_opener(no_proxy_support, cookie_handler)
urllib2.install_opener(opener)
protected_data = urllib2.urlopen(url).read()
print protected_data

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.