390503 http-method-omission element not being processed
This commit is contained in:
parent
286df12f03
commit
c7e36470c5
|
@ -19,16 +19,25 @@
|
|||
package org.eclipse.jetty.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import javax.servlet.HttpConstraintElement;
|
||||
import javax.servlet.HttpMethodConstraintElement;
|
||||
import javax.servlet.ServletSecurityElement;
|
||||
import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
|
||||
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
|
||||
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
|
@ -48,11 +57,217 @@ import org.eclipse.jetty.util.security.Constraint;
|
|||
*/
|
||||
public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
|
||||
{
|
||||
private static final String OMISSION_SUFFIX = ".omission";
|
||||
|
||||
private final List<ConstraintMapping> _constraintMappings= new CopyOnWriteArrayList<ConstraintMapping>();
|
||||
private final Set<String> _roles = new CopyOnWriteArraySet<String>();
|
||||
private final PathMap _constraintMap = new PathMap();
|
||||
private boolean _strict = true;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint()
|
||||
{
|
||||
return new Constraint();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param constraint
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint(Constraint constraint)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (Constraint)constraint.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
throw new IllegalStateException (e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Create a security constraint
|
||||
*
|
||||
* @param name
|
||||
* @param authenticate
|
||||
* @param roles
|
||||
* @param dataConstraint
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint (String name, boolean authenticate, String[] roles, int dataConstraint)
|
||||
{
|
||||
Constraint constraint = createConstraint();
|
||||
if (name != null)
|
||||
constraint.setName(name);
|
||||
constraint.setAuthenticate(authenticate);
|
||||
constraint.setRoles(roles);
|
||||
constraint.setDataConstraint(dataConstraint);
|
||||
return constraint;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint (String name, HttpConstraintElement element)
|
||||
{
|
||||
return createConstraint(name, element.getRolesAllowed(), element.getEmptyRoleSemantic(), element.getTransportGuarantee());
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name
|
||||
* @param rolesAllowed
|
||||
* @param permitOrDeny
|
||||
* @param transport
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint (String name, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
|
||||
{
|
||||
Constraint constraint = createConstraint();
|
||||
|
||||
if (rolesAllowed == null || rolesAllowed.length==0)
|
||||
{
|
||||
if (permitOrDeny.equals(EmptyRoleSemantic.DENY))
|
||||
{
|
||||
//Equivalent to <auth-constraint> with no roles
|
||||
constraint.setName(name+"-Deny");
|
||||
constraint.setAuthenticate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Equivalent to no <auth-constraint>
|
||||
constraint.setName(name+"-Permit");
|
||||
constraint.setAuthenticate(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Equivalent to <auth-constraint> with list of <security-role-name>s
|
||||
constraint.setAuthenticate(true);
|
||||
constraint.setRoles(rolesAllowed);
|
||||
constraint.setName(name+"-RolesAllowed");
|
||||
}
|
||||
|
||||
//Equivalent to //<user-data-constraint><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint>
|
||||
constraint.setDataConstraint((transport.equals(TransportGuarantee.CONFIDENTIAL)?Constraint.DC_CONFIDENTIAL:Constraint.DC_NONE));
|
||||
return constraint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param pathSpec
|
||||
* @param constraintMappings
|
||||
* @return
|
||||
*/
|
||||
public static List<ConstraintMapping> getConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
|
||||
{
|
||||
if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
|
||||
for (ConstraintMapping mapping:constraintMappings)
|
||||
{
|
||||
if (pathSpec.equals(mapping.getPathSpec()))
|
||||
{
|
||||
mappings.add(mapping);
|
||||
}
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param pathSpec
|
||||
* @param constraintMappings
|
||||
* @return
|
||||
*/
|
||||
public static List<ConstraintMapping> removeConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
|
||||
{
|
||||
if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
|
||||
for (ConstraintMapping mapping:constraintMappings)
|
||||
{
|
||||
//Remove the matching mappings by only copying in non-matching mappings
|
||||
if (!pathSpec.equals(mapping.getPathSpec()))
|
||||
{
|
||||
mappings.add(mapping);
|
||||
}
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Generate Constraints and ContraintMappings for the given url pattern and ServletSecurityElement
|
||||
*
|
||||
* @param name
|
||||
* @param pathSpec
|
||||
* @param securityElement
|
||||
* @return
|
||||
*/
|
||||
public static List<ConstraintMapping> createConstraintsWithMappingsForPath (String name, String pathSpec, ServletSecurityElement securityElement)
|
||||
{
|
||||
List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
|
||||
|
||||
//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);
|
||||
|
||||
|
||||
//See Spec 13.4.1.2 p127
|
||||
List<String> methodOmissions = new ArrayList<String>();
|
||||
|
||||
//make constraint mappings for this url for each of the HttpMethodConstraintElements
|
||||
Collection<HttpMethodConstraintElement> methodConstraints = securityElement.getHttpMethodConstraints();
|
||||
if (methodConstraints != null)
|
||||
{
|
||||
for (HttpMethodConstraintElement methodConstraint:methodConstraints)
|
||||
{
|
||||
//Make a Constraint that captures the <auth-constraint> and <user-data-constraint> elements supplied for the HttpMethodConstraintElement
|
||||
Constraint mconstraint = ConstraintSecurityHandler.createConstraint(name, methodConstraint);
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setConstraint(mconstraint);
|
||||
mapping.setPathSpec(pathSpec);
|
||||
if (methodConstraint.getMethodName() != null)
|
||||
{
|
||||
mapping.setMethod(methodConstraint.getMethodName());
|
||||
//See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
|
||||
methodOmissions.add(methodConstraint.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()]));
|
||||
|
||||
return mappings;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the strict mode.
|
||||
* @return true if the security handler is running in strict mode.
|
||||
|
@ -232,7 +447,9 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
|
@ -241,7 +458,15 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
_roles.clear();
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Create and combine the constraint with the existing processed
|
||||
* constraints.
|
||||
*
|
||||
* @param mapping
|
||||
*/
|
||||
protected void processConstraintMapping(ConstraintMapping mapping)
|
||||
{
|
||||
Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.get(mapping.getPathSpec());
|
||||
|
@ -253,8 +478,15 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
RoleInfo allMethodsRoleInfo = mappings.get(null);
|
||||
if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden())
|
||||
return;
|
||||
|
||||
if (mapping.getMethodOmissions() != null && mapping.getMethodOmissions().length > 0)
|
||||
{
|
||||
|
||||
processConstraintMappingWithMethodOmissions(mapping, mappings);
|
||||
return;
|
||||
}
|
||||
|
||||
String httpMethod = mapping.getMethod();
|
||||
String httpMethod = mapping.getMethod();
|
||||
RoleInfo roleInfo = mappings.get(httpMethod);
|
||||
if (roleInfo == null)
|
||||
{
|
||||
|
@ -268,10 +500,10 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
if (roleInfo.isForbidden())
|
||||
return;
|
||||
|
||||
Constraint constraint = mapping.getConstraint();
|
||||
boolean forbidden = constraint.isForbidden();
|
||||
roleInfo.setForbidden(forbidden);
|
||||
if (forbidden)
|
||||
//add in info from the constraint
|
||||
configureRoleInfo(roleInfo, mapping);
|
||||
|
||||
if (roleInfo.isForbidden())
|
||||
{
|
||||
if (httpMethod == null)
|
||||
{
|
||||
|
@ -281,36 +513,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
else
|
||||
{
|
||||
UserDataConstraint userDataConstraint = UserDataConstraint.get(constraint.getDataConstraint());
|
||||
roleInfo.setUserDataConstraint(userDataConstraint);
|
||||
|
||||
boolean checked = constraint.getAuthenticate();
|
||||
roleInfo.setChecked(checked);
|
||||
if (roleInfo.isChecked())
|
||||
{
|
||||
if (constraint.isAnyRole())
|
||||
{
|
||||
if (_strict)
|
||||
{
|
||||
// * means "all defined roles"
|
||||
for (String role : _roles)
|
||||
roleInfo.addRole(role);
|
||||
}
|
||||
else
|
||||
// * means any role
|
||||
roleInfo.setAnyRole(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] newRoles = constraint.getRoles();
|
||||
for (String role : newRoles)
|
||||
{
|
||||
if (_strict &&!_roles.contains(role))
|
||||
throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
|
||||
roleInfo.addRole(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
//combine with any entry that covers all methods
|
||||
if (httpMethod == null)
|
||||
{
|
||||
for (Map.Entry<String, RoleInfo> entry : mappings.entrySet())
|
||||
|
@ -325,6 +528,105 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constraints that name method omissions are dealt with differently.
|
||||
* We create an entry in the mappings with key "method.omission". This entry
|
||||
* is only ever combined with other omissions for the same method to produce a
|
||||
* consolidated RoleInfo. Then, when we wish to find the relevant constraints for
|
||||
* a given Request (in prepareConstraintInfo()), we consult 3 types of entries in
|
||||
* the mappings: an entry that names the method of the Request specifically, an
|
||||
* entry that names constraints that apply to all methods, entries of the form
|
||||
* method.omission, where the method of the Request is not named in the omission.
|
||||
* @param mapping
|
||||
* @param mappings
|
||||
*/
|
||||
protected void processConstraintMappingWithMethodOmissions (ConstraintMapping mapping, Map<String, RoleInfo> mappings)
|
||||
{
|
||||
String[] omissions = mapping.getMethodOmissions();
|
||||
|
||||
for (String omission:omissions)
|
||||
{
|
||||
//for each method omission, see if there is already a RoleInfo for it in mappings
|
||||
RoleInfo ri = mappings.get(omission+OMISSION_SUFFIX);
|
||||
if (ri == null)
|
||||
{
|
||||
//if not, make one
|
||||
ri = new RoleInfo();
|
||||
mappings.put(omission+OMISSION_SUFFIX, ri);
|
||||
}
|
||||
|
||||
//initialize RoleInfo or combine from ConstraintMapping
|
||||
configureRoleInfo(ri, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Initialize or update the RoleInfo from the constraint
|
||||
* @param ri
|
||||
* @param mapping
|
||||
*/
|
||||
protected void configureRoleInfo (RoleInfo ri, ConstraintMapping mapping)
|
||||
{
|
||||
Constraint constraint = mapping.getConstraint();
|
||||
boolean forbidden = constraint.isForbidden();
|
||||
ri.setForbidden(forbidden);
|
||||
|
||||
//set up the data constraint (NOTE: must be done after setForbidden, as it nulls out the data constraint
|
||||
//which we need in order to do combining of omissions in prepareConstraintInfo
|
||||
UserDataConstraint userDataConstraint = UserDataConstraint.get(mapping.getConstraint().getDataConstraint());
|
||||
ri.setUserDataConstraint(userDataConstraint);
|
||||
|
||||
|
||||
//if forbidden, no point setting up roles
|
||||
if (!ri.isForbidden())
|
||||
{
|
||||
//add in the roles
|
||||
boolean checked = mapping.getConstraint().getAuthenticate();
|
||||
ri.setChecked(checked);
|
||||
if (ri.isChecked())
|
||||
{
|
||||
if (mapping.getConstraint().isAnyRole())
|
||||
{
|
||||
if (_strict)
|
||||
{
|
||||
// * means "all defined roles"
|
||||
for (String role : _roles)
|
||||
ri.addRole(role);
|
||||
}
|
||||
else
|
||||
// * means any role
|
||||
ri.setAnyRole(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] newRoles = mapping.getConstraint().getRoles();
|
||||
for (String role : newRoles)
|
||||
{
|
||||
if (_strict &&!_roles.contains(role))
|
||||
throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
|
||||
ri.addRole(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Find constraints that apply to the given path.
|
||||
* In order to do this, we consult 3 different types of information stored in the mappings for each path - each mapping
|
||||
* represents a merged set of user data constraints, roles etc -:
|
||||
* <ol>
|
||||
* <li>A mapping of an exact method name </li>
|
||||
* <li>A mapping will null key that matches every method name</li>
|
||||
* <li>Mappings with keys of the form "method.omission" that indicates it will match every method name EXCEPT that given</li>
|
||||
* </ol>
|
||||
*
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#prepareConstraintInfo(java.lang.String, org.eclipse.jetty.server.Request)
|
||||
*/
|
||||
protected Object prepareConstraintInfo(String pathInContext, Request request)
|
||||
{
|
||||
Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext);
|
||||
|
@ -334,13 +636,46 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
String httpMethod = request.getMethod();
|
||||
RoleInfo roleInfo = mappings.get(httpMethod);
|
||||
if (roleInfo == null)
|
||||
roleInfo = mappings.get(null);
|
||||
{
|
||||
//No specific http-method names matched
|
||||
List<RoleInfo> applicableConstraints = new ArrayList<RoleInfo>();
|
||||
|
||||
//Get info for constraint that matches all methods if it exists
|
||||
RoleInfo all = mappings.get(null);
|
||||
if (all != null)
|
||||
applicableConstraints.add(all);
|
||||
|
||||
|
||||
//Get info for constraints that name method omissions where target method name is not omitted
|
||||
//(ie matches because target method is not omitted, hence considered covered by the constraint)
|
||||
for (Entry<String, RoleInfo> entry: mappings.entrySet())
|
||||
{
|
||||
if (entry.getKey() != null && entry.getKey().contains(OMISSION_SUFFIX) && !(httpMethod+OMISSION_SUFFIX).equals(entry.getKey()))
|
||||
applicableConstraints.add(entry.getValue());
|
||||
}
|
||||
|
||||
if (applicableConstraints.size() == 1)
|
||||
roleInfo = applicableConstraints.get(0);
|
||||
else
|
||||
{
|
||||
roleInfo = new RoleInfo();
|
||||
roleInfo.setUserDataConstraint(UserDataConstraint.None);
|
||||
|
||||
for (RoleInfo r:applicableConstraints)
|
||||
roleInfo.combine(r);
|
||||
}
|
||||
|
||||
}
|
||||
return roleInfo;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#checkUserDataPermissions(java.lang.String, org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object)
|
||||
*/
|
||||
protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException
|
||||
{
|
||||
if (constraintInfo == null)
|
||||
|
@ -404,7 +739,11 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#isAuthMandatory(org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object)
|
||||
*/
|
||||
protected boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo)
|
||||
{
|
||||
if (constraintInfo == null)
|
||||
|
@ -413,7 +752,12 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
return ((RoleInfo)constraintInfo).isChecked();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#checkWebResourcePermissions(java.lang.String, org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object, org.eclipse.jetty.server.UserIdentity)
|
||||
*/
|
||||
@Override
|
||||
protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo, UserIdentity userIdentity)
|
||||
throws IOException
|
||||
|
@ -454,4 +798,5 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
getBeans(),
|
||||
TypeUtil.asList(getHandlers()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,9 +22,11 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -76,6 +78,8 @@ public class ConstraintTest
|
|||
_loginService.putUser("user",new Password("password"));
|
||||
_loginService.putUser("user2",new Password("password"), new String[] {"user"});
|
||||
_loginService.putUser("admin",new Password("password"), new String[] {"user","administrator"});
|
||||
_loginService.putUser("user3", new Password("password"), new String[] {"foo"});
|
||||
|
||||
|
||||
_context.setContextPath("/ctx");
|
||||
_server.setHandler(_context);
|
||||
|
@ -189,17 +193,59 @@ public class ConstraintTest
|
|||
@Test
|
||||
public void testBasic() throws Exception
|
||||
{
|
||||
|
||||
List<ConstraintMapping> list = new ArrayList<ConstraintMapping>(_security.getConstraintMappings());
|
||||
|
||||
Constraint constraint6 = new Constraint();
|
||||
constraint6.setAuthenticate(true);
|
||||
constraint6.setName("omit POST and GET");
|
||||
constraint6.setRoles(new String[]{"user"});
|
||||
ConstraintMapping mapping6 = new ConstraintMapping();
|
||||
mapping6.setPathSpec("/omit/*");
|
||||
mapping6.setConstraint(constraint6);
|
||||
mapping6.setMethodOmissions(new String[]{"GET", "HEAD"}); //requests for every method except GET and HEAD must be in role "user"
|
||||
list.add(mapping6);
|
||||
|
||||
Constraint constraint7 = new Constraint();
|
||||
constraint7.setAuthenticate(true);
|
||||
constraint7.setName("non-omitted GET");
|
||||
constraint7.setRoles(new String[]{"administrator"});
|
||||
ConstraintMapping mapping7 = new ConstraintMapping();
|
||||
mapping7.setPathSpec("/omit/*");
|
||||
mapping7.setConstraint(constraint7);
|
||||
mapping7.setMethod("GET"); //requests for GET must be in role "admin"
|
||||
list.add(mapping7);
|
||||
|
||||
Constraint constraint8 = new Constraint();
|
||||
constraint8.setAuthenticate(true);
|
||||
constraint8.setName("non specific");
|
||||
constraint8.setRoles(new String[]{"foo"});
|
||||
ConstraintMapping mapping8 = new ConstraintMapping();
|
||||
mapping8.setPathSpec("/omit/*");
|
||||
mapping8.setConstraint(constraint8);//requests for all methods must be in role "foo"
|
||||
list.add(mapping8);
|
||||
|
||||
Set<String> knownRoles=new HashSet<String>();
|
||||
knownRoles.add("user");
|
||||
knownRoles.add("administrator");
|
||||
knownRoles.add("foo");
|
||||
|
||||
_security.setConstraintMappings(list, knownRoles);
|
||||
|
||||
|
||||
_security.setAuthenticator(new BasicAuthenticator());
|
||||
_security.setStrict(false);
|
||||
_server.start();
|
||||
|
||||
String response;
|
||||
/*
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
*/
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
/*
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
@ -214,8 +260,8 @@ public class ConstraintTest
|
|||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
||||
*/
|
||||
/*
|
||||
// test admin
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
|
@ -241,7 +287,33 @@ public class ConstraintTest
|
|||
|
||||
response = _connector.getResponses("GET /ctx/admin/relax/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check GET is in role administrator
|
||||
response = _connector.getResponses("GET /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check POST is in role user
|
||||
response = _connector.getResponses("POST /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check POST can be in role foo too
|
||||
response = _connector.getResponses("POST /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user3:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check HEAD cannot be in role user
|
||||
response = _connector.getResponses("HEAD /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testFormDispatch() throws Exception
|
||||
|
@ -847,7 +919,7 @@ public class ConstraintTest
|
|||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
if (request.getAuthType()==null || "user".equals(request.getRemoteUser()) || request.isUserInRole("user"))
|
||||
if (request.getAuthType()==null || "user".equals(request.getRemoteUser()) || request.isUserInRole("user") || request.isUserInRole("foo"))
|
||||
{
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/plain; charset=UTF-8");
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.security;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Password;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1441 $ $Date: 2010-04-02 12:28:17 +0200 (Fri, 02 Apr 2010) $
|
||||
*/
|
||||
public class SpecExampleConstraintTest
|
||||
{
|
||||
private static final String TEST_REALM = "TestRealm";
|
||||
private static Server _server;
|
||||
private static LocalConnector _connector;
|
||||
private static SessionHandler _session;
|
||||
private ConstraintSecurityHandler _security;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer()
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalConnector();
|
||||
_server.setConnectors(new Connector[]{_connector});
|
||||
|
||||
ContextHandler _context = new ContextHandler();
|
||||
_session = new SessionHandler();
|
||||
|
||||
HashLoginService _loginService = new HashLoginService(TEST_REALM);
|
||||
_loginService.putUser("fred",new Password("password"));
|
||||
_loginService.putUser("harry",new Password("password"), new String[] {"HOMEOWNER"});
|
||||
_loginService.putUser("chris",new Password("password"), new String[] {"CONTRACTOR"});
|
||||
_loginService.putUser("steven", new Password("password"), new String[] {"SALESCLERK"});
|
||||
|
||||
|
||||
_context.setContextPath("/ctx");
|
||||
_server.setHandler(_context);
|
||||
_context.setHandler(_session);
|
||||
|
||||
_server.addBean(_loginService);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupSecurity()
|
||||
{
|
||||
_security = new ConstraintSecurityHandler();
|
||||
_session.setHandler(_security);
|
||||
RequestHandler _handler = new RequestHandler();
|
||||
_security.setHandler(_handler);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>precluded methods</web-resource-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<url-pattern>/acme/wholesale/*</url-pattern>
|
||||
<url-pattern>/acme/retail/*</url-pattern>
|
||||
<http-method-exception>GET</http-method-exception>
|
||||
<http-method-exception>POST</http-method-exception>
|
||||
</web-resource-collection>
|
||||
<auth-constraint/>
|
||||
</security-constraint>
|
||||
*/
|
||||
|
||||
Constraint constraint0 = new Constraint();
|
||||
constraint0.setAuthenticate(true);
|
||||
constraint0.setName("precluded methods");
|
||||
ConstraintMapping mapping0 = new ConstraintMapping();
|
||||
mapping0.setPathSpec("/*");
|
||||
mapping0.setConstraint(constraint0);
|
||||
mapping0.setMethodOmissions(new String[]{"GET", "POST"});
|
||||
|
||||
ConstraintMapping mapping1 = new ConstraintMapping();
|
||||
mapping1.setPathSpec("/acme/wholesale/*");
|
||||
mapping1.setConstraint(constraint0);
|
||||
mapping1.setMethodOmissions(new String[]{"GET", "POST"});
|
||||
|
||||
ConstraintMapping mapping2 = new ConstraintMapping();
|
||||
mapping2.setPathSpec("/acme/retail/*");
|
||||
mapping2.setConstraint(constraint0);
|
||||
mapping2.setMethodOmissions(new String[]{"GET", "POST"});
|
||||
|
||||
/*
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>wholesale</web-resource-name>
|
||||
<url-pattern>/acme/wholesale/*</url-pattern>
|
||||
<http-method>GET</http-method>
|
||||
<http-method>PUT</http-method>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>SALESCLERK</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
*/
|
||||
Constraint constraint1 = new Constraint();
|
||||
constraint1.setAuthenticate(true);
|
||||
constraint1.setName("wholesale");
|
||||
constraint1.setRoles(new String[]{"SALESCLERK"});
|
||||
ConstraintMapping mapping3 = new ConstraintMapping();
|
||||
mapping3.setPathSpec("/acme/wholesale/*");
|
||||
mapping3.setConstraint(constraint1);
|
||||
mapping3.setMethod("GET");
|
||||
ConstraintMapping mapping4 = new ConstraintMapping();
|
||||
mapping4.setPathSpec("/acme/wholesale/*");
|
||||
mapping4.setConstraint(constraint1);
|
||||
mapping4.setMethod("PUT");
|
||||
|
||||
/*
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>wholesale 2</web-resource-name>
|
||||
<url-pattern>/acme/wholesale/*</url-pattern>
|
||||
<http-method>GET</http-method>
|
||||
<http-method>POST</http-method>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>CONTRACTOR</role-name>
|
||||
</auth-constraint>
|
||||
<user-data-constraint>
|
||||
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
|
||||
</user-data-constraint>
|
||||
</security-constraint>
|
||||
*/
|
||||
Constraint constraint2 = new Constraint();
|
||||
constraint2.setAuthenticate(true);
|
||||
constraint2.setName("wholesale 2");
|
||||
constraint2.setRoles(new String[]{"CONTRACTOR"});
|
||||
constraint2.setDataConstraint(Constraint.DC_CONFIDENTIAL);
|
||||
ConstraintMapping mapping5 = new ConstraintMapping();
|
||||
mapping5.setPathSpec("/acme/wholesale/*");
|
||||
mapping5.setMethod("GET");
|
||||
mapping5.setConstraint(constraint2);
|
||||
ConstraintMapping mapping6 = new ConstraintMapping();
|
||||
mapping6.setPathSpec("/acme/wholesale/*");
|
||||
mapping6.setMethod("POST");
|
||||
mapping6.setConstraint(constraint2);
|
||||
|
||||
/*
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>retail</web-resource-name>
|
||||
<url-pattern>/acme/retail/*</url-pattern>
|
||||
<http-method>GET</http-method>
|
||||
<http-method>POST</http-method>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>CONTRACTOR</role-name>
|
||||
<role-name>HOMEOWNER</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
*/
|
||||
Constraint constraint4 = new Constraint();
|
||||
constraint4.setName("retail");
|
||||
constraint4.setAuthenticate(true);
|
||||
constraint4.setRoles(new String[]{"CONTRACTOR", "HOMEOWNER"});
|
||||
ConstraintMapping mapping7 = new ConstraintMapping();
|
||||
mapping7.setPathSpec("/acme/retail/*");
|
||||
mapping7.setMethod("GET");
|
||||
mapping7.setConstraint(constraint4);
|
||||
ConstraintMapping mapping8 = new ConstraintMapping();
|
||||
mapping8.setPathSpec("/acme/retail/*");
|
||||
mapping8.setMethod("POST");
|
||||
mapping8.setConstraint(constraint4);
|
||||
|
||||
|
||||
|
||||
|
||||
Set<String> knownRoles=new HashSet<String>();
|
||||
knownRoles.add("CONTRACTOR");
|
||||
knownRoles.add("HOMEOWNER");
|
||||
knownRoles.add("SALESCLERK");
|
||||
|
||||
_security.setConstraintMappings(Arrays.asList(new ConstraintMapping[]
|
||||
{
|
||||
mapping0, mapping1, mapping2, mapping3, mapping4, mapping5, mapping6, mapping7, mapping8
|
||||
}), knownRoles);
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
if (_server.isRunning())
|
||||
{
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testBasic() throws Exception
|
||||
{
|
||||
|
||||
_security.setAuthenticator(new BasicAuthenticator());
|
||||
_security.setStrict(false);
|
||||
_server.start();
|
||||
|
||||
String response;
|
||||
/*
|
||||
/star all methods except GET/POST forbidden
|
||||
/acme/wholesale/star all methods except GET/POST forbidden
|
||||
/acme/retail/star all methods except GET/POST forbidden
|
||||
/acme/wholesale/star GET must be in role CONTRACTOR or SALESCLERK
|
||||
/acme/wholesale/star POST must be in role CONTRACTOR and confidential transport
|
||||
/acme/retail/star GET must be in role CONTRACTOR or HOMEOWNER
|
||||
/acme/retail/star POST must be in role CONTRACTOR or HOMEOWNER
|
||||
*/
|
||||
|
||||
//a user in role HOMEOWNER is forbidden HEAD request
|
||||
response = _connector.getResponses("HEAD /ctx/index.html HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("HEAD /ctx/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("HEAD /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("HEAD /ctx/acme/retail/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
//a user in role CONTRACTOR can do a GET
|
||||
response = _connector.getResponses("GET /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("chris:password") + "\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//a user in role CONTRACTOR can only do a post if confidential
|
||||
response = _connector.getResponses("POST /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("chris:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 !Confidential"));
|
||||
|
||||
|
||||
//a user in role HOMEOWNER can do a GET
|
||||
response = _connector.getResponses("GET /ctx/acme/retail/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
|
||||
private class RequestHandler extends AbstractHandler
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/plain; charset=UTF-8");
|
||||
response.getWriter().println("URI="+request.getRequestURI());
|
||||
String user = request.getRemoteUser();
|
||||
response.getWriter().println("user="+user);
|
||||
if (request.getParameter("test_parameter")!=null)
|
||||
response.getWriter().println(request.getParameter("test_parameter"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -626,7 +626,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
{
|
||||
//no servlet mappings
|
||||
context.getMetaData().setOrigin(servlet_name+".servlet.mappings", descriptor);
|
||||
ServletMapping mapping = addServletMapping(servlet_name, node, context);
|
||||
ServletMapping mapping = addServletMapping(servlet_name, node, context, descriptor);
|
||||
mapping.setDefault(context.getMetaData().getOrigin(servlet_name+".servlet.mappings") == Origin.WebDefaults);
|
||||
break;
|
||||
}
|
||||
|
@ -638,14 +638,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
//otherwise just ignore it
|
||||
if (!(descriptor instanceof FragmentDescriptor))
|
||||
{
|
||||
addServletMapping(servlet_name, node, context);
|
||||
addServletMapping(servlet_name, node, context, descriptor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WebFragment:
|
||||
{
|
||||
//mappings previously set by another web-fragment, so merge in this web-fragment's mappings
|
||||
addServletMapping(servlet_name, node, context);
|
||||
addServletMapping(servlet_name, node, context, descriptor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1170,7 +1170,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
* @param node
|
||||
* @param context
|
||||
*/
|
||||
protected ServletMapping addServletMapping (String servletName, XmlParser.Node node, WebAppContext context)
|
||||
protected ServletMapping addServletMapping (String servletName, XmlParser.Node node, WebAppContext context, Descriptor descriptor)
|
||||
{
|
||||
ServletMapping mapping = new ServletMapping();
|
||||
mapping.setServletName(servletName);
|
||||
|
@ -1182,6 +1182,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
String p = iter.next().toString(false, true);
|
||||
p = normalizePattern(p);
|
||||
paths.add(p);
|
||||
context.getMetaData().setOrigin(servletName+".servlet.mapping."+p, descriptor);
|
||||
}
|
||||
mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
|
||||
context.getServletHandler().addServletMapping(mapping);
|
||||
|
@ -1193,7 +1194,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
* @param node
|
||||
* @param context
|
||||
*/
|
||||
protected void addFilterMapping (String filterName, XmlParser.Node node, WebAppContext context)
|
||||
protected void addFilterMapping (String filterName, XmlParser.Node node, WebAppContext context, Descriptor descriptor)
|
||||
{
|
||||
FilterMapping mapping = new FilterMapping();
|
||||
mapping.setFilterName(filterName);
|
||||
|
@ -1205,6 +1206,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
String p = iter.next().toString(false, true);
|
||||
p = normalizePattern(p);
|
||||
paths.add(p);
|
||||
context.getMetaData().setOrigin(filterName+".filter.mapping."+p, descriptor);
|
||||
}
|
||||
mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
|
||||
|
||||
|
@ -1361,6 +1363,8 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
|
||||
//ServletSpec 3.0, p74 security-constraints, as minOccurs > 1, are additive
|
||||
//across fragments
|
||||
|
||||
//TODO: need to remember origin of the constraints
|
||||
try
|
||||
{
|
||||
XmlParser.Node auths = node.get("auth-constraint");
|
||||
|
@ -1409,29 +1413,50 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
{
|
||||
String url = iter2.next().toString(false, true);
|
||||
url = normalizePattern(url);
|
||||
|
||||
//remember origin so we can process ServletRegistration.Dynamic.setServletSecurityElement() correctly
|
||||
context.getMetaData().setOrigin("constraint.url."+url, descriptor);
|
||||
|
||||
Iterator<XmlParser.Node> iter3 = collection.iterator("http-method");
|
||||
Iterator<XmlParser.Node> iter4 = collection.iterator("http-method-omission");
|
||||
|
||||
if (iter3.hasNext())
|
||||
{
|
||||
if (iter4.hasNext())
|
||||
throw new IllegalStateException ("web-resource-collection cannot contain both http-method and http-method-omission");
|
||||
|
||||
//configure all the http-method elements for each url
|
||||
while (iter3.hasNext())
|
||||
{
|
||||
String method = ((XmlParser.Node) iter3.next()).toString(false, true);
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setMethod(method);
|
||||
mapping.setPathSpec(url);
|
||||
mapping.setConstraint(sc);
|
||||
((ConstraintAware)context.getSecurityHandler()).addConstraintMapping(mapping);
|
||||
}
|
||||
}
|
||||
else if (iter4.hasNext())
|
||||
{
|
||||
//configure all the http-method-omission elements for each url
|
||||
while (iter4.hasNext())
|
||||
{
|
||||
String method = ((XmlParser.Node)iter4.next()).toString(false, true);
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setMethodOmissions(new String[]{method});
|
||||
mapping.setPathSpec(url);
|
||||
mapping.setConstraint(sc);
|
||||
|
||||
((ConstraintAware)context.getSecurityHandler()).addConstraintMapping(mapping);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//No http-methods or http-method-omissions specified, the constraint applies to all
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setPathSpec(url);
|
||||
mapping.setConstraint(sc);
|
||||
((ConstraintAware)context.getSecurityHandler()).addConstraintMapping(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
|
@ -1777,7 +1802,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
{
|
||||
//no filtermappings for this filter yet defined
|
||||
context.getMetaData().setOrigin(filter_name+".filter.mappings", descriptor);
|
||||
addFilterMapping(filter_name, node, context);
|
||||
addFilterMapping(filter_name, node, context, descriptor);
|
||||
break;
|
||||
}
|
||||
case WebDefaults:
|
||||
|
@ -1787,14 +1812,14 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
//filter mappings defined in a web xml file. If we're processing a fragment, we ignore filter mappings.
|
||||
if (!(descriptor instanceof FragmentDescriptor))
|
||||
{
|
||||
addFilterMapping(filter_name, node, context);
|
||||
addFilterMapping(filter_name, node, context, descriptor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WebFragment:
|
||||
{
|
||||
//filter mappings first defined in a web-fragment, allow other fragments to add
|
||||
addFilterMapping(filter_name, node, context);
|
||||
addFilterMapping(filter_name, node, context, descriptor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue