Porting of custom Luminis API to Grails Done

Quite some time ago I developed a set of APIs that other developers at my institution could use. I documented these APIs at our wiki page here REST API for Luminis. Now these APIs were written to run in the servlet container which houses Luminis III which for those not familiar with that particular product uses Java 1.3.

Recently for another project I have been working on I had a need to add a new API to the mix that would return a list of courses a student is taking. I had a fellow developer build an Oracle package that would return a list of courses given a user’s student or employee they are connected to. Unfortunately the results of this package would not work over a database link which as it exists in a database different from what Luminis uses would require me to setup a separate connection to that database.

Not enjoying the idea of developing a database connection pool strategy for this new database using Java 1.3, and as I have recently began to play with Grails for yet another project I decided to try and port my existing set of APIs over to Grails. This way I could take advantage of a number of plug-ins for Grails including database connection pooling.

For this project I used the following Grails plug-ins:

  • Spring Security Core – allows you to secure pages within your Grails application
  • LDAP – this does for LDAP what GORM does for databases
  • datasources (note the s) – this allows you to specify multiple datasources in your Grails application

This has been a fun project to do over my spring break vacation as it has allowed me to learn a new approach to developing applications at work as well as allowing me to get one step closer to completing my clients project for the end of next month. I am still far from being an expert in Grails but I can see how much faster development can be in using it. All that I have left for my new API conversion is to put in the last little bit of code that will obtain the course list (so far I have just ported existing code over to Grails). My next post should be about adding the course list functionality to the API suite.

Posted in Programming | Tagged , , , | Comments Off

Remote posting and Twitter

image

Just a test to see if I can post to my blog from my phone. This post should also get auto tweeted for me.

Posted in news | Tagged , , | Comments Off

Custom Security Filter for Grails Spring Security 3 plugin

Introduction
I am converting an existing set of Java servlets to Grails. These servlets act as a RESTful API which take in addition to the API’s specific parameters two parameters to authenticate the request before handing over the information. In playing with Grails I very much enjoyed setting up my project to use the Grails Security Plugin. With minimal effort I was able to get the plugin to authenticate user’s using their existing credentials from the legacy system.

The Problem
Out of the box things worked well in the sense that if I visited one of the API’s URL if I had not authenticated myself it would direct me to a login page where I could supply the required credentials and then be sent back to the page I was requesting. Not bad when doing this interactively, but I desire to maintain the current functionality that I have where the credentials can be part of the URL. l also did not wish to change the name of the current parameters as I wish to make this change as transparent as possible.

My Solution
I found a number of articles that spoke of creating a custom filter (Hacking Custom Authentication Providers with Grails Spring Security this was for the previous ACEGI plugin and How do I implement a custom FilterSecurityInterceptor using grails 1.3.2 and the plugin spring-security-core 1?) however none of them worked perfectly for me.

In the end I took information from both of these pages and some poking around in the spring security core and web sources to put the following together. No unlike the two articles above I opted not to create my own Authentication Token as I decided to use the UsernamePasswordAuthenticationToken as it represented what I wanted (plus I had it working with the credentials when entered into a form). I also did not create my own Authentication Provider using the out of the box providers for much the same reason as not creating my own Authentication Token.

First up is my custom Filter:

package ca.umanitoba.ist.es.portal.api

import org.springframework.beans.factory.InitializingBean
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.authentication.*

import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.filter.GenericFilterBean

import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @date created on 2011/03/25 William Moore
 *
 * @version $Revision: $ $Date: $ $Author: $
 *
 * @class APIAuthenticationFilter
 * @brief This class adds a filter to handle URLs where the API credentials
 *        are supplied with the REST request
 *
 */
class APIAuthenticationFilter extends GenericFilterBean implements ApplicationEventPublisherAware {
    def authenticationManager
    def eventPublisher
    def rememberMeServices
    def springSecurityService
    AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler()
    AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler()

    void afterPropertiesSet() {
        assert authenticationManager != null, 'authenticationManager must be specified'
        assert rememberMeServices != null, 'rememberMeServices must be specified'
    }

    void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req
        HttpServletResponse response = (HttpServletResponse) res

        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            def username = request.getParameter("apikey")
            def password = request.getParameter("apisec") 

            Authentication auth
            UsernamePasswordAuthenticationToken upat

            if ( username && password ) {
                try {
                    upat = new UsernamePasswordAuthenticationToken(username, password)

                    if (upat != null) {
                        auth = authenticationManager.authenticate(upat)

                        logger.debug("Authentication success: " + auth);

                        onSuccessfulAuthentication(request, response, auth)
                    }
                } catch (AuthenticationException authenticationException) {
                    onUnsuccessfulAuthentication(request, response, authenticationException)
                } catch(e) {
                    onUnsuccessfulAuthentication(request, response, e)
                }
            }
        }
        chain.doFilter(req, res)
    }

    protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) {
        SecurityContextHolder.getContext().setAuthentication(authResult)
        rememberMeServices.onLoginSuccess(request, response, authResult)
    }

    protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
        SecurityContextHolder.clearContext();
        rememberMeServices.loginFail(request, response)
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher
    }
}

Now after creating the Filter I need to add a bean to my resources file

import ca.umanitoba.ist.es.portal.api.APIAuthenticationFilter
beans = {
   [ .. ]
    apiAuthFilter(APIAuthenticationFilter) {
        authenticationManager = ref("authenticationManager")
        rememberMeServices = ref("rememberMeServices")
        springSecurityService = ref("springSecurityService")
    }
}

Once this was done I needed to add my Filter to the existing chain of filters, I did this in the bootstrap file

import org.codehaus.groovy.grails.plugins.springsecurity.SecurityFilterPosition
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
class BootStrap {
    [..]
    def init = { servletContext ->
        [..]
        SpringSecurityUtils.clientRegisterFilter('apiAuthFilter', SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order + 10)
        [..]
    }
    [..]
}

Conclusion
I can still access the API interactively which will be nice for testing them out, but can also pass the credentials they way we are used to so that existing applications will continue to work with no hassle.

Posted in Programming | Tagged , , | 1 Comment

UPS Status Online Again

There I now have my UPS status information online again after the big crash of Jan 2010. I am using APCUPSD a rather nice software package for monitoring APC UPS’.

Posted in system | Tagged | Comments Off