diff options
Diffstat (limited to 'jetty-security')
14 files changed, 882 insertions, 79 deletions
diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index 6cc9e14c54..841523ffa3 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -2,7 +2,7 @@ <parent> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-project</artifactId> - <version>7.6.11-SNAPSHOT</version> + <version>8.1.11-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jetty-security</artifactId> @@ -24,7 +24,7 @@ </goals> <configuration> <instructions> - <Import-Package>javax.servlet.*;version="[2.5,3.0)",javax.security.cert,*</Import-Package> + <Import-Package>javax.servlet.*;version="2.6.0",javax.security.cert,*</Import-Package> </instructions> </configuration> diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java index fd27205278..50ae8a2230 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java @@ -23,6 +23,7 @@ import org.eclipse.jetty.util.security.Constraint; public class ConstraintMapping { String _method; + String[] _methodOmissions; String _pathSpec; @@ -81,4 +82,19 @@ public class ConstraintMapping { this._pathSpec = pathSpec; } + + /* ------------------------------------------------------------ */ + /** + * @param omissions The http-method-omission + */ + public void setMethodOmissions(String[] omissions) + { + _methodOmissions = omissions; + } + + /* ------------------------------------------------------------ */ + public String[] getMethodOmissions() + { + return _methodOmissions; + } } 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 a7515cc274..c1f147a4c2 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 @@ -19,17 +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.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 org.eclipse.jetty.http.HttpSchemes; +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; @@ -43,17 +51,225 @@ import org.eclipse.jetty.util.security.Constraint; /* ------------------------------------------------------------ */ /** * 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. * */ 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; + } + + + /* ------------------------------------------------------------ */ + /** Take out of the constraint mappings those that match the + * given path. + * + * @param pathSpec + * @param constraintMappings a new list minus the matching constraints + * @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. @@ -137,8 +353,6 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr */ public void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles) { - if (isStarted()) - throw new IllegalStateException("Started"); _constraintMappings.clear(); _constraintMappings.addAll(constraintMappings); @@ -157,6 +371,14 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr } } setRoles(roles); + + if (isStarted()) + { + for (ConstraintMapping mapping : _constraintMappings) + { + processConstraintMapping(mapping); + } + } } /* ------------------------------------------------------------ */ @@ -169,9 +391,6 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr */ public void setRoles(Set<String> roles) { - if (isStarted()) - throw new IllegalStateException("Started"); - _roles.clear(); _roles.addAll(roles); } @@ -233,7 +452,9 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr } super.doStart(); } - + + + /* ------------------------------------------------------------ */ @Override protected void doStop() throws Exception { @@ -242,7 +463,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()); @@ -254,8 +483,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) { @@ -269,10 +505,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) { @@ -282,50 +518,120 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr } else { - UserDataConstraint userDataConstraint = UserDataConstraint.get(constraint.getDataConstraint()); - roleInfo.setUserDataConstraint(userDataConstraint); + //combine with any entry that covers all methods + if (httpMethod == null) + { + for (Map.Entry<String, RoleInfo> entry : mappings.entrySet()) + { + if (entry.getKey() != null) + { + RoleInfo specific = entry.getValue(); + specific.combine(roleInfo); + } + } + } + } + } + + /* ------------------------------------------------------------ */ + /** 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(); - boolean checked = constraint.getAuthenticate(); - roleInfo.setChecked(checked); - if (roleInfo.isChecked()) + 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 (constraint.isAnyRole()) + //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) - roleInfo.addRole(role); + ri.addRole(role); } else // * means any role - roleInfo.setAnyRole(true); + ri.setAnyRole(true); } else { - String[] newRoles = constraint.getRoles(); + 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); - roleInfo.addRole(role); - } - } - } - if (httpMethod == null) - { - for (Map.Entry<String, RoleInfo> entry : mappings.entrySet()) - { - if (entry.getKey() != null) - { - RoleInfo specific = entry.getValue(); - specific.combine(roleInfo); + 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); @@ -335,13 +641,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) @@ -411,7 +750,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) @@ -420,7 +763,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 @@ -461,4 +809,5 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr getBeans(), TypeUtil.asList(getHandlers())); } + } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java index 93da8d2e87..1699c214b4 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java @@ -335,6 +335,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti if (_identityService==null) { + if (_loginService!=null) _identityService=_loginService.getIdentityService(); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java index 48712cd815..b5d85b3031 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/BasicAuthenticator.java @@ -54,6 +54,8 @@ public class BasicAuthenticator extends LoginAuthenticator return Constraint.__BASIC_AUTH; } + + /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.security.Authenticator#validateRequest(javax.servlet.ServletRequest, javax.servlet.ServletResponse, boolean) @@ -85,10 +87,9 @@ public class BasicAuthenticator extends LoginAuthenticator String username = credentials.substring(0,i); String password = credentials.substring(i+1); - UserIdentity user = _loginService.login(username,password); + UserIdentity user = login (username, password, request); if (user!=null) { - renewSession(request,response); return new UserAuthentication(getAuthMethod(),user); } } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java index d16f32b751..6b026fcbe5 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java @@ -81,6 +81,8 @@ public class ClientCertAuthenticator extends LoginAuthenticator return Constraint.__CERT_AUTH; } + + /** * @return Authentication for request * @throws ServerAuthException @@ -121,10 +123,9 @@ public class ClientCertAuthenticator extends LoginAuthenticator final char[] credential = B64Code.encode(cert.getSignature()); - UserIdentity user = _loginService.login(username,credential); + UserIdentity user = login(username, credential, req); if (user!=null) { - renewSession(request,response); return new UserAuthentication(getAuthMethod(),user); } } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java index 62392fbe8e..36b7a934f2 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java @@ -21,12 +21,15 @@ package org.eclipse.jetty.security.authentication; import java.io.IOException; import java.io.PrintWriter; +import java.util.Collection; +import java.util.Collections; import java.util.Locale; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.security.Authenticator; @@ -71,6 +74,7 @@ public class DeferredAuthentication implements Authentication.Deferred if (identity_service!=null) _previousAssociation=identity_service.associate(((Authentication.User)authentication).getUserIdentity()); + return authentication; } } @@ -78,7 +82,8 @@ public class DeferredAuthentication implements Authentication.Deferred { LOG.debug(e); } - return Authentication.UNAUTHENTICATED; + + return this; } /* ------------------------------------------------------------ */ @@ -101,28 +106,23 @@ public class DeferredAuthentication implements Authentication.Deferred { LOG.debug(e); } - return Authentication.UNAUTHENTICATED; + return this; } /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.server.Authentication.Deferred#login(java.lang.String, java.lang.String) */ - public Authentication login(String username, String password) + public Authentication login(String username, Object password, ServletRequest request) { - LoginService login_service= _authenticator.getLoginService(); - IdentityService identity_service=login_service.getIdentityService(); - - if (login_service!=null) + UserIdentity identity = _authenticator.login(username, password, request); + if (identity != null) { - UserIdentity user = login_service.login(username,password); - if (user!=null) - { - UserAuthentication authentication = new UserAuthentication("API",user); - if (identity_service!=null) - _previousAssociation=identity_service.associate(user); - return authentication; - } + IdentityService identity_service = _authenticator.getLoginService().getIdentityService(); + UserAuthentication authentication = new UserAuthentication("API",identity); + if (identity_service != null) + _previousAssociation=identity_service.associate(identity); + return authentication; } return null; } @@ -288,6 +288,29 @@ public class DeferredAuthentication implements Authentication.Deferred { } + public Collection<String> getHeaderNames() + { + return Collections.emptyList(); + } + + @Override + public String getHeader(String arg0) + { + return null; + } + + @Override + public Collection<String> getHeaders(String arg0) + { + return Collections.emptyList(); + } + + @Override + public int getStatus() + { + return 0; + } + }; /* ------------------------------------------------------------ */ @@ -309,4 +332,4 @@ public class DeferredAuthentication implements Authentication.Deferred }; -}
\ No newline at end of file +} diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java index 761080bcce..eabdc8cfec 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java @@ -148,6 +148,8 @@ public class DigestAuthenticator extends LoginAuthenticator { return true; } + + /* ------------------------------------------------------------ */ public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException @@ -217,10 +219,10 @@ public class DigestAuthenticator extends LoginAuthenticator if (n > 0) { - UserIdentity user = _loginService.login(digest.username,digest); + //UserIdentity user = _loginService.login(digest.username,digest); + UserIdentity user = login(digest.username, digest, req); if (user!=null) { - renewSession(request,response); return new UserAuthentication(getAuthMethod(),user); } } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java index d8914f1ef9..21e83150e4 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java @@ -180,6 +180,22 @@ public class FormAuthenticator extends LoginAuthenticator _formErrorPath = _formErrorPath.substring(0, _formErrorPath.indexOf('?')); } } + + + /* ------------------------------------------------------------ */ + @Override + public UserIdentity login(String username, Object password, ServletRequest request) + { + + UserIdentity user = super.login(username,password,request); + if (user!=null) + { + HttpSession session = ((HttpServletRequest)request).getSession(true); + Authentication cached=new SessionAuthentication(getAuthMethod(),user,password); + session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached); + } + return user; + } /* ------------------------------------------------------------ */ public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException @@ -207,11 +223,10 @@ public class FormAuthenticator extends LoginAuthenticator final String username = request.getParameter(__J_USERNAME); final String password = request.getParameter(__J_PASSWORD); - UserIdentity user = _loginService.login(username,password); + UserIdentity user = login(username, password, request); + session = request.getSession(true); if (user!=null) - { - session=renewSession(request,response); - + { // Redirect to original request String nuri; synchronized(session) @@ -224,9 +239,6 @@ public class FormAuthenticator extends LoginAuthenticator if (nuri.length() == 0) nuri = URIUtil.SLASH; } - - Authentication cached=new SessionAuthentication(getAuthMethod(),user,password); - session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached); } response.setContentLength(0); response.sendRedirect(response.encodeRedirectURL(nuri)); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java index 93993172e5..23b09e8483 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.security.authentication; +import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -25,6 +26,8 @@ import javax.servlet.http.HttpSession; import org.eclipse.jetty.security.Authenticator; import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.LoginService; +import org.eclipse.jetty.server.Authentication; +import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.session.AbstractSessionManager; public abstract class LoginAuthenticator implements Authenticator @@ -37,6 +40,20 @@ public abstract class LoginAuthenticator implements Authenticator { } + + /* ------------------------------------------------------------ */ + public UserIdentity login(String username, Object password, ServletRequest request) + { + UserIdentity user = _loginService.login(username,password); + if (user!=null) + { + renewSession((HttpServletRequest)request, null); + return user; + } + return null; + } + + public void setConfiguration(AuthConfiguration configuration) { _loginService=configuration.getLoginService(); diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java index ec462c4ea5..5f2b7b5df6 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java @@ -98,8 +98,8 @@ public class SessionAuthentication implements Authentication.User, Serializable, { if (_session!=null && _session.getAttribute(__J_AUTHENTICATED)!=null) _session.removeAttribute(__J_AUTHENTICATED); - else - doLogout(); + + doLogout(); } private void doLogout() diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java index ebb8a9e8b1..ab1b8edc27 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java @@ -60,6 +60,8 @@ public class SpnegoAuthenticator extends LoginAuthenticator return _authMethod; } + + public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException { HttpServletRequest req = (HttpServletRequest)request; @@ -96,7 +98,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator { String spnegoToken = header.substring(10); - UserIdentity user = _loginService.login(null,spnegoToken); + UserIdentity user = login(null,spnegoToken, request); if ( user != null ) { 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 474b5eafd6..7d4945a9a6 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 @@ -22,10 +22,12 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.ArrayList; import java.security.MessageDigest; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; @@ -83,6 +85,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); @@ -203,6 +207,46 @@ 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(); @@ -210,10 +254,10 @@ public class ConstraintTest 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); @@ -228,7 +272,7 @@ 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")); @@ -254,8 +298,32 @@ 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")); } - + private static String CNONCE="1234567890"; private String digest(String nonce, String username,String password,String uri,String nc) throws Exception @@ -1023,7 +1091,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"); diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/SpecExampleConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/SpecExampleConstraintTest.java new file mode 100644 index 0000000000..8dab97c8ec --- /dev/null +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/SpecExampleConstraintTest.java @@ -0,0 +1,311 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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")); + } + } + +} |