Archive for the ‘grails’ Category

Thursday, March 20th, 2008

OpenID is an open standard for decentralized authentication. The OpenID site has plenty of detailed documentation about the protocol so I will briefly explain the basics needed to understand how to integrate OpenID authentication into your grails project.

OpenID Provider
A user registers an OpenID through an OpenID provider. This is the site that provides the identifying URL for the user and handles the authentication request from the Relying Party.

There are a number of OpenID providers out there, with new ones cropping up all the time. I use myopenid simply because it was one of the first openid providers I had heard of. Many sites also provide an OpenID when you sign up for their service. This has lead to OpenID providers that aggregate all of your other OpenIDs. Since we want to drive adoption and there are probably more providers than consumers at this point, we are going to focus on just being an OpenID relying party.

Relying Party
The relying party is the web service that uses OpenID to handle it’s authentication. It prompts the user for their OpenID URL and redirects the user’s browser to the Provider’s authentication page, the provider prompts the user with information about the site making the authentication request, allows the user to accept or reject authentication with the site and then redirects the user back to the relying party with an authentication token that the relying party then verifies. The user never enters a password with the relying party, the provider can also allow automatic authentication with the relying party if they so choose.

Discovery
You can use any web address as your OpenID simply by including the following html in the head tag of your site.


<link rel="openid.server" href="http://youropenidserverendpoint">
<link rel="openid.delegate" href="http://youropenid/url">

This lets you use your blog and any other site you may have as your OpenID. The relying party will parse this information from whatever URL you pass to it.

Setup
I am using code and comments taken from the OpenID4Java getting started page and adapting it for quick integration with grails. If you need anymore detail than I have provided you should check out their wiki. The full source code for our example can be found here: UserController.groovy

1. Sign up for an OpenID, we want one to ease testing obviously.

2. Download the excellent OpenID java library OpenID4java and put the jar and its dependencies in your lib directory. Watch out for dependency versioning conflicts since grails uses many of the same dependencies.

3. For our example we will use a User controller, so go ahead and create a user controller. I won’t really go into modelling a User domain class but with OpenID you can skip all of the password management and storage and simply have a field for their OpenID URL instead.

Getting Started

We need to specify a return URL that the provider will redirect to after authentication is finished. You can store this in a number of places but I will just put it in the UserController. This URL corresponds to the auth action will will implement in UserController.


String _returnURL = "http://localhost:8080/openidtest/user/auth";

The controller actions share a ConsumerManager that is used to perform various steps of the OpenID authentication, I made it a static variable in the UserController because it seems to not work otherwise, there is probably a better way to do this.


  static ConsumerManager manager = new ConsumerManager();

Actions
We will define a few actions on our controller, these will be used to initiate and verify the OpenID authentication process.

login
The first action is login, this action simply presents the user with an OpenID entry field.


def login = {

    		if(session.user){
    			redirect(action: 'index') //redirect to main user page
    		}
    }

If the user is already logged in we redirect.

Here is gsp code for including an OpenID login field for your app, include it in your login.gsp view. Don’t forget to save the OpenID icon to your images directory.


<img src="${createLinkTo(dir:'images',file:'icon_openid.gif')}" alt="openid_logo" />
<g:form name="loginForm" action="handleLogin"><g:textField name="openid" value="http://yourname.myopenid.com" />
<g:actionSubmit value="Login" action="handleLogin" />
</g:form>

handleLogin
This action will take the user’s OpenID URL, create an authentication request and redirect the user to their OpenID Provider.


def handleLogin = {

    try{
		// disable realm verification
    		 RealmVerifier rv = new RealmVerifier();
    		 rv.setEnforceRpId(false);
    		 manager.setRealmVerifier(rv)

    		 // perform discovery on the user-supplied identifier
    		    List discoveries = manager.discover(params['openid']);
    		    DiscoveryInformation discovered = manager.associate(discoveries);

    		    // store the discovery information in the user's session for later use
    		    session.discovered = discovered

    		    // obtain a AuthRequest message to be sent to the OpenID provider
    		    AuthRequest authReq = manager.authenticate(discovered, _returnURL);

    		    response.sendRedirect authReq.getDestinationUrl(true)
    		    }catch(DiscoveryException e){
    		    	//add flash message , failed to find openid at address
    		    	flash.message = "Failed to find valid openid URI at specified address"
    		    	redirect(action:'login')
    		    }
    }

