/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.security.cas;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.security.AbstractSecurityServiceTest;
import org.geoserver.security.GeoServerSecurityFilterChain;
import org.geoserver.security.GeoServerSecurityFilterChainProxy;
import org.geoserver.security.LogoutFilterChain;
import org.geoserver.security.ServiceLoginFilterChain;
import org.geoserver.security.auth.AbstractAuthenticationProviderTest;
import org.geoserver.security.auth.TestingAuthenticationCache;
import org.geoserver.security.config.PreAuthenticatedUserNameFilterConfig.PreAuthenticatedUserNameRoleSource;
import org.geoserver.security.filter.GeoServerLogoutFilter;
import org.geoserver.security.impl.GeoServerRole;
import org.geoserver.security.impl.GeoServerUser;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsServer;
/**
* A running cas server is needed
*
* To activate the test a file ".geoserver/cas.properties" in the home directory is needed.
*
* Content # Fixture for cas # casserverurlprefix=https://ux-server02.mc-home.local:8443/cas
* service=https://ux-desktop03.mc-home.local:4711/geoserver/j_spring_cas_security_check
* proxycallbackurlprefix=https://ux-desktop03.mc-home.local:4711/geoserver/
*
* Client ssl configuration: Create a keystore keystore.jks in home_dir/.geoserver with key store
* key password "changeit"
*
* Create self signing certificate keytool -genkey -alias mc-home.local -keystore rsa-keystore
* -keyalg RSA -sigalg MD5withRSA -validity 365000
*
* Only the cn must be set to the full server name "ux-desktop03.mc-home.local"
*
* Export the certificate keytool -export -alias mc-home.local -keystore keystore.jks -file
* ux-desktop03.crt
*
* For the cas server copy ux-desktop03.crt to the server
*
* Find cacerts file for the virtual machine running cas
*
* Import the certificate
*
* keytool -import -trustcacerts -alias mc-home.local -file ux-desktop03.crt \ -keystore
* /usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/security/cacerts
*
* The keystore password for cacerts is "changeit"
*
* Next, export the certificate of tomcat and import it into the cacerts of your java sdk
*
* @author christian
*
*/
public class CasAuthenticationTest extends AbstractAuthenticationProviderTest {
static URL casServerURLPrefix;
static URL serviceUrl;
static URL loginUrl;
static URL proxyCallbackUrlPrefix;
static HttpsServer httpsServer;
public class HttpsProxyCallBackHandler implements HttpHandler {
@Override
public void handle(HttpExchange ex) throws IOException {
URI uri = ex.getRequestURI();
ex.getRequestBody().close();
LOGGER.info("Cas proxy callback: " + uri.toString());
String query = uri.getQuery();
MockHttpServletRequest request = createRequest(GeoServerCasConstants.CAS_PROXY_RECEPTOR_PATTERN);
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
// CAS sends the callback twice, the first time without parameters
if (query != null) {
request.setQueryString(query);
String[] kvps = query.split("&");
for (String kvp : kvps) {
String[] tmp = kvp.split("=");
request.addParameter(tmp[0], tmp[1]);
}
}
try {
getProxy().doFilter(request, response, chain);
} catch (ServletException e) {
throw new RuntimeException(e);
}
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
ex.sendResponseHeaders(200, 0);
ex.getResponseBody().close();
}
}
public class SingleSignOutHandler implements HttpHandler {
private String service;
public String getService() {
return service;
}
public SingleSignOutHandler(String servicePath) {
service = servicePath;
}
@Override
public void handle(HttpExchange ex) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(ex.getRequestBody()));
String line = "";
StringBuffer buff = new StringBuffer();
while ((line = in.readLine()) != null) {
buff.append(line);
}
in.close();
MockHttpServletRequest request = createRequest(service);
request.setMethod("POST");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
String paramValue = URLDecoder.decode(buff.toString(), "utf-8");
request.addParameter("logoutRequest", paramValue.substring(paramValue.indexOf("=") + 1));
try {
GeoServerSecurityFilterChainProxy proxy = getProxy();
System.out.println("SERVCIE: " + service);
System.out.println("URL: " + request.getRequestURL().toString());
for (SecurityFilterChain c : proxy.getFilterChains()) {
System.out.println(c.toString());
}
proxy.doFilter(request, response, chain);
} catch (ServletException e) {
throw new RuntimeException(e);
}
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
ex.sendResponseHeaders(200, 0);
ex.getResponseBody().close();
}
}
@Before
public void checkOnline() {
Assume.assumeTrue(getTestData().isTestDataAvailable());
}
@Override
protected SystemTestData createTestData() throws Exception {
return new LiveCasData(AbstractSecurityServiceTest.unpackTestDataDir());
}
@Override
protected void onSetUp(org.geoserver.data.test.SystemTestData testData) throws Exception {
super.onSetUp(testData);
LiveCasData td = (LiveCasData) getTestData();
casServerURLPrefix = td.getServerURLPrefix();
loginUrl = td.getLoginURL();
serviceUrl = td.getServiceURL();
proxyCallbackUrlPrefix = td.getProxyCallbackURLPrefix();
if (httpsServer == null) {
httpsServer = createAndStartHttpsServer();
td.checkSSLServer();
}
}
protected HttpsServer createAndStartHttpsServer() throws Exception {
HttpsServer httpsServer = ((LiveCasData) getTestData()).createSSLServer();
URL callbackUrl = new URL(
GeoServerCasConstants.createProxyCallBackURl(proxyCallbackUrlPrefix.toString()));
httpsServer.createContext(callbackUrl.getPath(), new HttpsProxyCallBackHandler());
httpsServer.createContext(createRequest("/j_spring_cas_security_check").getRequestURI(),
new SingleSignOutHandler("/j_spring_cas_security_check"));
httpsServer.createContext(createRequest("/wms").getRequestURI(), new SingleSignOutHandler(
"/wms"));
httpsServer.start();
return httpsServer;
}
protected String getResponseHeaderValue(HttpURLConnection conn, String name) {
for (int i = 0;; i++) {
String headerName = conn.getHeaderFieldKey(i);
String headerValue = conn.getHeaderField(i);
if (headerName == null && headerValue == null) {
// No more headers
break;
}
if (name.equalsIgnoreCase(headerName)) {
return headerValue;
}
}
return null;
}
@Test
public void testCASLogin() throws Exception {
String casFilterName = "testCasFilter1";
CasAuthenticationFilterConfig config = new CasAuthenticationFilterConfig();
config.setClassName(GeoServerCasAuthenticationFilter.class.getName());
config.setCasServerUrlPrefix(casServerURLPrefix.toString());
config.setName(casFilterName);
config.setRoleSource(PreAuthenticatedUserNameRoleSource.UserGroupService);
config.setUserGroupServiceName("ug1");
config.setSingleSignOut(true);
getSecurityManager().saveFilter(config);
prepareFilterChain(pattern,casFilterName);
modifyChain(pattern, false, true, null);
SecurityContextHolder.getContext().setAuthentication(null);
// Test entry point
MockHttpServletRequest request = createRequest("/foo/bar");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
getProxy().doFilter(request, response, chain);
assertTrue(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
String redirectURL = response.getHeader("Location");
assertTrue(redirectURL.contains(GeoServerCasConstants.LOGIN_URI));
assertTrue(redirectURL.endsWith("bar"));
// test success
String username = "castest";
String password = username;
CasFormAuthenticationHelper helper = new CasFormAuthenticationHelper(casServerURLPrefix,username,password);
helper.ssoLogin();
request = createRequest("/foo/bar");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
String ticket =loginUsingTicket(helper, request, response, chain);
assertFalse(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
SecurityContext ctx = (SecurityContext) request.getSession(false).getAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
assertNotNull(ctx);
Authentication auth = ctx.getAuthentication();
assertNotNull(auth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
checkForAuthenticatedRole(auth);
assertEquals(username, auth.getPrincipal());
assertTrue(auth.getAuthorities().contains(new GeoServerRole(rootRole)));
assertTrue(auth.getAuthorities().contains(new GeoServerRole(derivedRole)));
assertNotNull(GeoServerCasAuthenticationFilter.getHandler().getSessionMappingStorage()
.removeSessionByMappingId(ticket));
helper.ssoLogout();
// check unknown user
username = "unknown";
password = username;
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, password);
helper.ssoLogin();
request = createRequest("/foo/bar");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
ticket =loginUsingTicket(helper, request, response, chain);
assertFalse(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
ctx = (SecurityContext) request.getSession(true).getAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
assertNotNull(ctx);
auth = ctx.getAuthentication();
assertNotNull(auth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
checkForAuthenticatedRole(ctx.getAuthentication());
assertEquals(username, auth.getPrincipal());
assertEquals(1, auth.getAuthorities().size());
assertNotNull(GeoServerCasAuthenticationFilter.getHandler().getSessionMappingStorage()
.removeSessionByMappingId(ticket));
helper.ssoLogout();
// test root user
username = GeoServerUser.ROOT_USERNAME;
password = username;
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, password);
helper.ssoLogin();
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request = createRequest("/foo/bar");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
ticket =loginUsingTicket(helper, request, response, chain);
ctx = (SecurityContext) request.getSession(true).getAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
assertFalse(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
auth = ctx.getAuthentication();
assertNotNull(auth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
// checkForAuthenticatedRole(auth);
assertEquals(GeoServerUser.ROOT_USERNAME, auth.getPrincipal());
assertTrue(auth.getAuthorities().size() == 1);
assertTrue(auth.getAuthorities().contains(GeoServerRole.ADMIN_ROLE));
assertNotNull(GeoServerCasAuthenticationFilter.getHandler().getSessionMappingStorage()
.removeSessionByMappingId(ticket));
helper.ssoLogout();
// check disabled user
username = "castest";
password = username;
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, password);
helper.ssoLogin();
updateUser("ug1", username, false);
request = createRequest("/foo/bar");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
ticket =loginUsingTicket(helper, request, response, chain);
assertTrue(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
redirectURL = response.getHeader("Location");
assertTrue(redirectURL.contains("login"));
ctx = (SecurityContext) request.getSession(true).getAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
assertNull(ctx);
assertNull(SecurityContextHolder.getContext().getAuthentication());
assertNull(GeoServerCasAuthenticationFilter.getHandler().getSessionMappingStorage()
.removeSessionByMappingId(ticket));
updateUser("ug1", username, true);
helper.ssoLogout();
insertAnonymousFilter();
request = createRequest("foo/bar");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
// Anonymous context is not stored in http session, no further testing
removeAnonymousFilter();
// test invalid ticket
username = "castest";
password = username;
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, password);
helper.ssoLogin();
request = createRequest("/foo/bar");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
ticket = helper.getServiceTicket(new URL(request.getRequestURL().toString()));
ticket += "ST-A";
request.addParameter("ticket", ticket);
request.setQueryString("ticket=" + ticket);
getProxy().doFilter(request, response, chain);
assertTrue(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
redirectURL = response.getHeader("Location");
assertTrue(redirectURL.contains(GeoServerCasConstants.LOGIN_URI));
ctx = (SecurityContext) request.getSession(true).getAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
assertNull(ctx);
assertNull(SecurityContextHolder.getContext().getAuthentication());
assertNull(GeoServerCasAuthenticationFilter.getHandler().getSessionMappingStorage()
.removeSessionByMappingId(ticket));
helper.ssoLogout();
// test success with proxy granting ticket
config.setProxyCallbackUrlPrefix(proxyCallbackUrlPrefix.toString());
getSecurityManager().saveFilter(config);
username = "castest";
password = username;
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, password);
helper.ssoLogin();
request = createRequest("/foo/bar");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
ticket = helper.getServiceTicket(new URL(request.getRequestURL().toString()));
request.addParameter("ticket", ticket);
request.setQueryString("ticket=" + ticket);
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
// assertTrue(response.wasRedirectSent());
// redirectUrl = response.getHeader("Location");
// assertNotNull(redirectUrl);
ctx = (SecurityContext) request.getSession(true).getAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
assertNotNull(ctx);
PreAuthenticatedAuthenticationToken casAuth = (PreAuthenticatedAuthenticationToken) ctx.getAuthentication();
assertNotNull(casAuth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
checkForAuthenticatedRole(casAuth);
assertEquals(username, casAuth.getPrincipal());
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(rootRole)));
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(derivedRole)));
Assertion ass = (Assertion) request.getSession(true).getAttribute(GeoServerCasConstants.CAS_ASSERTION_KEY);
assertNotNull(ass);
String proxyTicket = ass.getPrincipal()
.getProxyTicketFor("http://localhost/blabla");
assertNotNull(proxyTicket);
assertNotNull(GeoServerCasAuthenticationFilter.getHandler().getSessionMappingStorage()
.removeSessionByMappingId(ticket));
helper.ssoLogout();
}
@Test
public void testLogout() throws Exception {
LogoutFilterChain logoutchain =
(LogoutFilterChain) getSecurityManager().getSecurityConfig().getFilterChain().getRequestChainByName("webLogout");
String casFilterName = "testCasFilter2";
CasAuthenticationFilterConfig config = new CasAuthenticationFilterConfig();
config.setClassName(GeoServerCasAuthenticationFilter.class.getName());
config.setCasServerUrlPrefix(casServerURLPrefix.toString());
config.setName(casFilterName);
config.setRoleSource(PreAuthenticatedUserNameRoleSource.UserGroupService);
config.setUserGroupServiceName("ug1");
config.setSingleSignOut(true);
getSecurityManager().saveFilter(config);
// put a CAS filter on an active chain
prepareFilterChain(pattern,casFilterName);
modifyChain(pattern, false, true, null);
SecurityContextHolder.getContext().setAuthentication(null);
getCache().removeAll();
// login
String username = "castest";
String password = username;
CasFormAuthenticationHelper helper = new CasFormAuthenticationHelper(casServerURLPrefix,
username, password);
helper.ssoLogin();
MockHttpServletRequest request = createRequest(pattern);
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
loginUsingTicket(helper, request, response, chain);
assertFalse(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
SecurityContext ctx = (SecurityContext) request.getSession(false).getAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
assertNotNull(ctx);
Authentication auth = ctx.getAuthentication();
assertNotNull(auth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
MockHttpSession session = (MockHttpSession) request.getSession(false);
assertNotNull(session);
assertFalse(session.isInvalid());
// logout triggered by geoserver
request = createRequest(logoutchain.getPatterns().get(0));
//request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, ctx);
SecurityContextHolder.setContext(ctx);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
//getProxy().doFilter(request, response, chain);
GeoServerLogoutFilter logoutFilter=
(GeoServerLogoutFilter) getSecurityManager().loadFilter(GeoServerSecurityFilterChain.FORM_LOGOUT_FILTER);
logoutFilter.doFilter(request, response, chain);
assertTrue(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
String redirectUrl = response.getHeader("Location");
assertNotNull(redirectUrl);
assertTrue(redirectUrl.contains(GeoServerCasConstants.LOGOUT_URI));
session = (MockHttpSession) request.getSession(false);
// login
helper = new CasFormAuthenticationHelper(casServerURLPrefix,
username, password);
helper.ssoLogin();
request = createRequest(pattern);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
String ticket = loginUsingTicket(helper, request, response, chain);
assertFalse(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
ctx = (SecurityContext) request.getSession(false).getAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
assertNotNull(ctx);
auth = ctx.getAuthentication();
assertNotNull(auth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
session = (MockHttpSession) request.getSession(false);
assertNotNull(session);
assertFalse(session.isInvalid());
// logout triggered by cas server
request = createRequest(pattern);
//request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, ctx);
SecurityContextHolder.setContext(ctx);
request.setMethod("POST");
request.setSession(session);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("logoutRequest", getBodyForLogoutRequest(ticket));
GeoServerCasAuthenticationFilter casFilter = (GeoServerCasAuthenticationFilter)
getSecurityManager().loadFilter(casFilterName);
//getProxy().doFilter(request, response, chain);
casFilter.doFilter(request, response, chain);
assertTrue(response.getStatus() == MockHttpServletResponse.SC_MOVED_TEMPORARILY);
redirectUrl = response.getHeader("Location");
assertNotNull(redirectUrl);
assertFalse(redirectUrl.contains(GeoServerCasConstants.LOGOUT_URI));
}
protected Assertion authenticateWithPGT(CasFormAuthenticationHelper helper) throws Exception {
helper.ssoLogin();
String ticket = helper.getServiceTicket(serviceUrl);
Cas20ProxyTicketValidator validator = new Cas20ProxyTicketValidator(
casServerURLPrefix.toString());
validator.setAcceptAnyProxy(true);
validator.setProxyCallbackUrl(GeoServerCasConstants
.createProxyCallBackURl(proxyCallbackUrlPrefix.toExternalForm()));
validator.setProxyGrantingTicketStorage(GeoServerExtensions
.bean(ProxyGrantingTicketStorage.class));
Assertion result = validator.validate(ticket, serviceUrl.toExternalForm());
assertNotNull(result);
return result;
}
@Test
public void testAuthWithServiceTicket() throws Exception {
pattern = "/wms/**";
String casProxyFilterName = "testCasProxyFilter1";
CasAuthenticationFilterConfig pconfig1 = new CasAuthenticationFilterConfig();
pconfig1.setClassName(GeoServerCasAuthenticationFilter.class.getName());
pconfig1.setName(casProxyFilterName);
pconfig1.setCasServerUrlPrefix(casServerURLPrefix.toString());
pconfig1.setRoleSource(PreAuthenticatedUserNameRoleSource.UserGroupService);
pconfig1.setUserGroupServiceName("ug1");
pconfig1.setSingleSignOut(true);
getSecurityManager().saveFilter(pconfig1);
prepareFilterChain(ServiceLoginFilterChain.class ,pattern,casProxyFilterName);
SecurityContextHolder.getContext().setAuthentication(null);
// test entry point
MockHttpServletRequest request = createRequest("wms");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
request.addParameter("ticket", "ST-blabla");
request.setQueryString("ticket=ST-blabla");
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getStatus());
// test successful
getCache().removeAll();
String username = "castest";
CasFormAuthenticationHelper helper = new CasFormAuthenticationHelper(casServerURLPrefix,
username, username);
helper.ssoLogin();
request = createRequest("wms");
request.setQueryString("request=getCapabilities");
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
String ticket = helper.getServiceTicket(new URL(request.getRequestURL().toString() + "?"
+ request.getQueryString()));
assertNotNull(ticket);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", ticket);
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
TestingAuthenticationCache cache = getCache();
Authentication casAuth = cache.get(casProxyFilterName, username);
assertNotNull(casAuth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
checkForAuthenticatedRole(casAuth);
assertEquals(username, casAuth.getPrincipal());
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(rootRole)));
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(derivedRole)));
assertNotNull(request.getAttribute(GeoServerCasConstants.CAS_ASSERTION_KEY));
assertNull(GeoServerCasAuthenticationFilter.getHandler().getSessionMappingStorage()
.removeSessionByMappingId(ticket));
helper.ssoLogout();
// check unknown user
username = "unknown";
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, username);
helper.ssoLogin();
request = createRequest("wms");
ticket = helper.getServiceTicket(new URL(request.getRequestURL().toString()));
assertNotNull(ticket);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", ticket);
request.setQueryString("ticket=" + ticket);
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
cache = getCache();
casAuth = cache.get(casProxyFilterName, username);
assertNotNull(casAuth);
assertNotNull(casAuth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
checkForAuthenticatedRole(casAuth);
assertEquals(username, casAuth.getPrincipal());
assertEquals(1, casAuth.getAuthorities().size());
assertNotNull(request.getAttribute(GeoServerCasConstants.CAS_ASSERTION_KEY));
// check for disabled user
getCache().removeAll();
updateUser("ug1", "castest", false);
username = "castest";
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, username);
helper.ssoLogin();
request = createRequest("wms");
ticket = helper.getServiceTicket(new URL(request.getRequestURL().toString()));
assertNotNull(ticket);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", ticket);
request.setQueryString("ticket=" + ticket);
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getStatus());
cache = getCache();
casAuth = cache.get(casProxyFilterName, ticket);
assertNull(casAuth);
assertNull(request.getAttribute(GeoServerCasConstants.CAS_ASSERTION_KEY));
assertNull(request.getSession(false));
updateUser("ug1", "castest", true);
helper.ssoLogout();
// Test anonymous
insertAnonymousFilter();
request = createRequest("wms");
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
// Anonymous context is not stored in http session, no further testing
removeAnonymousFilter();
// test proxy granting ticket
pconfig1.setProxyCallbackUrlPrefix(proxyCallbackUrlPrefix.toString());
getSecurityManager().saveFilter(pconfig1);
getCache().removeAll();
username = "castest";
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, username);
authenticateWithPGT(helper);
request = createRequest("wms");
ticket = helper.getServiceTicket(new URL(request.getRequestURL().toString()));
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
assertNotNull(ticket);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", ticket);
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
cache = getCache();
casAuth = cache.get(casProxyFilterName, username);
assertNotNull(casAuth);
assertNotNull(casAuth);
assertNull(SecurityContextHolder.getContext().getAuthentication());
checkForAuthenticatedRole(casAuth);
assertEquals(username, casAuth.getPrincipal());
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(rootRole)));
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(derivedRole)));
String proxyTicket = ((Assertion) request.getAttribute(
GeoServerCasConstants.CAS_ASSERTION_KEY)).getPrincipal().getProxyTicketFor(
"http://localhost/blabla");
assertNotNull(proxyTicket);
helper.ssoLogout();
}
@Test
public void testAuthWithProxyTicket() throws Exception {
pattern = "/wms/**";
String casProxyFilterName = "testCasProxyFilter2";
CasAuthenticationFilterConfig pconfig1 = new CasAuthenticationFilterConfig();
pconfig1.setClassName(GeoServerCasAuthenticationFilter.class.getName());
pconfig1.setName(casProxyFilterName);
pconfig1.setCasServerUrlPrefix(casServerURLPrefix.toString());
pconfig1.setRoleSource(PreAuthenticatedUserNameRoleSource.UserGroupService);
pconfig1.setUserGroupServiceName("ug1");
getSecurityManager().saveFilter(pconfig1);
prepareFilterChain(ServiceLoginFilterChain.class ,pattern,casProxyFilterName);
// prepareFilterChain(GeoServerCasConstants.CAS_PROXY_RECEPTOR_PATTERN,
// casFilterName);
// prepareFilterChain("/j_spring_cas_security_check",
// GeoServerSecurityFilterChain.SECURITY_CONTEXT_ASC_FILTER,
// casFilterName);
SecurityContextHolder.getContext().setAuthentication(null);
// test entry point with header attribute
MockHttpServletRequest request = createRequest("wms");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
request.addParameter("ticket", "ST-blabla");
request.setQueryString("ticket=ST-blabla");
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getStatus());
// test entry point with url param
request = createRequest("wms");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", "ST-blabla");
request.addParameter(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
request.setQueryString("ticket=ST-blabla&"+GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT+"=false");
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getStatus());
// test successful
getCache().removeAll();
String username = "castest";
CasFormAuthenticationHelper helper = new CasFormAuthenticationHelper(casServerURLPrefix,
username, username);
Assertion ass = authenticateWithPGT(helper);
String proxyTicket = null;
for (int i = 0; i < 2; i++) {
request = createRequest("wms");
request.setQueryString("request=getCapabilities");
proxyTicket = ass.getPrincipal().getProxyTicketFor(
request.getRequestURL().toString() + "?" + request.getQueryString());
assertNotNull(proxyTicket);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", proxyTicket);
if (i==0) {
request.addParameter(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
request.setQueryString(request.getQueryString()+"&ticket="+proxyTicket+"&"+GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT+"=false");
} else {
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
request.setQueryString(request.getQueryString()+"&ticket="+proxyTicket);
}
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
TestingAuthenticationCache cache = getCache();
Authentication casAuth = cache.get(casProxyFilterName, username);
assertNotNull(casAuth);
checkForAuthenticatedRole(casAuth);
assertEquals(username, casAuth.getPrincipal());
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(rootRole)));
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(derivedRole)));
assertNotNull(request.getAttribute(GeoServerCasConstants.CAS_ASSERTION_KEY));
assertNull(request.getSession(false));
}
assertNull(GeoServerCasAuthenticationFilter.getHandler().getSessionMappingStorage()
.removeSessionByMappingId(proxyTicket));
helper.ssoLogout();
// check unknown user
username = "unknown";
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, username);
ass = authenticateWithPGT(helper);
for (int i = 0; i < 2; i++) {
request = createRequest("wms");
request.setQueryString("request=getCapabilities");
proxyTicket = ass.getPrincipal().getProxyTicketFor(request.getRequestURL().toString() + "?" + request.getQueryString());
assertNotNull(proxyTicket);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", proxyTicket);
if (i==0) {
request.addParameter(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
request.setQueryString(request.getQueryString()+"&ticket="+proxyTicket+"&"+GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT+"=false");
} else {
request.addHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
request.setQueryString(request.getQueryString()+"&ticket="+proxyTicket);
}
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
TestingAuthenticationCache cache = getCache();
Authentication casAuth = cache.get(casProxyFilterName, username);
assertNotNull(casAuth);
checkForAuthenticatedRole(casAuth);
assertEquals(username, casAuth.getPrincipal());
assertEquals(1, casAuth.getAuthorities().size());
assertNotNull(request.getAttribute(GeoServerCasConstants.CAS_ASSERTION_KEY));
assertNull(request.getSession(false));
}
helper.ssoLogout();
// check for disabled user
getCache().removeAll();
updateUser("ug1", "castest", false);
username = "castest";
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, username);
ass = authenticateWithPGT(helper);
request = createRequest("wms");
proxyTicket = ass.getPrincipal().getProxyTicketFor(request.getRequestURL().toString());
assertNotNull(proxyTicket);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", proxyTicket);
request.addParameter(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
request.setQueryString("ticket="+proxyTicket+"&"+GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT+"=false");
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getStatus());
TestingAuthenticationCache cache = getCache();
Authentication casAuth = cache.get(casProxyFilterName, proxyTicket);
assertNull(casAuth);
assertNull(request.getAttribute(GeoServerCasConstants.CAS_ASSERTION_KEY));
assertNull(request.getSession(false));
updateUser("ug1", "castest", true);
helper.ssoLogout();
// Test anonymous
insertAnonymousFilter();
request = createRequest("wms");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
// Anonymous context is not stored in http session, no further testing
removeAnonymousFilter();
// test proxy granting ticket in proxied auth filter
pconfig1.setProxyCallbackUrlPrefix(proxyCallbackUrlPrefix.toString());
getSecurityManager().saveFilter(pconfig1);
getCache().removeAll();
username = "castest";
helper = new CasFormAuthenticationHelper(casServerURLPrefix, username, username);
ass = authenticateWithPGT(helper);
request = createRequest("wms");
proxyTicket = ass.getPrincipal().getProxyTicketFor(request.getRequestURL().toString());
assertNotNull(proxyTicket);
response = new MockHttpServletResponse();
chain = new MockFilterChain();
request.addParameter("ticket", proxyTicket);
getProxy().doFilter(request, response, chain);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
cache = getCache();
casAuth = cache.get(casProxyFilterName, username);
assertNotNull(casAuth);
checkForAuthenticatedRole(casAuth);
assertEquals(username, casAuth.getPrincipal());
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(rootRole)));
assertTrue(casAuth.getAuthorities().contains(new GeoServerRole(derivedRole)));
proxyTicket = ((Assertion) request.getAttribute(GeoServerCasConstants.CAS_ASSERTION_KEY))
.getPrincipal().getProxyTicketFor("http://localhost/blabla");
assertNotNull(proxyTicket);
helper.ssoLogout();
}
// protected MockHttpServletRequest createRequest(String url) {
// MockHttpServletRequest request = super.createRequest(url);
// request.setProtocol(serviceUrl.getProtocol());
// request.setScheme(serviceUrl.getProtocol());
// request.setServerName(serviceUrl.getHost());
// request.setServerPort(serviceUrl.getPort());
// return request;
// }
@Test
public void testCasAuthenticationHelper() throws Exception {
CasFormAuthenticationHelper helper = new CasFormAuthenticationHelper(casServerURLPrefix,
"fail", "abc");
assertFalse(helper.ssoLogin());
helper = new CasFormAuthenticationHelper(casServerURLPrefix,"success","success");
assertTrue(helper.ssoLogin());
assertNotNull(helper.getTicketGrantingCookie());
LOGGER.info("TGC after login : " + helper.getTicketGrantingCookie());
assertTrue(helper.ssoLogout());
assertNotNull(helper.getTicketGrantingCookie());
LOGGER.info("TGC after logout : " + helper.getTicketGrantingCookie());
assertTrue(helper.ssoLogin());
assertNotNull(helper.getTicketGrantingCookie());
String ticket = helper.getServiceTicket(serviceUrl);
assertNotNull(ticket);
assertTrue(ticket.startsWith("ST-"));
LOGGER.info("ST : " + ticket);
helper.ssoLogout();
}
protected String getBodyForLogoutRequest(String ticket) {
String template = "<LogoutRequest ID=\"[RANDOM ID]\" Version=\"2.0\" IssueInstant=\"[CURRENT DATE/TIME]\">"
+ "<NameID>@NOT_USED@</NameID>"
+ "<SessionIndex>[SESSION IDENTIFIER]</SessionIndex>" + "</LogoutRequest>";
return template.replace("[SESSION IDENTIFIER]", ticket);
}
protected String loginUsingTicket(CasFormAuthenticationHelper helper, MockHttpServletRequest request,
MockHttpServletResponse response,MockFilterChain chain) throws Exception {
String ticket = helper.getServiceTicket(new URL(request.getRequestURL().toString()));
request.setQueryString("ticket=" + ticket);
request.addParameter("ticket", ticket);
getProxy().doFilter(request, response, chain);
return ticket;
}
}