Unit Test Your Web Security
Thursday, May 31st, 2007Web-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());
}
}