auth
The auth action is the action specified by our service that the OpenID provider will redirect the user to after authenticating with the provider. The provider includes a number of parameters so that the relying party can verify that the user has actually authenticated with the provider.


 def auth = {

    	    // check if this is an openid message, this is to avoid someone
	    // calling the auth action themselves
    	    if(!params['openid.mode']){
    	    	redirect(action:'err')
    	    return;
    	    }

    	    ParameterList openidResp = new ParameterList(request.getParameterMap());

    	    // retrieve the previously stored discovery information
    	    DiscoveryInformation discovered = (DiscoveryInformation) session.discovered;

    	    // extract the receiving URL from the HTTP request
	    // is there an easier way to get the full path including servername and port?
    	    StringBuffer receivingURL = new StringBuffer('http://' + request.getServerName() + ':' +
  request.getServerPort() +request.forwardURI);
    	    String queryString = request.getQueryString();
    	    if (queryString != null && queryString.length() != 0)
    	        receivingURL.append('?').append(request.getQueryString());

    	    // verify the response
    	    VerificationResult verification = manager.verify(receivingURL.toString(), openidResp, discovered);

    	    // examine the verification result and extract the verified identifier
    	    Identifier verified = verification.getVerifiedId();

    	    if (verified != null){
    	    	//User.findByUrl(verfied.getIdentifier())
    	    	session.user = verified
    	    	 // success, use the verified identifier to identify the user
    	    	redirect(action: 'index')

    	    }else{
    	        // OpenID authentication failed
    	        redirect(action: 'err')
    	    }

    }

request.forwardURI is a grails specific method that actually calls request.request.requestURI, this is needed to verify the previously called URL that made the authentication call to the provider.

err
The err action is the action we will redirect to if our authentication fails at any point. You can probably get away with just redirecting the the grails default error page.

Filter
Our final step is to set up an Authentication filter like the one we made for basic authentication . The only difference is that we have a number of controller actions that we want to allow to pass the filter, like login, handleLogin, auth, and err.


class SecurityFilters {
	class SecurityFilters {
	def filters = {
			loginCheck(controller:'*', action:'*') {
		           before = {
		        		   log.trace("inside of filter")
		              if(!session.user && !actionName.equals('login') &amp;amp;&amp;amp; !actionName.equals('handleLogin') && !actionName.equals('auth') && !actionName.equals('err')) {
		                  redirect(controller:'user' , action:'login')
		                  return false
		               }
		           }

		}
	}
}

OpenID, Authorization, and APIs
Since OpenID focuses on authentication there is not currently a good way to incorporate OpenID with API calls. Having to redirect a user to a web page is not something someone programming a mobile or desktop application wants to do in order to make API calls. There have been rumblings of integrating an API http header authorization mechanism into the OpenID standard, and of course you could always integrate OAuth and OpenID so the user would only have to do web based authorization once for your application.

Friday, March 7th, 2008

I have been experimenting with implementing a RESTful API in Grails. Like most APIs some of the methods require user authentication before they are allowed to be performed. There are a number of interesting HTTP based authentication/authorization schemes out there, but the most straight forward is Basic Authentication. Basic Authentication takes a Base64 encoded username:password pair and places it into the “Authorization” http header. The server then decodes the pair and uses them with it’s authentication system. It is not the most secure way to do authentication as your user name and password are basically in plain text, but the risk can be mitigated by using https.

There are a number of java packages and grails plugins that provide Basic Authentication functionality amongst other things. I thought I would walk through doing it manually within Grails, since it is fairly straightforward and provides an example of how grails filters can be used.

The main part of the approach is creating a Filter that will intercept the calls to our api and authenticate the user. In the conf directory of your grails project create a groovy class called SecurityFilters.groovy and insert the following:


 class SecurityFilters {
	def filters = {
			basicAuth(controller:'api', action:'*') {
		           before = {
		            	 def authString = request.getHeader('Authorization') 

		            	 if(!authString){
		            		 redirect('500')
		            	 }

		            	 def encodedPair = authString - 'Basic '
		            	 def decodedPair =  new String(new sun.misc.BASE64Decoder().decodeBuffer(encodedPair));
		            	 def credentials = decodedPair.split(':')
		            	 def user = User.findByNameAndPassword(credentials[0],credentials[1])

		            	 if(user){
		            		 session.user = user
		            	 }
		            	 else{

		            		 redirect('500') 

		            	 }
		           }
		     }
}

3: Define a filter called basicAuth which will filter on all controllers and all actions. You can change this to be the specific controller for your API as well as specific the actions you want to authenticate.
4: This specifies that we want a before filter, that will occur before the action is triggered.
5: Extract the value of the “Authorization” header, the value for this is “Basic username:password” where the “username:password” part is Base64 encoded.
7-9: If the request doesn’t have the authorization header we want to redirect the request to an error page, grails already has an URL mapping for “500″ that redirects to an error.gsp, this is fine for now, but you probably want to add a 401 Unauthorized error.

You can do the next few lines a number of ways, I have broken it down into steps to make it easier to follow:

11: Use groovy string-fu to get rid of the “Basic ” part of our authString by subtracting from it.
12: Base64 decode the encoded pair. We could have used grails built in codecs
13: Use a little bit more groovy fu using split() to create an array that contains username and password.
14: Query the User model to match the username and password we just extracted. You should have an authentication scheme that doesn’t involve storing your user’s passwords in plaintext.
16-21: If the user exists we store it in the session and the filter passes to the action, if not redirect with an error.