Package org.geoserver.security.cas

Source Code of org.geoserver.security.cas.CasAuthenticationTest$SingleSignOutHandler

/* (c) 2014 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 com.mockrunner.mock.web.MockFilterChain;
import com.mockrunner.mock.web.MockHttpServletRequest;
import com.mockrunner.mock.web.MockHttpServletResponse;
import com.mockrunner.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
*
* 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.setupAddParameter(tmp[0], tmp[1]);
                }
            }

            try {
                getProxy().doFilter(request, response, chain);
            } catch (ServletException e) {
                throw new RuntimeException(e);
            }
            assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());

            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.setupAddParameter("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.getErrorCode());

            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();

    }

    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;
    }

    // disabled
    @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);

        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertTrue(response.wasRedirectSent());
        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);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertFalse(response.wasRedirectSent());


        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);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertFalse(response.wasRedirectSent());

       
        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);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertFalse(response.wasRedirectSent());
        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);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertTrue(response.wasRedirectSent());
        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.getErrorCode());
        // 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.setupAddParameter("ticket", ticket);
        request.setQueryString("ticket=" + ticket);

        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertTrue(response.wasRedirectSent());
        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.setupAddParameter("ticket", ticket);
        request.setQueryString("ticket=" + ticket);
        getProxy().doFilter(request, response, chain);

        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
//        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);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertFalse(response.wasRedirectSent());


        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);
        assertTrue(session.isValid());



        // 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);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertTrue(response.wasRedirectSent());
        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);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertFalse(response.wasRedirectSent());


        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);
        assertTrue(session.isValid());

       
        // 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.setupAddParameter("logoutRequest", getBodyForLogoutRequest(ticket));
        GeoServerCasAuthenticationFilter casFilter = (GeoServerCasAuthenticationFilter)
                getSecurityManager().loadFilter(casFilterName);
        //getProxy().doFilter(request, response, chain);
        casFilter.doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        assertTrue(response.wasRedirectSent());
        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.setupAddParameter("ticket", "ST-blabla");
        request.setQueryString("ticket=ST-blabla");
        request.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getErrorCode());

        // test successful
        getCache().removeAll();
        String username = "castest";
        CasFormAuthenticationHelper helper = new CasFormAuthenticationHelper(casServerURLPrefix,
                username, username);
        helper.ssoLogin();

        request = createRequest("wms");
        request.setQueryString("request=getCapabilities");
        request.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        String ticket = helper.getServiceTicket(new URL(request.getRequestURL().toString() + "?"
                + request.getQueryString()));
        assertNotNull(ticket);
        response = new MockHttpServletResponse();
        chain = new MockFilterChain();
        request.setupAddParameter("ticket", ticket);
        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        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.setupAddParameter("ticket", ticket);
        request.setQueryString("ticket=" + ticket);
        request.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        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.setupAddParameter("ticket", ticket);
        request.setQueryString("ticket=" + ticket);
        request.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getErrorCode());
        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.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        response = new MockHttpServletResponse();
        chain = new MockFilterChain();
        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        // 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.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        assertNotNull(ticket);

        response = new MockHttpServletResponse();
        chain = new MockFilterChain();
        request.setupAddParameter("ticket", ticket);
        getProxy().doFilter(request, response, chain);

        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        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.setupAddParameter("ticket", "ST-blabla");
        request.setQueryString("ticket=ST-blabla");
        request.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getErrorCode());
       
        // test entry point with url param
        request = createRequest("wms");
        response = new MockHttpServletResponse();
        chain = new MockFilterChain();
        request.setupAddParameter("ticket", "ST-blabla");
        request.setupAddParameter(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        request.setQueryString("ticket=ST-blabla&"+GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT+"=false");       
        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getErrorCode());


        // 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.setupAddParameter("ticket", proxyTicket);
            if (i==0) {
                request.setupAddParameter(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
                request.setQueryString(request.getQueryString()+"&ticket="+proxyTicket+"&"+GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT+"=false");
            } else {
                request.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
                request.setQueryString(request.getQueryString()+"&ticket="+proxyTicket);
            }           
            getProxy().doFilter(request, response, chain);
            assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
            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.setupAddParameter("ticket", proxyTicket);
            if (i==0) {
                request.setupAddParameter(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
                request.setQueryString(request.getQueryString()+"&ticket="+proxyTicket+"&"+GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT+"=false");
            } else {
                request.setHeader(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
                request.setQueryString(request.getQueryString()+"&ticket="+proxyTicket);
            }           
            getProxy().doFilter(request, response, chain);
            assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
            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.setupAddParameter("ticket", proxyTicket);
        request.setupAddParameter(GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT, "false");
        request.setQueryString("ticket="+proxyTicket+"&"+GeoServerCasAuthenticationEntryPoint.CAS_REDIRECT+"=false");

        getProxy().doFilter(request, response, chain);
        assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getErrorCode());
        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.getErrorCode());
        // 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.setupAddParameter("ticket", proxyTicket);
        getProxy().doFilter(request, response, chain);

        assertEquals(HttpServletResponse.SC_OK, response.getErrorCode());
        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.setupAddParameter("ticket", ticket);
        getProxy().doFilter(request, response, chain);
        return ticket;
    }

}
TOP

Related Classes of org.geoserver.security.cas.CasAuthenticationTest$SingleSignOutHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.