package org.geoserver.security.filter; import java.io.File; import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.springframework.mock.web.MockHttpServletRequest; import org.apache.commons.codec.binary.Base64; import org.geoserver.config.GeoServerDataDirectory; import org.geoserver.security.GeoServerSecurityManager; import org.geoserver.security.config.BasicAuthenticationFilterConfig; import org.geoserver.test.GeoServerAbstractTestSupport; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.security.crypto.codec.Hex; public class GeoServerBasicAuthenticationFilterTest { public static final String USERNAME = "admin:"; public static final String PASSWORD = "geoserver"; private static final int NTHREADS = 8; private String expected; private GeoServerBasicAuthenticationFilter authenticationFilter; @Before public void setUp() throws Exception { authenticationFilter = createAuthenticationFilter(); StringBuffer buff = new StringBuffer(PASSWORD); buff.append(":"); buff.append(authenticationFilter.getName()); MessageDigest digest = MessageDigest.getInstance("MD5"); String digestString = new String(Hex.encode(digest.digest(buff.toString().getBytes("utf-8")))); expected = USERNAME + digestString; } @Test public void testMultiThreadGetCacheKey() throws Exception { ExecutorService executor = Executors.newFixedThreadPool(NTHREADS); List<Future<Boolean>> list = new ArrayList<Future<Boolean>>(); for (int i = 0; i < 600; i++) { Callable<Boolean> worker = new AuthenticationCallable(authenticationFilter); Future<Boolean> submit = executor.submit(worker); list.add(submit); } for (Future<Boolean> future : list) { future.get(); } // This will make the executor accept no new threads // and finish all existing threads in the queue executor.shutdown(); } private GeoServerBasicAuthenticationFilter createAuthenticationFilter() { GeoServerBasicAuthenticationFilter authenticationFilter = new GeoServerBasicAuthenticationFilter(); GeoServerSecurityManager sm = null; try { sm = new GeoServerSecurityManager(new GeoServerDataDirectory(new File("target"))); authenticationFilter.setSecurityManager(sm); BasicAuthenticationFilterConfig config = new BasicAuthenticationFilterConfig(); authenticationFilter.initializeFromConfig(config); } catch (Exception e) { throw new RuntimeException("Failed to initialize authentication authenticationFilter."); } return authenticationFilter; } private MockHttpServletRequest createRequest() { MockHttpServletRequest request = new GeoServerAbstractTestSupport.GeoServerMockHttpServletRequest(); request.setScheme("http"); request.setServerName("localhost"); request.setContextPath("/geoserver"); request.setRemoteAddr("127.0.0.1"); String token = "admin:" + PASSWORD; request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes()))); return request; } private class AuthenticationCallable implements Callable<Boolean> { private GeoServerBasicAuthenticationFilter authenticationFilter; private AuthenticationCallable(GeoServerBasicAuthenticationFilter authenticationFilter) { this.authenticationFilter = authenticationFilter; } @Override public Boolean call() throws Exception { MockHttpServletRequest request = createRequest(); String result = authenticationFilter.getCacheKey(request); Assert.assertEquals(expected, result); return true; } } }