diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java index 83aae6ec7c8..99dce3fe88c 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java @@ -235,41 +235,50 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr List mappings = new ArrayList(); //Create a constraint that will describe the default case (ie if not overridden by specific HttpMethodConstraints) - Constraint constraint = ConstraintSecurityHandler.createConstraint(name, securityElement); - - //Create a mapping for the pathSpec for the default case - ConstraintMapping defaultMapping = new ConstraintMapping(); - defaultMapping.setPathSpec(pathSpec); - defaultMapping.setConstraint(constraint); - mappings.add(defaultMapping); + Constraint httpConstraint = null; + ConstraintMapping httpConstraintMapping = null; + + if (securityElement.getEmptyRoleSemantic() != EmptyRoleSemantic.PERMIT || + securityElement.getRolesAllowed().length != 0 || + securityElement.getTransportGuarantee() != TransportGuarantee.NONE) + { + httpConstraint = ConstraintSecurityHandler.createConstraint(name, securityElement); + //Create a mapping for the pathSpec for the default case + httpConstraintMapping = new ConstraintMapping(); + httpConstraintMapping.setPathSpec(pathSpec); + httpConstraintMapping.setConstraint(httpConstraint); + mappings.add(httpConstraintMapping); + } + //See Spec 13.4.1.2 p127 List methodOmissions = new ArrayList(); //make constraint mappings for this url for each of the HttpMethodConstraintElements - Collection methodConstraints = securityElement.getHttpMethodConstraints(); - if (methodConstraints != null) + Collection methodConstraintElements = securityElement.getHttpMethodConstraints(); + if (methodConstraintElements != null) { - for (HttpMethodConstraintElement methodConstraint:methodConstraints) + for (HttpMethodConstraintElement methodConstraintElement:methodConstraintElements) { //Make a Constraint that captures the and elements supplied for the HttpMethodConstraintElement - Constraint mconstraint = ConstraintSecurityHandler.createConstraint(name, methodConstraint); + Constraint methodConstraint = ConstraintSecurityHandler.createConstraint(name, methodConstraintElement); ConstraintMapping mapping = new ConstraintMapping(); - mapping.setConstraint(mconstraint); + mapping.setConstraint(methodConstraint); mapping.setPathSpec(pathSpec); - if (methodConstraint.getMethodName() != null) + if (methodConstraintElement.getMethodName() != null) { - mapping.setMethod(methodConstraint.getMethodName()); + mapping.setMethod(methodConstraintElement.getMethodName()); //See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint - methodOmissions.add(methodConstraint.getMethodName()); + methodOmissions.add(methodConstraintElement.getMethodName()); } mappings.add(mapping); } } //See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint - if (methodOmissions.size() > 0) - defaultMapping.setMethodOmissions(methodOmissions.toArray(new String[methodOmissions.size()])); + //UNLESS the default constraint contains all default values. In that case, we won't add it. See Servlet Spec 3.1 pg 129 + if (methodOmissions.size() > 0 && httpConstraintMapping != null) + httpConstraintMapping.setMethodOmissions(methodOmissions.toArray(new String[methodOmissions.size()])); return mappings; } diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java index 780abf94d25..42ddacfe62f 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java @@ -40,7 +40,12 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.servlet.HttpConstraintElement; +import javax.servlet.HttpMethodConstraintElement; import javax.servlet.ServletException; +import javax.servlet.ServletSecurityElement; +import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; +import javax.servlet.annotation.ServletSecurity.TransportGuarantee; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -222,6 +227,154 @@ public class ConstraintTest assertFalse(mappings.get(3).getConstraint().getAuthenticate()); } + + /** + * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-1 + * @ServletSecurity + * @throws Exception + */ + @Test + public void testSecurityElementExample13_1() throws Exception + { + ServletSecurityElement element = new ServletSecurityElement(); + List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath("foo", "/foo/*", element); + assertTrue(mappings.isEmpty()); + } + + + /** + * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-2 + * @ServletSecurity(@HttpConstraint(transportGuarantee = TransportGuarantee.CONFIDENTIAL)) + * + * @throws Exception + */ + @Test + public void testSecurityElementExample13_2() throws Exception + { + HttpConstraintElement httpConstraintElement = new HttpConstraintElement(TransportGuarantee.CONFIDENTIAL, new String[]{}); + ServletSecurityElement element = new ServletSecurityElement(httpConstraintElement); + List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath("foo", "/foo/*", element); + assertTrue(!mappings.isEmpty()); + assertEquals(1, mappings.size()); + ConstraintMapping mapping = mappings.get(0); + assertEquals(2, mapping.getConstraint().getDataConstraint()); + } + + /** + * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-3 + * @ServletSecurity(@HttpConstraint(EmptyRoleSemantic.DENY)) + * @throws Exception + */ + @Test + public void testSecurityElementExample13_3() throws Exception + { + HttpConstraintElement httpConstraintElement = new HttpConstraintElement(EmptyRoleSemantic.DENY); + ServletSecurityElement element = new ServletSecurityElement(httpConstraintElement); + List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath("foo", "/foo/*", element); + assertTrue(!mappings.isEmpty()); + assertEquals(1, mappings.size()); + ConstraintMapping mapping = mappings.get(0); + assertTrue(mapping.getConstraint().isForbidden()); + } + + /** + * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-4 + * @ServletSecurity(@HttpConstraint(rolesAllowed = "R1")) + * @throws Exception + */ + @Test + public void testSecurityElementExample13_4() throws Exception + { + HttpConstraintElement httpConstraintElement = new HttpConstraintElement(TransportGuarantee.NONE, "R1"); + ServletSecurityElement element = new ServletSecurityElement(httpConstraintElement); + List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath("foo", "/foo/*", element); + assertTrue(!mappings.isEmpty()); + assertEquals(1, mappings.size()); + ConstraintMapping mapping = mappings.get(0); + assertTrue(mapping.getConstraint().getAuthenticate()); + assertTrue(mapping.getConstraint().getRoles() != null); + assertEquals(1, mapping.getConstraint().getRoles().length); + assertEquals("R1", mapping.getConstraint().getRoles()[0]); + assertEquals(0, mapping.getConstraint().getDataConstraint()); + } + + /** + * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-5 + * @ServletSecurity((httpMethodConstraints = { + * @HttpMethodConstraint(value = "GET", rolesAllowed = "R1"), + * @HttpMethodConstraint(value = "POST", rolesAllowed = "R1", + * transportGuarantee = TransportGuarantee.CONFIDENTIAL)}) + * @throws Exception + */ + @Test + public void testSecurityElementExample13_5() throws Exception + { + List methodElements = new ArrayList(); + methodElements.add(new HttpMethodConstraintElement("GET", new HttpConstraintElement(TransportGuarantee.NONE, "R1"))); + methodElements.add(new HttpMethodConstraintElement("POST", new HttpConstraintElement(TransportGuarantee.CONFIDENTIAL, "R1"))); + ServletSecurityElement element = new ServletSecurityElement(methodElements); + List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath("foo", "/foo/*", element); + assertTrue(!mappings.isEmpty()); + assertEquals(2, mappings.size()); + assertEquals("GET", mappings.get(0).getMethod()); + assertEquals("R1", mappings.get(0).getConstraint().getRoles()[0]); + assertTrue(mappings.get(0).getMethodOmissions() == null); + assertEquals(0, mappings.get(0).getConstraint().getDataConstraint()); + assertEquals("POST", mappings.get(1).getMethod()); + assertEquals("R1", mappings.get(1).getConstraint().getRoles()[0]); + assertEquals(2, mappings.get(1).getConstraint().getDataConstraint()); + assertTrue(mappings.get(1).getMethodOmissions() == null); + } + + /** + * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-6 + * @ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"), httpMethodConstraints = @HttpMethodConstraint("GET")) + * @throws Exception + */ + @Test + public void testSecurityElementExample13_6 () throws Exception + { + List methodElements = new ArrayList(); + methodElements.add(new HttpMethodConstraintElement("GET")); + ServletSecurityElement element = new ServletSecurityElement(new HttpConstraintElement(TransportGuarantee.NONE, "R1"), methodElements); + List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath("foo", "/foo/*", element); + assertTrue(!mappings.isEmpty()); + assertEquals(2, mappings.size()); + assertTrue(mappings.get(0).getMethodOmissions() != null); + assertEquals("GET", mappings.get(0).getMethodOmissions()[0]); + assertTrue(mappings.get(0).getConstraint().getAuthenticate()); + assertEquals("R1", mappings.get(0).getConstraint().getRoles()[0]); + assertEquals("GET", mappings.get(1).getMethod()); + assertTrue(mappings.get(1).getMethodOmissions() == null); + assertEquals(0, mappings.get(1).getConstraint().getDataConstraint()); + assertFalse(mappings.get(1).getConstraint().getAuthenticate()); + } + + /** + * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-7 + * @ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"), + * httpMethodConstraints = @HttpMethodConstraint(value="TRACE", + * emptyRoleSemantic = EmptyRoleSemantic.DENY)) + * @throws Exception + */ + @Test + public void testSecurityElementExample13_7() throws Exception + { + List methodElements = new ArrayList(); + methodElements.add(new HttpMethodConstraintElement("TRACE", new HttpConstraintElement(EmptyRoleSemantic.DENY))); + ServletSecurityElement element = new ServletSecurityElement(new HttpConstraintElement(TransportGuarantee.NONE, "R1"), methodElements); + List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath("foo", "/foo/*", element); + assertTrue(!mappings.isEmpty()); + assertEquals(2, mappings.size()); + assertTrue(mappings.get(0).getMethodOmissions() != null); + assertEquals("TRACE", mappings.get(0).getMethodOmissions()[0]); + assertTrue(mappings.get(0).getConstraint().getAuthenticate()); + assertEquals("R1", mappings.get(0).getConstraint().getRoles()[0]); + assertEquals("TRACE", mappings.get(1).getMethod()); + assertTrue(mappings.get(1).getMethodOmissions() == null); + assertEquals(0, mappings.get(1).getConstraint().getDataConstraint()); + assertTrue(mappings.get(1).getConstraint().isForbidden()); + } @Test public void testUncoveredHttpMethodDetection() throws Exception