blob: 0a08075d66883ee1f0529b0be9b3de52b4b02e4a [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.annotations;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.HttpMethodConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
import javax.servlet.http.HttpServlet;
import org.eclipse.jetty.security.ConstraintAware;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.Test;
public class TestSecurityAnnotationConversions
{
@ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.DENY))
public static class DenyServlet extends HttpServlet
{}
@ServletSecurity
public static class PermitServlet extends HttpServlet
{}
@ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}))
public static class RolesServlet extends HttpServlet
{}
@ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}),
httpMethodConstraints={@HttpMethodConstraint(value="GET")})
public static class Method1Servlet extends HttpServlet
{}
@ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}),
httpMethodConstraints={@HttpMethodConstraint(value="GET", transportGuarantee=TransportGuarantee.CONFIDENTIAL)})
public static class Method2Servlet extends HttpServlet
{}
public void setUp()
{
}
@Test
public void testDenyAllOnClass() throws Exception
{
WebAppContext wac = makeWebAppContext(DenyServlet.class.getCanonicalName(), "denyServlet", new String[]{"/foo/*", "*.foo"});
//Assume we found 1 servlet with a @HttpConstraint with value=EmptyRoleSemantic.DENY security annotation
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
AnnotationIntrospector introspector = new AnnotationIntrospector();
introspector.registerHandler(annotationHandler);
//set up the expected outcomes:
//1 ConstraintMapping per ServletMapping pathSpec
Constraint expectedConstraint = new Constraint();
expectedConstraint.setAuthenticate(true);
expectedConstraint.setDataConstraint(Constraint.DC_NONE);
ConstraintMapping[] expectedMappings = new ConstraintMapping[2];
expectedMappings[0] = new ConstraintMapping();
expectedMappings[0].setConstraint(expectedConstraint);
expectedMappings[0].setPathSpec("/foo/*");
expectedMappings[1] = new ConstraintMapping();
expectedMappings[1].setConstraint(expectedConstraint);
expectedMappings[1].setPathSpec("*.foo");
introspector.introspect(DenyServlet.class);
compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
@Test
public void testPermitAll() throws Exception
{
//Assume we found 1 servlet with a @ServletSecurity security annotation
WebAppContext wac = makeWebAppContext(PermitServlet.class.getCanonicalName(), "permitServlet", new String[]{"/foo/*", "*.foo"});
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
AnnotationIntrospector introspector = new AnnotationIntrospector();
introspector.registerHandler(annotationHandler);
//set up the expected outcomes - no constraints at all as per Servlet Spec 3.1 pg 129
//1 ConstraintMapping per ServletMapping pathSpec
ConstraintMapping[] expectedMappings = new ConstraintMapping[]{};
introspector.introspect(PermitServlet.class);
compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
@Test
public void testRolesAllowedWithTransportGuarantee() throws Exception
{
//Assume we found 1 servlet with annotation with roles defined and
//and a TransportGuarantee
WebAppContext wac = makeWebAppContext(RolesServlet.class.getCanonicalName(), "rolesServlet", new String[]{"/foo/*", "*.foo"});
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
AnnotationIntrospector introspector = new AnnotationIntrospector();
introspector.registerHandler(annotationHandler);
//set up the expected outcomes:compareResults
//1 ConstraintMapping per ServletMapping
Constraint expectedConstraint = new Constraint();
expectedConstraint.setAuthenticate(true);
expectedConstraint.setRoles(new String[]{"tom", "dick", "harry"});
expectedConstraint.setDataConstraint(Constraint.DC_CONFIDENTIAL);
ConstraintMapping[] expectedMappings = new ConstraintMapping[2];
expectedMappings[0] = new ConstraintMapping();
expectedMappings[0].setConstraint(expectedConstraint);
expectedMappings[0].setPathSpec("/foo/*");
expectedMappings[1] = new ConstraintMapping();
expectedMappings[1].setConstraint(expectedConstraint);
expectedMappings[1].setPathSpec("*.foo");
introspector.introspect(RolesServlet.class);
compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
@Test
public void testMethodAnnotation() throws Exception
{
//ServletSecurity annotation with HttpConstraint of TransportGuarantee.CONFIDENTIAL, and a list of rolesAllowed, and
//a HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default)
WebAppContext wac = makeWebAppContext(Method1Servlet.class.getCanonicalName(), "method1Servlet", new String[]{"/foo/*", "*.foo"});
//set up the expected outcomes: - a Constraint for the RolesAllowed on the class
//with userdata constraint of DC_CONFIDENTIAL
//and mappings for each of the pathSpecs
Constraint expectedConstraint1 = new Constraint();
expectedConstraint1.setAuthenticate(true);
expectedConstraint1.setRoles(new String[]{"tom", "dick", "harry"});
expectedConstraint1.setDataConstraint(Constraint.DC_CONFIDENTIAL);
//a Constraint for the PermitAll on the doGet method with a userdata
//constraint of DC_CONFIDENTIAL inherited from the class
Constraint expectedConstraint2 = new Constraint();
expectedConstraint2.setDataConstraint(Constraint.DC_NONE);
ConstraintMapping[] expectedMappings = new ConstraintMapping[4];
expectedMappings[0] = new ConstraintMapping();
expectedMappings[0].setConstraint(expectedConstraint1);
expectedMappings[0].setPathSpec("/foo/*");
expectedMappings[0].setMethodOmissions(new String[]{"GET"});
expectedMappings[1] = new ConstraintMapping();
expectedMappings[1].setConstraint(expectedConstraint1);
expectedMappings[1].setPathSpec("*.foo");
expectedMappings[1].setMethodOmissions(new String[]{"GET"});
expectedMappings[2] = new ConstraintMapping();
expectedMappings[2].setConstraint(expectedConstraint2);
expectedMappings[2].setPathSpec("/foo/*");
expectedMappings[2].setMethod("GET");
expectedMappings[3] = new ConstraintMapping();
expectedMappings[3].setConstraint(expectedConstraint2);
expectedMappings[3].setPathSpec("*.foo");
expectedMappings[3].setMethod("GET");
AnnotationIntrospector introspector = new AnnotationIntrospector();
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
introspector.registerHandler(annotationHandler);
introspector.introspect(Method1Servlet.class);
compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
@Test
public void testMethodAnnotation2() throws Exception
{
//A ServletSecurity annotation that has HttpConstraint of CONFIDENTIAL with defined roles, but a
//HttpMethodConstraint for GET that permits all, but also requires CONFIDENTIAL
WebAppContext wac = makeWebAppContext(Method2Servlet.class.getCanonicalName(), "method2Servlet", new String[]{"/foo/*", "*.foo"});
AnnotationIntrospector introspector = new AnnotationIntrospector();
ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac);
introspector.registerHandler(annotationHandler);
//set up the expected outcomes: - a Constraint for the RolesAllowed on the class
//with userdata constraint of DC_CONFIDENTIAL
//and mappings for each of the pathSpecs
Constraint expectedConstraint1 = new Constraint();
expectedConstraint1.setAuthenticate(true);
expectedConstraint1.setRoles(new String[]{"tom", "dick", "harry"});
expectedConstraint1.setDataConstraint(Constraint.DC_CONFIDENTIAL);
//a Constraint for the Permit on the GET method with a userdata
//constraint of DC_CONFIDENTIAL
Constraint expectedConstraint2 = new Constraint();
expectedConstraint2.setDataConstraint(Constraint.DC_CONFIDENTIAL);
ConstraintMapping[] expectedMappings = new ConstraintMapping[4];
expectedMappings[0] = new ConstraintMapping();
expectedMappings[0].setConstraint(expectedConstraint1);
expectedMappings[0].setPathSpec("/foo/*");
expectedMappings[0].setMethodOmissions(new String[]{"GET"});
expectedMappings[1] = new ConstraintMapping();
expectedMappings[1].setConstraint(expectedConstraint1);
expectedMappings[1].setPathSpec("*.foo");
expectedMappings[1].setMethodOmissions(new String[]{"GET"});
expectedMappings[2] = new ConstraintMapping();
expectedMappings[2].setConstraint(expectedConstraint2);
expectedMappings[2].setPathSpec("/foo/*");
expectedMappings[2].setMethod("GET");
expectedMappings[3] = new ConstraintMapping();
expectedMappings[3].setConstraint(expectedConstraint2);
expectedMappings[3].setPathSpec("*.foo");
expectedMappings[3].setMethod("GET");
introspector.introspect(Method2Servlet.class);
compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());
}
private void compareResults (ConstraintMapping[] expectedMappings, List<ConstraintMapping> actualMappings)
{
assertNotNull(actualMappings);
assertEquals(expectedMappings.length, actualMappings.size());
for (int k=0; k < actualMappings.size(); k++)
{
ConstraintMapping am = actualMappings.get(k);
boolean matched = false;
for (int i=0; i< expectedMappings.length && !matched; i++)
{
ConstraintMapping em = expectedMappings[i];
if (em.getPathSpec().equals(am.getPathSpec()))
{
if ((em.getMethod()==null && am.getMethod() == null) || em.getMethod() != null && em.getMethod().equals(am.getMethod()))
{
matched = true;
assertEquals(em.getConstraint().getAuthenticate(), am.getConstraint().getAuthenticate());
assertEquals(em.getConstraint().getDataConstraint(), am.getConstraint().getDataConstraint());
if (em.getMethodOmissions() == null)
{
assertNull(am.getMethodOmissions());
}
else
{
assertTrue(Arrays.equals(am.getMethodOmissions(), em.getMethodOmissions()));
}
if (em.getConstraint().getRoles() == null)
{
assertNull(am.getConstraint().getRoles());
}
else
{
assertTrue(Arrays.equals(em.getConstraint().getRoles(), am.getConstraint().getRoles()));
}
}
}
}
if (!matched)
fail("No expected ConstraintMapping matching method:"+am.getMethod()+" pathSpec: "+am.getPathSpec());
}
}
private WebAppContext makeWebAppContext (String className, String servletName, String[] paths)
{
WebAppContext wac = new WebAppContext();
ServletHolder[] holders = new ServletHolder[1];
holders[0] = new ServletHolder();
holders[0].setClassName(className);
holders[0].setName(servletName);
holders[0].setServletHandler(wac.getServletHandler());
wac.getServletHandler().setServlets(holders);
wac.setSecurityHandler(new ConstraintSecurityHandler());
ServletMapping[] servletMappings = new ServletMapping[1];
servletMappings[0] = new ServletMapping();
servletMappings[0].setPathSpecs(paths);
servletMappings[0].setServletName(servletName);
wac.getServletHandler().setServletMappings(servletMappings);
return wac;
}
}