Archive for May, 2007

Unit Test Your Web Security

Thursday, May 31st, 2007

Web-based business applications require stringent security measures. Within a secure website, a user must be authenticated by the system and for each different user role a predetermined set of authorization rights must be imposed. This isn’t anything new, and luckily, there exists an open source Java security framework, known as Acegi, which makes the job of keeping those hackers at bay a relatively straightforward one.

Acegi is a powerful, flexible security solution for the Java enterprise application. Working in tandem with its best friend, Spring, it provides applications with comprehensive authentication and authorization capabilities.

Integrating Acegi into your Spring enabled web application is generally an easy, although perhaps sometimes tedious, process of adding a bunch of XML wiring into your Spring context. And after you add that little extra touch of custom configuration for your specific web application, you are good to go.

Or are you? How do you know the thing actually works? And, more importantly, how can you be sure that it will continue to work for every project build? Here’s a JUnit test that shows you how.


package com.twopaths.test.core.security;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;

import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockFilterConfig;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import
  org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ContextLoaderListener;

public class AcegiSecurityTest
  extends AbstractTransactionalDataSourceSpringContextTests {

  private static final String SECURITY_CONTEXT_CLASSPATH =
    "classpath:/com/twopaths/test/core/security-context.xml";

  private static final String TEST_USERNAME = "test";
  private static final String TEST_PASSWORD = "test";

  private MockServletContext servletContext;
  private MockFilterConfig mockConfig;
  private FilterChain mockFilterChain;
  private Filter authenticationFilter;

  @Override
  protected String[] getConfigLocations() {
    return new String[] {SECURITY_CONTEXT_CLASSPATH};
  }

  @Override
  protected void onSetUpInTransaction() throws Exception {
    // Insert user dummy data
    jdbcTemplate.execute("insert into end_user values(1, 'ROLE_USR', '" +
      TEST_USERNAME + "', '" +
      TEST_PASSWORD + "', 'true')");
  }

  @Override
  protected void onSetUpBeforeTransaction() throws Exception {
    // Init servlet context mock
    servletContext = new MockServletContext("");
    servletContext.addInitParameter(
      ContextLoader.CONFIG_LOCATION_PARAM,
      SECURITY_CONTEXT_CLASSPATH);

    // Init servlet context listener
    ServletContextListener contextListener = new ContextLoaderListener();
    ServletContextEvent event = new ServletContextEvent(servletContext);
    contextListener.contextInitialized(event);

    // Init filter config and filter chain mocks
    mockConfig = new MockFilterConfig(servletContext);
    mockFilterChain = new MockFilterChain();

    // Init authentication filter
    authenticationFilter = (Filter)
      this.getApplicationContext().getBean("authenticationProcessingFilter");
    authenticationFilter.init(mockConfig);
  }

  public void testThatTestUserLogsInOk() throws Exception {
    // Build mock request
    MockHttpServletRequest request =
      new MockHttpServletRequest("POST", "/j_acegi_security_check");
    request.setParameter(
      AuthenticationProcessingFilter.ACEGI_SECURITY_FORM_USERNAME_KEY,
      TEST_USERNAME);
    request.setParameter(
      AuthenticationProcessingFilter.ACEGI_SECURITY_FORM_PASSWORD_KEY,
      TEST_PASSWORD);

    // Build mock response
    MockHttpServletResponse response = new MockHttpServletResponse();

    // Run authentication filter
    authenticationFilter.doFilter(request, response, mockFilterChain);

    // Get authentication instance
    Authentication authentication =
      SecurityContextHolder.getContext().getAuthentication();

    // Verify authentication instance
    assertNotNull(authentication);
    assertEquals(TEST_USERNAME, authentication.getName());

    // Verify response redirected URL
    assertEquals("/home", response.getRedirectedUrl());
  }

}

Learning curve

Wednesday, May 30th, 2007

Many people would prefer to bask in comfort as an established expert in their field, with the experience and confidence to prevail in their domain, rather than struggle as a novice in unfamiliar territory. I actually prefer the bracing challenges of being steep on the learning curve.

Not being handy to the open ocean, I don’t really have the ready opportunity to become a very skilled surfer. There is sheltered water nearby, and I spend a lot of time on and around the Straight of Georgia in a sailboat, and have gained a degree of expertise in that domain. However, there is no substitute for the untempered swell of the west coast, so I take a surf trip a couple times a year, to keep in touch with the Pacific’s primal forces.

In the course of a recent three day trip, I was subjected the usual large doses of humility, but at the same time, there were brief flashes of exhilaration, and the genuine satisfaction of achievement - from breaking one’s own barriers - that are unobtainable once one has reached their peak. Sailing is a lot of fun, and I’m certainly still learning, but I get a lot of pleasure from dramatically raising my surfing skills in a single weekend.

