390163 Implement ServletRegistration.Dynamic.setServletSecurity
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
index ee2c45c..bfbef9b 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
@@ -21,6 +21,7 @@
import java.util.ArrayList;
import java.util.List;
+import javax.servlet.ServletSecurityElement;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.HttpMethodConstraint;
import javax.servlet.annotation.ServletSecurity;
@@ -30,12 +31,13 @@
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
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.LazyList;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;
+import org.eclipse.jetty.webapp.Origin;
import org.eclipse.jetty.webapp.WebAppContext;
/**
@@ -82,7 +84,7 @@
if (servletSecurity == null)
return;
- //If there are already constraints defined (ie from web.xml or programmatically(?)) that match any
+ //If there are already constraints defined (ie from web.xml) that match any
//of the url patterns defined for this servlet, then skip the security annotation.
List<ServletMapping> servletMappings = getServletMappings(clazz.getCanonicalName());
@@ -97,19 +99,15 @@
//Make a fresh list
constraintMappings = new ArrayList<ConstraintMapping>();
- //Get the values that form the constraints that will apply unless there are HttpMethodConstraints to augment them
- HttpConstraint defaults = servletSecurity.value();
-
- //Make a Constraint for the <auth-constraint> and <user-data-constraint> specified by the HttpConstraint
- Constraint defaultConstraint = makeConstraint (clazz,
- defaults.rolesAllowed(),
- defaults.value(),
- defaults.transportGuarantee());
-
- constraintMappings.addAll(makeMethodMappings(clazz,
- defaultConstraint,
- servletMappings,
- servletSecurity.httpMethodConstraints()));
+ ServletSecurityElement securityElement = new ServletSecurityElement(servletSecurity);
+ for (ServletMapping sm : servletMappings)
+ {
+ for (String url : sm.getPathSpecs())
+ {
+ _context.getMetaData().setOrigin("constraint.url."+url, Origin.Annotation);
+ constraintMappings.addAll(ConstraintSecurityHandler.createConstraintsWithMappingsForPath(clazz.getName(), url, securityElement));
+ }
+ }
//set up the security constraints produced by the annotation
ConstraintAware securityHandler = (ConstraintAware)_context.getSecurityHandler();
@@ -131,111 +129,10 @@
*/
protected Constraint makeConstraint (Class servlet, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
{
- Constraint constraint = new Constraint();
- if (rolesAllowed == null || rolesAllowed.length==0)
- {
- if (permitOrDeny.equals(EmptyRoleSemantic.DENY))
- {
- //Equivalent to <auth-constraint> with no roles
- constraint.setName(servlet.getName()+"-Deny");
- constraint.setAuthenticate(true);
- }
- else
- {
- //Equivalent to no <auth-constraint>
- constraint.setAuthenticate(false);
- constraint.setName(servlet.getName()+"-Permit");
- }
- }
- else
- {
- //Equivalent to <auth-constraint> with list of <security-role-name>s
- constraint.setAuthenticate(true);
- constraint.setRoles(rolesAllowed);
- constraint.setName(servlet.getName()+"-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;
+ return ConstraintSecurityHandler.createConstraint(servlet.getName(), rolesAllowed, permitOrDeny, transport);
}
- /**
- * Make a ConstraintMapping which captures the <http-method> or <http-method-omission> elements for a particular url pattern,
- * and relates it to a Constraint object (<auth-constraint> and <user-data-constraint>).
- * @param constraint
- * @param url
- * @param method
- * @param omissions
- * @return
- */
- protected ConstraintMapping makeConstraintMapping (Constraint constraint, String url, String method, String[] omissions)
- {
- ConstraintMapping mapping = new ConstraintMapping();
- mapping.setConstraint(constraint);
- mapping.setPathSpec(url);
- if (method != null)
- mapping.setMethod(method);
- if (omissions != null)
- mapping.setMethodOmissions(omissions);
- return mapping;
- }
-
- /**
- * Make the Jetty Constraints and ConstraintMapping objects that correspond to the HttpMethodConstraint
- * annotations for each url pattern for the servlet.
- * @param servlet
- * @param defaultConstraint
- * @param servletMappings
- * @param annotations
- * @return
- */
- protected List<ConstraintMapping> makeMethodMappings (Class servlet, Constraint defaultConstraint, List<ServletMapping> servletMappings, HttpMethodConstraint[] annotations)
- {
- List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
-
- //for each url-pattern existing for the servlet make a ConstraintMapping for the HttpConstraint, and ConstraintMappings for
- //each HttpMethodConstraint
- for (ServletMapping sm : servletMappings)
- {
- for (String url : sm.getPathSpecs())
- {
- //Make a ConstraintMapping that matches the defaultConstraint
- ConstraintMapping defaultMapping = makeConstraintMapping(defaultConstraint, url, null, null);
-
- //If there are HttpMethodConstraint annotations, make a Constraint and a ConstraintMapping for it
- if (annotations != null && annotations.length>0)
- {
- List<String> omissions = new ArrayList<String>();
-
- //for each HttpMethodConstraint annotation, make a new Constraint and ConstraintMappings for this url
- for (int i=0; i < annotations.length;i++)
- {
- //Make a Constraint that captures the <auth-constraint> and <user-data-constraint> elements
- Constraint methodConstraint = makeConstraint(servlet,
- annotations[i].rolesAllowed(),
- annotations[i].emptyRoleSemantic(),
- annotations[i].transportGuarantee());
-
- //Make ConstraintMapping that captures the <http-method> elements
- ConstraintMapping methodConstraintMapping = makeConstraintMapping (methodConstraint,
- url,annotations[i].value(),
- null);
- mappings.add(methodConstraintMapping);
- omissions.add(annotations[i].value());
- }
- defaultMapping.setMethodOmissions(omissions.toArray(new String[0]));
- }
-
- //add the constraint mapping containing the http-method-omissions, if there are any
- mappings.add(defaultMapping);
- }
- }
- return mappings;
- }
-
-
/**
* Get the ServletMappings for the servlet's class.
@@ -284,6 +181,7 @@
{
for (int j=0; j < pathSpecs.length; j++)
{
+ //TODO decide if we need to check the origin
if (pathSpecs[j].equals(constraintMappings.get(i).getPathSpec()))
{
exists = true;
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 94f70f5..5712c1d 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
@@ -24,7 +24,6 @@
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;
@@ -51,7 +50,7 @@
/* ------------------------------------------------------------ */
/**
* Handler to enforce SecurityConstraints. This implementation is servlet spec
- * 2.4 compliant and precomputes the constraint combinations for runtime
+ * 3.0 compliant and precomputes the constraint combinations for runtime
* efficiency.
*
*/
@@ -191,9 +190,11 @@
/* ------------------------------------------------------------ */
- /**
+ /** Take out of the constraint mappings those that match the
+ * given path.
+ *
* @param pathSpec
- * @param constraintMappings
+ * @param constraintMappings a new list minus the matching constraints
* @return
*/
public static List<ConstraintMapping> removeConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
@@ -351,8 +352,6 @@
*/
public void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles)
{
- if (isStarted())
- throw new IllegalStateException("Started");
_constraintMappings.clear();
_constraintMappings.addAll(constraintMappings);
@@ -371,6 +370,14 @@
}
}
setRoles(roles);
+
+ if (isStarted())
+ {
+ for (ConstraintMapping mapping : _constraintMappings)
+ {
+ processConstraintMapping(mapping);
+ }
+ }
}
/* ------------------------------------------------------------ */
@@ -383,9 +390,6 @@
*/
public void setRoles(Set<String> roles)
{
- if (isStarted())
- throw new IllegalStateException("Started");
-
_roles.clear();
_roles.addAll(roles);
}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
index 1c71363..055060a 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
@@ -48,6 +48,7 @@
import javax.servlet.descriptor.TaglibDescriptor;
import org.eclipse.jetty.security.ConstraintAware;
+import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Dispatcher;
@@ -59,6 +60,7 @@
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.LazyList;
+import org.eclipse.jetty.util.security.Constraint;
/* ------------------------------------------------------------ */
@@ -377,10 +379,21 @@
* @param registration ServletRegistration.Dynamic instance that setServletSecurity was called on
* @param servletSecurityElement new security info
* @return the set of exact URL mappings currently associated with the registration that are also present in the web.xml
- * security constratins and thus will be unaffected by this call.
+ * security constraints and thus will be unaffected by this call.
*/
public Set<String> setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement)
{
+ //Default implementation is to just accept them all. If using a webapp, then this behaviour is overridden in WebAppContext.setServletSecurity
+ Collection<String> pathSpecs = registration.getMappings();
+ if (pathSpecs != null)
+ {
+ for (String pathSpec:pathSpecs)
+ {
+ List<ConstraintMapping> mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
+ for (ConstraintMapping m:mappings)
+ ((ConstraintAware)getSecurityHandler()).addConstraintMapping(m);
+ }
+ }
return Collections.emptySet();
}
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java
index 284a1cd..cdd84b7 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java
@@ -538,6 +538,15 @@
OriginInfo x = new OriginInfo (name, Origin.Annotation);
_origins.put(name, x);
}
+
+ public void setOrigin(String name, Origin origin)
+ {
+ if (name == null)
+ return;
+
+ OriginInfo x = new OriginInfo (name, origin);
+ _origins.put(name, x);
+ }
public boolean isMetaDataComplete()
{
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Origin.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Origin.java
index 1481b38..f2f941c 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Origin.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Origin.java
@@ -18,4 +18,4 @@
package org.eclipse.jetty.webapp;
-public enum Origin {NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation}
\ No newline at end of file
+public enum Origin {NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation, API}
\ No newline at end of file
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
index ed0d8f2..45ffa3a 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
@@ -25,18 +25,29 @@
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.EventListener;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import javax.servlet.HttpMethodConstraintElement;
import javax.servlet.ServletContext;
+import javax.servlet.ServletRegistration.Dynamic;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
+import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionListener;
+import org.eclipse.jetty.security.ConstraintAware;
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HandlerContainer;
@@ -56,6 +67,7 @@
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
+import org.eclipse.jetty.util.security.Constraint;
/* ------------------------------------------------------------ */
/** Web Application Context Handler.
@@ -1237,6 +1249,79 @@
super.startContext();
}
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public Set<String> setServletSecurity(Dynamic registration, ServletSecurityElement servletSecurityElement)
+ {
+
+ Set<String> unchangedURLMappings = new HashSet<String>();
+ //From javadoc for ServletSecurityElement:
+ /*
+ If a URL pattern of this ServletRegistration is an exact target of a security-constraint that
+ was established via the portable deployment descriptor, then this method does not change the
+ security-constraint for that pattern, and the pattern will be included in the return value.
+
+ If a URL pattern of this ServletRegistration is an exact target of a security constraint
+ that was established via the ServletSecurity annotation or a previous call to this method,
+ then this method replaces the security constraint for that pattern.
+
+ If a URL pattern of this ServletRegistration is neither the exact target of a security constraint
+ that was established via the ServletSecurity annotation or a previous call to this method,
+ nor the exact target of a security-constraint in the portable deployment descriptor, then
+ this method establishes the security constraint for that pattern from the argument ServletSecurityElement.
+ */
+
+ Collection<String> pathMappings = registration.getMappings();
+ if (pathMappings != null)
+ {
+ Constraint constraint = ConstraintSecurityHandler.createConstraint(registration.getName(), servletSecurityElement);
+
+ for (String pathSpec:pathMappings)
+ {
+ Origin origin = getMetaData().getOrigin("constraint.url."+pathSpec);
+
+ switch (origin)
+ {
+ case NotSet:
+ {
+ //No mapping for this url already established
+ List<ConstraintMapping> mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
+ for (ConstraintMapping m:mappings)
+ ((ConstraintAware)getSecurityHandler()).addConstraintMapping(m);
+ getMetaData().setOrigin("constraint.url."+pathSpec, Origin.API);
+ break;
+ }
+ case WebXml:
+ case WebDefaults:
+ case WebOverride:
+ case WebFragment:
+ {
+ //a mapping for this url was created in a descriptor, which overrides everything
+ unchangedURLMappings.add(pathSpec);
+ break;
+ }
+ case Annotation:
+ case API:
+ {
+ //mapping established via an annotation or by previous call to this method,
+ //replace the security constraint for this pattern
+ List<ConstraintMapping> constraintMappings = ConstraintSecurityHandler.removeConstraintMappingsForPath(pathSpec, ((ConstraintAware)getSecurityHandler()).getConstraintMappings());
+
+ List<ConstraintMapping> freshMappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
+ constraintMappings.addAll(freshMappings);
+
+ ((ConstraintSecurityHandler)getSecurityHandler()).setConstraintMappings(constraintMappings);
+ break;
+ }
+ }
+ }
+ }
+
+ return unchangedURLMappings;
+ }
+
+
/* ------------------------------------------------------------ */
public class Context extends ServletContextHandler.Context
@@ -1287,6 +1372,8 @@
}
}
+
+
}
/* ------------------------------------------------------------ */
diff --git a/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml b/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml
index 9e42d6d..7b7f9e4 100644
--- a/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml
+++ b/test-jetty-webapp/src/main/config/contexts/test.d/override-web.xml
@@ -15,15 +15,6 @@
<param-value>a context value</param-value>
</context-param>
- <!-- Add or override filter init parameter -->
- <filter>
- <filter-name>TestFilter</filter-name>
- <filter-class>com.acme.TestFilter</filter-class>
- <init-param>
- <param-name>remote</param-name>
- <param-value>false</param-value>
- </init-param>
- </filter>
<!-- Add or override servlet init parameter -->
<servlet>
diff --git a/test-jetty-webapp/src/main/java/com/acme/RegTest.java b/test-jetty-webapp/src/main/java/com/acme/RegTest.java
new file mode 100644
index 0000000..8d99cd1
--- /dev/null
+++ b/test-jetty-webapp/src/main/java/com/acme/RegTest.java
@@ -0,0 +1,194 @@
+//
+// ========================================================================
+// 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 com.acme;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.util.StringUtil;
+
+
+
+
+/* ------------------------------------------------------------ */
+/** Rego Servlet - tests being accessed from servlet 3.0 programmatic
+ * configuration.
+ *
+ */
+public class RegTest extends HttpServlet
+{
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public void init(ServletConfig config) throws ServletException
+ {
+ super.init(config);
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ {
+ doGet(request, response);
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+ {
+ request.setCharacterEncoding("UTF-8");
+ PrintWriter pout=null;
+
+ try
+ {
+ pout =response.getWriter();
+ }
+ catch(IllegalStateException e)
+ {
+ pout=new PrintWriter(new OutputStreamWriter(response.getOutputStream(),"UTF-8"));
+ }
+
+ try
+ {
+ pout.write("<html>\n<body>\n");
+ pout.write("<h1>Rego Servlet</h1>\n");
+ pout.write("<table width=\"95%\">");
+ pout.write("<tr>\n");
+ pout.write("<th align=\"right\">getMethod: </th>");
+ pout.write("<td>" + notag(request.getMethod())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getContentLength: </th>");
+ pout.write("<td>"+Integer.toString(request.getContentLength())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getContentType: </th>");
+ pout.write("<td>"+notag(request.getContentType())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getRequestURI: </th>");
+ pout.write("<td>"+notag(request.getRequestURI())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getRequestURL: </th>");
+ pout.write("<td>"+notag(request.getRequestURL().toString())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getContextPath: </th>");
+ pout.write("<td>"+request.getContextPath()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getServletPath: </th>");
+ pout.write("<td>"+notag(request.getServletPath())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getPathInfo: </th>");
+ pout.write("<td>"+notag(request.getPathInfo())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getPathTranslated: </th>");
+ pout.write("<td>"+notag(request.getPathTranslated())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getQueryString: </th>");
+ pout.write("<td>"+notag(request.getQueryString())+"</td>");
+ pout.write("</tr><tr>\n");
+
+ pout.write("<th align=\"right\">getProtocol: </th>");
+ pout.write("<td>"+request.getProtocol()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getScheme: </th>");
+ pout.write("<td>"+request.getScheme()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getServerName: </th>");
+ pout.write("<td>"+notag(request.getServerName())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getServerPort: </th>");
+ pout.write("<td>"+Integer.toString(request.getServerPort())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getLocalName: </th>");
+ pout.write("<td>"+request.getLocalName()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getLocalAddr: </th>");
+ pout.write("<td>"+request.getLocalAddr()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getLocalPort: </th>");
+ pout.write("<td>"+Integer.toString(request.getLocalPort())+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getRemoteUser: </th>");
+ pout.write("<td>"+request.getRemoteUser()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getUserPrincipal: </th>");
+ pout.write("<td>"+request.getUserPrincipal()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getRemoteAddr: </th>");
+ pout.write("<td>"+request.getRemoteAddr()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getRemoteHost: </th>");
+ pout.write("<td>"+request.getRemoteHost()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getRemotePort: </th>");
+ pout.write("<td>"+request.getRemotePort()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">getRequestedSessionId: </th>");
+ pout.write("<td>"+request.getRequestedSessionId()+"</td>");
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">isSecure(): </th>");
+ pout.write("<td>"+request.isSecure()+"</td>");
+
+ pout.write("</tr><tr>\n");
+ pout.write("<th align=\"right\">isUserInRole(admin): </th>");
+ pout.write("<td>"+request.isUserInRole("admin")+"</td>");
+
+ pout.write("</tr></table>");
+
+ }
+ catch (Exception e)
+ {
+ getServletContext().log("dump "+e);
+ }
+
+
+ pout.write("</body>\n</html>\n");
+
+ pout.close();
+ }
+
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public String getServletInfo()
+ {
+ return "Rego Servlet";
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public synchronized void destroy()
+ {
+ }
+
+
+ private String notag(String s)
+ {
+ if (s==null)
+ return "null";
+ s=StringUtil.replace(s,"&","&");
+ s=StringUtil.replace(s,"<","<");
+ s=StringUtil.replace(s,">",">");
+ return s;
+ }
+}
diff --git a/test-jetty-webapp/src/main/java/com/acme/TestListener.java b/test-jetty-webapp/src/main/java/com/acme/TestListener.java
index faaa760..cf950ed 100644
--- a/test-jetty-webapp/src/main/java/com/acme/TestListener.java
+++ b/test-jetty-webapp/src/main/java/com/acme/TestListener.java
@@ -18,6 +18,7 @@
package com.acme;
+import javax.servlet.DispatcherType;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
@@ -26,6 +27,12 @@
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
+import javax.servlet.ServletRegistration;
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.HttpConstraintElement;
+import javax.servlet.HttpMethodConstraintElement;
+import javax.servlet.annotation.ServletSecurity;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
@@ -33,6 +40,9 @@
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
+import java.util.EnumSet;
+import java.util.Set;
+
public class TestListener implements HttpSessionListener, HttpSessionAttributeListener, HttpSessionActivationListener, ServletContextListener, ServletContextAttributeListener, ServletRequestListener, ServletRequestAttributeListener
{
public void attributeAdded(HttpSessionBindingEvent se)
@@ -62,16 +72,30 @@
public void contextInitialized(ServletContextEvent sce)
{
- /* TODO for servlet 3.0
- * FilterRegistration registration=context.addFilter("TestFilter",TestFilter.class.getName());
-
-
+ //configure programmatic security
+ ServletRegistration.Dynamic rego = sce.getServletContext().addServlet("RegoTest", RegTest.class.getName());
+ rego.addMapping("/rego/*");
+ HttpConstraintElement constraintElement = new HttpConstraintElement(ServletSecurity.EmptyRoleSemantic.PERMIT,
+ ServletSecurity.TransportGuarantee.NONE, new String[]{"admin"});
+ ServletSecurityElement securityElement = new ServletSecurityElement(constraintElement, null);
+ Set<String> unchanged = rego.setServletSecurity(securityElement);
+ System.err.println("Security constraints registered: "+unchanged.isEmpty());
+
+ //Test that a security constraint from web.xml can't be overridden programmatically
+ ServletRegistration.Dynamic rego2 = sce.getServletContext().addServlet("RegoTest2", RegTest.class.getName());
+ rego2.addMapping("/rego2/*");
+ securityElement = new ServletSecurityElement(constraintElement, null);
+ unchanged = rego2.setServletSecurity(securityElement);
+ System.err.println("Overridding web.xml constraints not possible:" +!unchanged.isEmpty());
+
+ /* For servlet 3.0 */
+ FilterRegistration.Dynamic registration = sce.getServletContext().addFilter("TestFilter",TestFilter.class.getName());
+ registration.setInitParameter("remote", "false");
registration.setAsyncSupported(true);
registration.addMappingForUrlPatterns(
EnumSet.of(DispatcherType.ERROR,DispatcherType.ASYNC,DispatcherType.FORWARD,DispatcherType.INCLUDE,DispatcherType.REQUEST),
true,
- new String[]{"/dump/*","/dispatch/*","*.dump"});
- */
+ new String[]{"/*"});
}
public void contextDestroyed(ServletContextEvent sce)
diff --git a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
index a0c2bb3..9fc7003 100644
--- a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
+++ b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
@@ -18,20 +18,6 @@
<listener-class>com.acme.TestListener</listener-class>
</listener>
- <filter>
- <filter-name>TestFilter</filter-name>
- <filter-class>com.acme.TestFilter</filter-class>
- <async-support>true</async-support>
- <init-param>
- <param-name>remote</param-name>
- <param-value>false</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>TestFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
-
<filter>
<filter-name>QoSFilter</filter-name>
@@ -120,7 +106,6 @@
</filter-mapping>
-->
-
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>com.acme.HelloWorld</servlet-class>
@@ -275,6 +260,18 @@
<location>/error404.html</location>
</error-page>
+
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Rego2</web-resource-name>
+ <url-pattern>/rego2/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>server-administrator</role-name>
+ </auth-constraint>
+ </security-constraint>
+
<security-constraint>
<web-resource-collection>
<web-resource-name>Auth2</web-resource-name>
diff --git a/test-jetty-webapp/src/main/webapp/auth.html b/test-jetty-webapp/src/main/webapp/auth.html
index 1b1de11..0bce2d5 100644
--- a/test-jetty-webapp/src/main/webapp/auth.html
+++ b/test-jetty-webapp/src/main/webapp/auth.html
@@ -18,6 +18,8 @@
<li><a href="dump/auth/info">dump/auth/*</a> - Authenticated any user</li>
<li><a href="dump/auth/admin/info">dump/auth/admin/*</a> - Authenticated admin role (<a href="session/?Action=Invalidate">click</a> to invalidate session)</li>
<li><a href="dump/auth/ssl/info">dump/auth/ssl/*</a> - Confidential</li>
+<li><a href="rego/info">rego/info/*</a> - Authenticated admin role from programmatic security (<a href="session/?Action=Invalidate">click</a> to invalidate session)</li>
+<li><a href="rego2/info">rego2/info/*</a> - Authenticated servlet-administrator role from programmatic security (login as admin/admin, <a href="session/?Action=Invalidate">click</a> to invalidate session)</li>
</ul>
<p/>
<p>