/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.descriptor.web;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.HttpConstraintElement;
import javax.servlet.HttpMethodConstraintElement;
import javax.servlet.ServletSecurityElement;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Assert;
import org.junit.Test;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
public class TestSecurityConstraint {
private static final String URL_PATTERN = "/test";
private static final String ROLE1 = "R1";
private static final Log DUMMY_LOG = LogFactory.getLog("DUMMY");
private static final SecurityConstraint GET_ONLY;
private static final SecurityConstraint POST_ONLY;
private static final SecurityConstraint GET_OMIT;
private static final SecurityConstraint POST_OMIT;
static {
// Configure the constraints to use in the tests
GET_ONLY = new SecurityConstraint();
GET_ONLY.addAuthRole(ROLE1);
SecurityCollection scGetOnly = new SecurityCollection();
scGetOnly.addMethod("GET");
scGetOnly.addPatternDecoded(URL_PATTERN);
scGetOnly.setName("GET-ONLY");
GET_ONLY.addCollection(scGetOnly);
POST_ONLY = new SecurityConstraint();
POST_ONLY.addAuthRole(ROLE1);
SecurityCollection scPostOnly = new SecurityCollection();
scPostOnly.addMethod("POST");
scPostOnly.addPatternDecoded(URL_PATTERN);
scPostOnly.setName("POST_ONLY");
POST_ONLY.addCollection(scPostOnly);
GET_OMIT = new SecurityConstraint();
GET_OMIT.addAuthRole(ROLE1);
SecurityCollection scGetOmit = new SecurityCollection();
scGetOmit.addOmittedMethod("GET");
scGetOmit.addPatternDecoded(URL_PATTERN);
scGetOmit.setName("GET_OMIT");
GET_OMIT.addCollection(scGetOmit);
POST_OMIT = new SecurityConstraint();
POST_OMIT.addAuthRole(ROLE1);
SecurityCollection scPostOmit = new SecurityCollection();
scPostOmit.addOmittedMethod("POST");
scPostOmit.addPatternDecoded(URL_PATTERN);
scPostOmit.setName("POST_OMIT");
POST_OMIT.addCollection(scPostOmit);
}
/**
* Uses the examples in SRV.13.4 as the basis for these tests
*/
@Test
public void testCreateConstraints() {
ServletSecurityElement element;
SecurityConstraint[] result;
Set<HttpMethodConstraintElement> hmces = new HashSet<>();
// Example 13-1
// @ServletSecurity
element = new ServletSecurityElement();
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
assertEquals(0, result.length);
// Example 13-2
// @ServletSecurity(
// @HttpConstraint(
// transportGuarantee = TransportGuarantee.CONFIDENTIAL))
element = new ServletSecurityElement(
new HttpConstraintElement(
ServletSecurity.TransportGuarantee.CONFIDENTIAL));
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
assertEquals(1, result.length);
assertFalse(result[0].getAuthConstraint());
assertTrue(result[0].findCollections()[0].findPattern(URL_PATTERN));
assertEquals(0, result[0].findCollections()[0].findMethods().length);
assertEquals(ServletSecurity.TransportGuarantee.CONFIDENTIAL.name(),
result[0].getUserConstraint());
// Example 13-3
// @ServletSecurity(@HttpConstraint(EmptyRoleSemantic.DENY))
element = new ServletSecurityElement(
new HttpConstraintElement(EmptyRoleSemantic.DENY));
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
assertEquals(1, result.length);
assertTrue(result[0].getAuthConstraint());
assertTrue(result[0].findCollections()[0].findPattern(URL_PATTERN));
assertEquals(0, result[0].findCollections()[0].findMethods().length);
assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
result[0].getUserConstraint());
// Example 13-4
// @ServletSecurity(@HttpConstraint(rolesAllowed = "R1"))
element = new ServletSecurityElement(new HttpConstraintElement(
ServletSecurity.TransportGuarantee.NONE, ROLE1));
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
assertEquals(1, result.length);
assertTrue(result[0].getAuthConstraint());
assertEquals(1, result[0].findAuthRoles().length);
assertTrue(result[0].findAuthRole(ROLE1));
assertTrue(result[0].findCollections()[0].findPattern(URL_PATTERN));
assertEquals(0, result[0].findCollections()[0].findMethods().length);
assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
result[0].getUserConstraint());
// Example 13-5
// @ServletSecurity((httpMethodConstraints = {
// @HttpMethodConstraint(value = "GET", rolesAllowed = "R1"),
// @HttpMethodConstraint(value = "POST", rolesAllowed = "R1",
// transportGuarantee = TransportGuarantee.CONFIDENTIAL)
// })
hmces.clear();
hmces.add(new HttpMethodConstraintElement("GET",
new HttpConstraintElement(
ServletSecurity.TransportGuarantee.NONE, ROLE1)));
hmces.add(new HttpMethodConstraintElement("POST",
new HttpConstraintElement(
ServletSecurity.TransportGuarantee.CONFIDENTIAL,
ROLE1)));
element = new ServletSecurityElement(hmces);
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
assertEquals(2, result.length);
for (int i = 0; i < 2; i++) {
assertTrue(result[i].getAuthConstraint());
assertEquals(1, result[i].findAuthRoles().length);
assertTrue(result[i].findAuthRole(ROLE1));
assertTrue(result[i].findCollections()[0].findPattern(URL_PATTERN));
assertEquals(1, result[i].findCollections()[0].findMethods().length);
String method = result[i].findCollections()[0].findMethods()[0];
if ("GET".equals(method)) {
assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
result[i].getUserConstraint());
} else if ("POST".equals(method)) {
assertEquals(ServletSecurity.TransportGuarantee.CONFIDENTIAL.name(),
result[i].getUserConstraint());
} else {
fail("Unexpected method :[" + method + "]");
}
}
// Example 13-6
// @ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"),
// httpMethodConstraints = @HttpMethodConstraint("GET"))
hmces.clear();
hmces.add(new HttpMethodConstraintElement("GET"));
element = new ServletSecurityElement(
new HttpConstraintElement(
ServletSecurity.TransportGuarantee.NONE,
ROLE1),
hmces);
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
assertEquals(2, result.length);
for (int i = 0; i < 2; i++) {
assertTrue(result[i].findCollections()[0].findPattern(URL_PATTERN));
if (result[i].findCollections()[0].findMethods().length == 1) {
assertEquals("GET",
result[i].findCollections()[0].findMethods()[0]);
assertFalse(result[i].getAuthConstraint());
} else if (result[i].findCollections()[0].findOmittedMethods().length == 1) {
assertEquals("GET",
result[i].findCollections()[0].findOmittedMethods()[0]);
assertTrue(result[i].getAuthConstraint());
assertEquals(1, result[i].findAuthRoles().length);
assertEquals(ROLE1, result[i].findAuthRoles()[0]);
} else {
fail("Unexpected number of methods defined");
}
assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
result[i].getUserConstraint());
}
// Example 13-7
// @ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"),
// httpMethodConstraints = @HttpMethodConstraint(value="TRACE",
// emptyRoleSemantic = EmptyRoleSemantic.DENY))
hmces.clear();
hmces.add(new HttpMethodConstraintElement("TRACE",
new HttpConstraintElement(EmptyRoleSemantic.DENY)));
element = new ServletSecurityElement(
new HttpConstraintElement(
ServletSecurity.TransportGuarantee.NONE,
ROLE1),
hmces);
result = SecurityConstraint.createConstraints(element, URL_PATTERN);
assertEquals(2, result.length);
for (int i = 0; i < 2; i++) {
assertTrue(result[i].findCollections()[0].findPattern(URL_PATTERN));
if (result[i].findCollections()[0].findMethods().length == 1) {
assertEquals("TRACE",
result[i].findCollections()[0].findMethods()[0]);
assertTrue(result[i].getAuthConstraint());
assertEquals(0, result[i].findAuthRoles().length);
} else if (result[i].findCollections()[0].findOmittedMethods().length == 1) {
assertEquals("TRACE",
result[i].findCollections()[0].findOmittedMethods()[0]);
assertTrue(result[i].getAuthConstraint());
assertEquals(1, result[i].findAuthRoles().length);
assertEquals(ROLE1, result[i].findAuthRoles()[0]);
} else {
fail("Unexpected number of methods defined");
}
assertEquals(ServletSecurity.TransportGuarantee.NONE.name(),
result[i].getUserConstraint());
}
// Example 13-8 is the same as 13-4
// Example 13-9 is the same as 13-7
}
@Test
public void testFindUncoveredHttpMethods01() {
// No new constraints if denyUncoveredHttpMethods is false
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_ONLY}, false, DUMMY_LOG);
Assert.assertEquals(0, result.length);
}
@Test
public void testFindUncoveredHttpMethods02() {
// No new constraints if denyUncoveredHttpMethods is false
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_OMIT}, false, DUMMY_LOG);
Assert.assertEquals(0, result.length);
}
@Test
public void testFindUncoveredHttpMethods03() {
// No new constraints if denyUncoveredHttpMethods is false
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {POST_ONLY}, false, DUMMY_LOG);
Assert.assertEquals(0, result.length);
}
@Test
public void testFindUncoveredHttpMethods04() {
// No new constraints if denyUncoveredHttpMethods is false
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {POST_OMIT}, false, DUMMY_LOG);
Assert.assertEquals(0, result.length);
}
@Test
public void testFindUncoveredHttpMethods05() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_ONLY}, true, DUMMY_LOG);
Assert.assertEquals(1, result.length);
// Should be a deny constraint
Assert.assertTrue(result[0].getAuthConstraint());
// Should have a single collection
Assert.assertEquals(1, result[0].findCollections().length);
SecurityCollection sc = result[0].findCollections()[0];
// Should list GET as an omitted method
Assert.assertEquals(0, sc.findMethods().length);
Assert.assertEquals(1, sc.findOmittedMethods().length);
Assert.assertEquals("GET", sc.findOmittedMethods()[0]);
}
@Test
public void testFindUncoveredHttpMethods06() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {POST_ONLY}, true, DUMMY_LOG);
Assert.assertEquals(1, result.length);
// Should be a deny constraint
Assert.assertTrue(result[0].getAuthConstraint());
// Should have a single collection
Assert.assertEquals(1, result[0].findCollections().length);
SecurityCollection sc = result[0].findCollections()[0];
// Should list POST as an omitted method
Assert.assertEquals(0, sc.findMethods().length);
Assert.assertEquals(1, sc.findOmittedMethods().length);
Assert.assertEquals("POST", sc.findOmittedMethods()[0]);
}
@Test
public void testFindUncoveredHttpMethods07() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_OMIT}, true, DUMMY_LOG);
Assert.assertEquals(1, result.length);
// Should be a deny constraint
Assert.assertTrue(result[0].getAuthConstraint());
// Should have a single collection
Assert.assertEquals(1, result[0].findCollections().length);
SecurityCollection sc = result[0].findCollections()[0];
// Should list GET as an method
Assert.assertEquals(0, sc.findOmittedMethods().length);
Assert.assertEquals(1, sc.findMethods().length);
Assert.assertEquals("GET", sc.findMethods()[0]);
}
@Test
public void testFindUncoveredHttpMethods08() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {POST_OMIT}, true, DUMMY_LOG);
Assert.assertEquals(1, result.length);
// Should be a deny constraint
Assert.assertTrue(result[0].getAuthConstraint());
// Should have a single collection
Assert.assertEquals(1, result[0].findCollections().length);
SecurityCollection sc = result[0].findCollections()[0];
// Should list POST as an method
Assert.assertEquals(0, sc.findOmittedMethods().length);
Assert.assertEquals(1, sc.findMethods().length);
Assert.assertEquals("POST", sc.findMethods()[0]);
}
@Test
public void testFindUncoveredHttpMethods09() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_ONLY, GET_OMIT}, true,
DUMMY_LOG);
Assert.assertEquals(0, result.length);
}
@Test
public void testFindUncoveredHttpMethods10() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {POST_ONLY, POST_OMIT}, true,
DUMMY_LOG);
Assert.assertEquals(0, result.length);
}
@Test
public void testFindUncoveredHttpMethods11() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_ONLY, POST_ONLY}, true,
DUMMY_LOG);
Assert.assertEquals(1, result.length);
// Should be a deny constraint
Assert.assertTrue(result[0].getAuthConstraint());
// Should have a single collection
Assert.assertEquals(1, result[0].findCollections().length);
SecurityCollection sc = result[0].findCollections()[0];
// Should list GET and POST as omitted methods
Assert.assertEquals(0, sc.findMethods().length);
Assert.assertEquals(2, sc.findOmittedMethods().length);
HashSet<String> omittedMethods = new HashSet<>();
for (String omittedMethod : sc.findOmittedMethods()) {
omittedMethods.add(omittedMethod);
}
Assert.assertTrue(omittedMethods.remove("GET"));
Assert.assertTrue(omittedMethods.remove("POST"));
}
@Test
public void testFindUncoveredHttpMethods12() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_OMIT, POST_OMIT}, true,
DUMMY_LOG);
Assert.assertEquals(0, result.length);
}
@Test
public void testFindUncoveredHttpMethods13() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_ONLY, POST_OMIT}, true,
DUMMY_LOG);
Assert.assertEquals(1, result.length);
// Should be a deny constraint
Assert.assertTrue(result[0].getAuthConstraint());
// Should have a single collection
Assert.assertEquals(1, result[0].findCollections().length);
SecurityCollection sc = result[0].findCollections()[0];
// Should list POST as a method
Assert.assertEquals(1, sc.findMethods().length);
Assert.assertEquals(0, sc.findOmittedMethods().length);
Assert.assertEquals("POST", sc.findMethods()[0]);
}
@Test
public void testFindUncoveredHttpMethods14() {
SecurityConstraint[] result =
SecurityConstraint.findUncoveredHttpMethods(
new SecurityConstraint[] {GET_OMIT, POST_ONLY}, true,
DUMMY_LOG);
Assert.assertEquals(1, result.length);
// Should be a deny constraint
Assert.assertTrue(result[0].getAuthConstraint());
// Should have a single collection
Assert.assertEquals(1, result[0].findCollections().length);
SecurityCollection sc = result[0].findCollections()[0];
// Should list GET as a method
Assert.assertEquals(1, sc.findMethods().length);
Assert.assertEquals(0, sc.findOmittedMethods().length);
Assert.assertEquals("GET", sc.findMethods()[0]);
}
}