The same principle applies at work. The java world is changing rapidly, and there is much work to be done to keep up with the technology. Beyond that, we are maturing as a company, constantly improving our processes and methodology, and we all enjoy the satisfaction of raising our own bar. We are actively using Java 5 as our language of choice, AJAX in our UI, and JPA for database integration needs. In the last couple of months, we’ve revamped our build automation infrastructure with the help of Subversion, Continuum, and Selenium. And keeping up with currently in-vogue agile methodologies, two of our team recently certified as Scrum masters.

With each improvement, we not only enhance our ability to deliver agile, high quality, rapidly developed custom applications, we also reap the tremendous satisfaction of continuous learning and personal achievement.

Eclipse WTP 1.5.4 and 2.0RC1 for OS X

Monday, May 28th, 2007

I’ve downloaded and hand-configured the latest Eclipse WTP builds for your convenience. I’d included the Subclipse SVN plugin as well. If there are any other plugins you’d like to see by default in the future, let me know.

First of all, if you haven’t installed this update to the Java SWT libraries from Apple, do it now. It should improve stability with Eclipse.

Download: SWT Compatibility Update (188KB)

Eclipse WTP 1.5.4 is the latest update to the WTP 1.5 line. Not anything new, but contains numerous bug fixes etc.

Download: Eclipse WTP 1.5.4 (183.9MB)

Eclipse WTP 2.0 RC1 is based on Eclipse 3.3 RC1 and appears to be fairly stable. Some of the new features are support for Tomcat 6, support for JPA projects (annotations, , mappings etc), built in support for web services, and spell checking. This is pre-release, so use at your own risk (I’ve been using it and it seems ok, although I keep my 1.5.4 around just incase).

Download: Eclipse WTP 2.0RC1 (227MB)

Remember to update your copy of eclipse regularly to receive the latest bugfixes, or better yet, set it to auto update in preferences.

Automating Asynchronous Jobs with Java 5 and Spring

Friday, May 25th, 2007

<< The Spiel >>

Java 5 brings a new arsenal of weaponry when it comes to creating highly scalable concurrent applications. The JVM has been improved to allow classes to take advantage of hardware-level concurrency support, and a rich set of new concurrency classes has been provided to make it easier to develop thread-safe, well-tested, high-performance concurrent applications.

The following code example makes full use of these new features and leverages the power of Spring to fully automate an asynchronous job to run periodically for a given duration (or forever if required). There is also a couple of extra goodies in the bag. Not only do jobs get kicked off, we also get a result back when they finish. And if the unimaginable happens and the job hangs, no problem, a timeout will occur, thus ensuring that no threads are left hanging around to hinder our application’s robustness.

<< The Brains >>

package com.twopaths.core.asynchronous;

import static java.util.concurrent.TimeUnit.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class AsynchronousProcessor<T>
    implements Runnable, ApplicationContextAware {

  protected final Log logger = LogFactory.getLog(this.getClass());

  protected static boolean started = false;

  private ScheduledFuture handle;

  // Specifies which bean in spring to instantiate as a new job
  // Default is job
  private String jobBean = "job";

  // Specified initial delay before kicking off the first job
  // Default is 1 second
  private int initialDelay = 1;

  // Specifies the delay between finishing and starting a new job
  // Default is 10 seconds
  private int delay = 10;

  // Specifies how long to wait for a job to complete before timing out
  // Default is 60 seconds
  private int timeout = 60;

  // Specifies how long job will keep running
  // Default is 1 hour. Set to zero to run forever.
  private int duration = 60 * 60;

  protected final ScheduledExecutorService scheduler =
      Executors.newScheduledThreadPool(1);
  protected final ExecutorService THREADPOOL =
      Executors.newCachedThreadPool();

  private ApplicationContext applicationContext;

  public void setApplicationContext(ApplicationContext applicationContext)
      throws BeansException {
    this.applicationContext = applicationContext;
  }

  public AsynchronousProcessor() {
    this.start();
  }

  protected synchronized void start() {
    if (!this.started) { // Ensures that it only starts up once
      this.started = true;
      final ScheduledFuture handle =
        scheduler.scheduleWithFixedDelay(this, this.getInitialDelay(),
        this.getDelay(), SECONDS);
      if (this.getDuration() > 0) {
        scheduler.schedule(new Runnable() {
          public void run() {handle.cancel(true);}
        }, this.getDuration(), SECONDS);
      }
      this.setHandle(handle);
    }
  }

  public void run() {
    try {
      Callable<T> job =
        (Callable<T>) applicationContext.getBean(this.getJobBean());
      T result = this.call(job, this.getTimeout());
      this.logger.info(result);
    } catch (Exception e) {
      this.logger.error("Exception occured when running job", e);
    }
  }

  protected <T> T call(Callable<T> c, long timeout)
      throws InterruptedException, ExecutionException, TimeoutException {
    FutureTask<T> t = new FutureTask<T>(c);
    THREADPOOL.execute(t);
    T result = t.get(timeout, SECONDS);
    return result;
  }

  public void destroy() {
    if ((this.getHandle() != null) && (!this.getHandle().isCancelled())) {
      this.getHandle().cancel(true);
    }
  }

  public String getJobBean() {
    return jobBean;
  }
  public void setJobBean(String jobBean) {
    this.jobBean = jobBean;
  }

  public ScheduledFuture getHandle() {
    return handle;
  }
  protected void setHandle(ScheduledFuture handle) {
    this.handle = handle;
  }

  public int getDelay() {
    return delay;
  }
  public void setDelay(int delay) {
    this.delay = delay;
  }

  public int getInitialDelay() {
    return initialDelay;
  }
  public void setInitialDelay(int initialDelay) {
    this.initialDelay = initialDelay;
  }

  public int getTimeout() {
    return timeout;
  }
  public void setTimeout(int timeout) {
    this.timeout = timeout;
  }

  public int getDuration() {
    return duration;
  }
  public void setDuration(int duration) {
    this.duration = duration;
  }

}

