package org.jasig.cas.client.jetty; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.SimpleInstanceManager; import org.eclipse.jetty.annotations.ServletContainerInitializersStarter; import org.eclipse.jetty.apache.jsp.JettyJasperInitializer; import org.eclipse.jetty.jsp.JettyJspServlet; import org.eclipse.jetty.plus.annotation.ContainerInitializer; import org.eclipse.jetty.security.ConstraintMapping; import org.eclipse.jetty.security.ConstraintSecurityHandler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.webapp.WebAppContext; import org.jasig.cas.client.PublicTestHttpServer; import org.jasig.cas.client.validation.Cas20ServiceTicketValidator; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import static org.junit.Assert.*; /** * Unit test for {@link CasAuthenticator}. * * @author Marvin S. Addison */ public class CasAuthenticatorTest { private static final Server server = new Server(8080); private static final CasAuthenticator authenticator = new CasAuthenticator(); @BeforeClass public static void beforeClass() throws Exception { final WebAppContext context = new WebAppContext(); context.setContextPath("/webapp"); String workingDir = new File(".").getAbsolutePath(); workingDir = workingDir.substring(0, workingDir.length() - 2); final String webappDir; if (workingDir.endsWith("/cas-client-integration-jetty")) { webappDir = workingDir + "/src/test/webapp"; } else { webappDir = workingDir + "/cas-client-integration-jetty/src/test/webapp"; } context.setWar(webappDir); // JSP config from https://github.com/jetty-project/embedded-jetty-jsp/ System.setProperty("org.apache.jasper.compiler.disablejsr199", "false"); context.setAttribute("javax.servlet.context.tempdir", getScratchDir()); context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/.*taglibs.*\\.jar$"); context.setAttribute("org.eclipse.jetty.containerInitializers", jspInitializers()); context.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager()); context.addBean(new ServletContainerInitializersStarter(context), true); context.addServlet(jspServletHolder(), "*.jsp"); // Wire up CAS authentication authenticator.setServerNames("localhost:8080"); authenticator.setTicketValidator(new Cas20ServiceTicketValidator("http://localhost:8081/cas")); // Configure security handling for webapp context final ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler(); final Constraint constraint = new Constraint("CasRealm", Constraint.ANY_AUTH); constraint.setAuthenticate(true); final ConstraintMapping secureMapping = new ConstraintMapping(); secureMapping.setPathSpec("/secure.jsp"); secureMapping.setConstraint(constraint); securityHandler.addConstraintMapping(secureMapping); securityHandler.setAuthenticator(authenticator); context.setSecurityHandler(securityHandler); // Add webapp context and start the server server.setHandler(context); server.start(); } @Test public void testValidateRequestPublicPageNoTicket() throws Exception { final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/"); try { assertEquals(200, uc.getResponseCode()); assertTrue(readOutput(uc).contains("Welcome everyone")); } finally { uc.disconnect(); } } @Test public void testValidateRequestPublicPageWithTicket() throws Exception { final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/?ticket=ST-12345"); try { assertEquals(200, uc.getResponseCode()); assertTrue(readOutput(uc).contains("Welcome everyone")); } finally { uc.disconnect(); } } @Test public void testValidateRequestSecurePageNoTicket() throws Exception { final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/secure.jsp"); try { assertEquals(302, uc.getResponseCode()); assertEquals( "http://localhost:8081/cas/login?service=http%3A%2F%2Flocalhost%3A8080%2Fwebapp%2Fsecure.jsp", uc.getHeaderField("Location")); } finally { uc.disconnect(); } } @Test public void testValidateRequestSecurePageWithTicket() throws Exception { final String successResponse = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>" + "<cas:authenticationSuccess>" + "<cas:user>bob</cas:user>" + "</cas:authenticationSuccess>" + "</cas:serviceResponse>"; final PublicTestHttpServer server = PublicTestHttpServer.instance(8081); server.content = successResponse.getBytes(StandardCharsets.UTF_8); final HttpURLConnection uc = openConnection("http://localhost:8080/webapp/secure.jsp?ticket=ST-12345"); try { assertEquals(200, uc.getResponseCode()); assertTrue(readOutput(uc).contains("Hello bob")); } finally { uc.disconnect(); } } @AfterClass public static void afterClass() throws Exception { server.stop(); } private String readOutput(final URLConnection connection) throws IOException { final InputStreamReader reader = new InputStreamReader(connection.getInputStream()); final StringBuilder builder = new StringBuilder(); final CharBuffer buffer = CharBuffer.allocate(1024); try { while (reader.read(buffer) > 0) { builder.append(buffer.flip()); buffer.clear(); } } finally { reader.close(); } return builder.toString(); } private static File getScratchDir() throws IOException { final File tempDir = new File(System.getProperty("java.io.tmpdir")); final File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp"); if (!scratchDir.exists()) { if (!scratchDir.mkdirs()) { throw new IOException("Unable to create scratch directory: " + scratchDir); } } return scratchDir; } /** * Ensure the jsp engine is initialized correctly */ private static List<ContainerInitializer> jspInitializers() { return Collections.singletonList(new ContainerInitializer(new JettyJasperInitializer(), null)); } /** * Create JSP Servlet (must be named "jsp") */ private static ServletHolder jspServletHolder() { final ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class); holderJsp.setInitOrder(0); holderJsp.setInitParameter("logVerbosityLevel", "DEBUG"); holderJsp.setInitParameter("fork", "false"); holderJsp.setInitParameter("xpoweredBy", "false"); holderJsp.setInitParameter("compilerTargetVM", "1.7"); holderJsp.setInitParameter("compilerSourceVM", "1.7"); holderJsp.setInitParameter("keepgenerated", "true"); return holderJsp; } private static HttpURLConnection openConnection(final String url) throws IOException { final HttpURLConnection uc; try { uc = (HttpURLConnection) new URL(url).openConnection(); } catch (IOException e) { throw new RuntimeException("Invalid URL: " + url, e); } uc.setInstanceFollowRedirects(false); uc.connect(); return uc; } }