<< The Slave >>

package com.twopaths.core.asynchronous;

import java.util.concurrent.Callable;

public class HelloWorldJob<T> implements Callable<T> {

  private String message = "Hello World"; // default

  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }

  public T call() {
    return (T) message;
  }

}

<< The Glue >>

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”>

  <bean id=”job”
  class=”com.twopaths.core.asynchronous.HelloWorldJob”
  scope=”prototype”/>

  <bean id=”asynchronousProcessor”
  class=”com.twopaths.core.asynchronous.AsynchronousProcessor”
  destroy-method=”destroy”/>

</beans>

A typical day around the 2Paths Coffee Machine

Tuesday, May 22nd, 2007

Coffee, as for all development shops, is a religious institution. Early morning around the expresso machine can get a little dicey especially for those of us working a little close to Vancouver’s downtown eastside. We’re battle hardened. Tough. We like a double shot with a little latte art.

We haven’t got it this hard though:

Never in my biology days did I see something as hardcore as that.

My “hot” new phone - Nokia N95

Tuesday, May 22nd, 2007

After the subtle washing and drying of my previous phone, a Motorola SLVR, it was time to pony up for the next generation. For me at least. Welcome an unlocked N95 from MobilePlanet. UK plugs but I can live with that.

Summary of the first 12 hours:

-wifi connection to our WPA2 Personal network, no probs
-isync plugin from nokia worked seamlessly - contacts + appts all set and loaded
-default email app able to connect over SSL to gmail
-gmail mobile mail app installed, works ok
-Shozu up and running (choosing the N93 to signup), sending pictures to flickr, huzzah!
-battery life hasn’t destroyed it yet

Haven’t bothered with the GPS yet, and therefore no geotagging of photos.

The bad? A few reboots already. Seems to be when connecting to the wifi connection, ah and once using maps. A lockup using the camera with a shoot repeatedly for 10 seconds test.

The other bad? Well I already knew this before buying but there will be no data plan for the phone yet :( It’s just prohibitively expensive, and therefore dangerous to even have a plan. You’d end up racking up charges inadvertently.

Update 20070522 - No more lock ups. A few random reboots and one “an unexpected error has occured please reboot the phone” (or something to that effect). Otherwise - I’m taking a ton more photo’s of my early mornings with the kids and sharing them with the rest of the family that morning. Reminds me of my last nokia moment in Morocco….but that’ll be another story.

Hibernate Tip of the Day - Is it a feature or a bug?

Thursday, May 10th, 2007

Annotations have undoubtedly been a breath of fresh air since coming onto the Java scene, but here’s one big slap in the face which you can’t help but feel is totally unwarranted.

I’m talking about mixing your field and method annotations in Hibernate. This really bares its ugly head when annotating relationships.

Let’s have a look-see at the following code snippet:

@Entity
public class Book {

@Id
@GeneratedValue
private Long id;
private Publisher publisher;

public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

@ManyToOne
public Publisher getPublisher() {
return publisher;
}
public void setPublisher(Publisher publisher) {
this.publisher = publisher;
}
}

So what does Hibernate think of my code? Like a friend who you come to depend on just as they give you the slip and leave you in the lurch, it spits out this exiguous exception:

org.hibernate.MappingException: Could not determine type for: Publisher,
for columns: [org.hibernate.mapping.Column(publisher)]

The real conundrum though, is it a feature or a bug?

Unbelievably, Emmanuel Bernard, the project lead for Hibernate Annotations, states that this is a feature.

Well, Emmanuel, this is one feature (a.k.a. a mighty kick in the cojones) which we could all certainly do without.