View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.security;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Map.Entry;
30  import java.util.Set;
31  import java.util.concurrent.CopyOnWriteArrayList;
32  import java.util.concurrent.CopyOnWriteArraySet;
33  
34  import javax.servlet.HttpConstraintElement;
35  import javax.servlet.HttpMethodConstraintElement;
36  import javax.servlet.ServletSecurityElement;
37  import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
38  import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
39  
40  import org.eclipse.jetty.http.PathMap;
41  import org.eclipse.jetty.server.AbstractHttpConnection;
42  import org.eclipse.jetty.server.Connector;
43  import org.eclipse.jetty.server.Request;
44  import org.eclipse.jetty.server.Response;
45  import org.eclipse.jetty.server.UserIdentity;
46  import org.eclipse.jetty.util.StringMap;
47  import org.eclipse.jetty.util.TypeUtil;
48  import org.eclipse.jetty.util.security.Constraint;
49  
50  /* ------------------------------------------------------------ */
51  /**
52   * Handler to enforce SecurityConstraints. This implementation is servlet spec
53   * 3.0 compliant and precomputes the constraint combinations for runtime
54   * efficiency.
55   *
56   */
57  public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
58  {
59      private static final String OMISSION_SUFFIX = ".omission";
60      
61      private final List<ConstraintMapping> _constraintMappings= new CopyOnWriteArrayList<ConstraintMapping>();
62      private final Set<String> _roles = new CopyOnWriteArraySet<String>();
63      private final PathMap _constraintMap = new PathMap();
64      private boolean _strict = true;
65      
66      
67      /* ------------------------------------------------------------ */
68      /**
69       * @return
70       */
71      public static Constraint createConstraint()
72      {
73          return new Constraint();
74      }
75      
76      /* ------------------------------------------------------------ */
77      /**
78       * @param constraint
79       * @return
80       */
81      public static Constraint createConstraint(Constraint constraint)
82      {
83          try
84          {
85              return (Constraint)constraint.clone();
86          }
87          catch (CloneNotSupportedException e)
88          {
89              throw new IllegalStateException (e);
90          }
91      }
92      
93      /* ------------------------------------------------------------ */
94      /**
95       * Create a security constraint
96       * 
97       * @param name
98       * @param authenticate
99       * @param roles
100      * @param dataConstraint
101      * @return
102      */
103     public static Constraint createConstraint (String name, boolean authenticate, String[] roles, int dataConstraint)
104     {
105         Constraint constraint = createConstraint();
106         if (name != null)
107             constraint.setName(name);
108         constraint.setAuthenticate(authenticate);
109         constraint.setRoles(roles);
110         constraint.setDataConstraint(dataConstraint);
111         return constraint;
112     }
113     
114 
115     /* ------------------------------------------------------------ */
116     /**
117      * @param name
118      * @param element
119      * @return
120      */
121     public static Constraint createConstraint (String name, HttpConstraintElement element)
122     {
123         return createConstraint(name, element.getRolesAllowed(), element.getEmptyRoleSemantic(), element.getTransportGuarantee());     
124     }
125 
126 
127     /* ------------------------------------------------------------ */
128     /**
129      * @param name
130      * @param rolesAllowed
131      * @param permitOrDeny
132      * @param transport
133      * @return
134      */
135     public static Constraint createConstraint (String name, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
136     {
137         Constraint constraint = createConstraint();
138         
139         if (rolesAllowed == null || rolesAllowed.length==0)
140         {           
141             if (permitOrDeny.equals(EmptyRoleSemantic.DENY))
142             {
143                 //Equivalent to <auth-constraint> with no roles
144                 constraint.setName(name+"-Deny");
145                 constraint.setAuthenticate(true);
146             }
147             else
148             {
149                 //Equivalent to no <auth-constraint>
150                 constraint.setName(name+"-Permit");
151                 constraint.setAuthenticate(false);
152             }
153         }
154         else
155         {
156             //Equivalent to <auth-constraint> with list of <security-role-name>s
157             constraint.setAuthenticate(true);
158             constraint.setRoles(rolesAllowed);
159             constraint.setName(name+"-RolesAllowed");           
160         } 
161 
162         //Equivalent to //<user-data-constraint><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint>
163         constraint.setDataConstraint((transport.equals(TransportGuarantee.CONFIDENTIAL)?Constraint.DC_CONFIDENTIAL:Constraint.DC_NONE));
164         return constraint; 
165     }
166     
167     
168 
169     /* ------------------------------------------------------------ */
170     /**
171      * @param pathSpec
172      * @param constraintMappings
173      * @return
174      */
175     public static List<ConstraintMapping> getConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
176     {
177         if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
178             return Collections.emptyList();
179         
180         List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
181         for (ConstraintMapping mapping:constraintMappings)
182         {
183             if (pathSpec.equals(mapping.getPathSpec()))
184             {
185                mappings.add(mapping);
186             }
187         }
188         return mappings;
189     }
190     
191     
192     /* ------------------------------------------------------------ */
193     /** Take out of the constraint mappings those that match the 
194      * given path.
195      * 
196      * @param pathSpec
197      * @param constraintMappings a new list minus the matching constraints
198      * @return
199      */
200     public static List<ConstraintMapping> removeConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
201     {
202         if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
203             return Collections.emptyList();
204         
205         List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
206         for (ConstraintMapping mapping:constraintMappings)
207         {
208             //Remove the matching mappings by only copying in non-matching mappings
209             if (!pathSpec.equals(mapping.getPathSpec()))
210             {
211                mappings.add(mapping);
212             }
213         }
214         return mappings;
215     }
216     
217     
218     
219     /* ------------------------------------------------------------ */
220     /** Generate Constraints and ContraintMappings for the given url pattern and ServletSecurityElement
221      * 
222      * @param name
223      * @param pathSpec
224      * @param securityElement
225      * @return
226      */
227     public static List<ConstraintMapping> createConstraintsWithMappingsForPath (String name, String pathSpec, ServletSecurityElement securityElement)
228     {
229         List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
230 
231         //Create a constraint that will describe the default case (ie if not overridden by specific HttpMethodConstraints)
232         Constraint constraint = ConstraintSecurityHandler.createConstraint(name, securityElement);
233 
234         //Create a mapping for the pathSpec for the default case
235         ConstraintMapping defaultMapping = new ConstraintMapping();
236         defaultMapping.setPathSpec(pathSpec);
237         defaultMapping.setConstraint(constraint);  
238         mappings.add(defaultMapping);
239 
240 
241         //See Spec 13.4.1.2 p127
242         List<String> methodOmissions = new ArrayList<String>();
243         
244         //make constraint mappings for this url for each of the HttpMethodConstraintElements
245         Collection<HttpMethodConstraintElement> methodConstraints = securityElement.getHttpMethodConstraints();
246         if (methodConstraints != null)
247         {
248             for (HttpMethodConstraintElement methodConstraint:methodConstraints)
249             {
250                 //Make a Constraint that captures the <auth-constraint> and <user-data-constraint> elements supplied for the HttpMethodConstraintElement
251                 Constraint mconstraint = ConstraintSecurityHandler.createConstraint(name, methodConstraint);
252                 ConstraintMapping mapping = new ConstraintMapping();
253                 mapping.setConstraint(mconstraint);
254                 mapping.setPathSpec(pathSpec);
255                 if (methodConstraint.getMethodName() != null)
256                 {
257                     mapping.setMethod(methodConstraint.getMethodName());
258                     //See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
259                     methodOmissions.add(methodConstraint.getMethodName());
260                 }
261                 mappings.add(mapping);
262             }
263         }
264         //See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
265         if (methodOmissions.size() > 0)
266             defaultMapping.setMethodOmissions(methodOmissions.toArray(new String[methodOmissions.size()]));
267 
268         return mappings;
269     }
270     
271     
272     /* ------------------------------------------------------------ */
273     /** Get the strict mode.
274      * @return true if the security handler is running in strict mode.
275      */
276     public boolean isStrict()
277     {
278         return _strict;
279     }
280 
281     /* ------------------------------------------------------------ */
282     /** Set the strict mode of the security handler.
283      * <p>
284      * When in strict mode (the default), the full servlet specification
285      * will be implemented.
286      * If not in strict mode, some additional flexibility in configuration
287      * is allowed:<ul>
288      * <li>All users do not need to have a role defined in the deployment descriptor
289      * <li>The * role in a constraint applies to ANY role rather than all roles defined in
290      * the deployment descriptor.
291      * </ul>
292      *
293      * @param strict the strict to set
294      * @see #setRoles(Set)
295      * @see #setConstraintMappings(List, Set)
296      */
297     public void setStrict(boolean strict)
298     {
299         _strict = strict;
300     }
301 
302     /* ------------------------------------------------------------ */
303     /**
304      * @return Returns the constraintMappings.
305      */
306     public List<ConstraintMapping> getConstraintMappings()
307     {
308         return _constraintMappings;
309     }
310 
311     /* ------------------------------------------------------------ */
312     public Set<String> getRoles()
313     {
314         return _roles;
315     }
316 
317     /* ------------------------------------------------------------ */
318     /**
319      * Process the constraints following the combining rules in Servlet 3.0 EA
320      * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
321      *
322      * @param constraintMappings
323      *            The constraintMappings to set, from which the set of known roles
324      *            is determined.
325      */
326     public void setConstraintMappings(List<ConstraintMapping> constraintMappings)
327     {
328         setConstraintMappings(constraintMappings,null);
329     }
330 
331     /**
332      * Process the constraints following the combining rules in Servlet 3.0 EA
333      * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
334      *
335      * @param constraintMappings
336      *            The constraintMappings to set as array, from which the set of known roles
337      *            is determined.  Needed to retain API compatibility for 7.x
338      */
339     public void setConstraintMappings( ConstraintMapping[] constraintMappings )
340     {
341         setConstraintMappings( Arrays.asList(constraintMappings), null);
342     }
343 
344     /* ------------------------------------------------------------ */
345     /**
346      * Process the constraints following the combining rules in Servlet 3.0 EA
347      * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
348      *
349      * @param constraintMappings
350      *            The constraintMappings to set.
351      * @param roles The known roles (or null to determine them from the mappings)
352      */
353     public void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles)
354     {
355         _constraintMappings.clear();
356         _constraintMappings.addAll(constraintMappings);
357 
358         if (roles==null)
359         {
360             roles = new HashSet<String>();
361             for (ConstraintMapping cm : constraintMappings)
362             {
363                 String[] cmr = cm.getConstraint().getRoles();
364                 if (cmr!=null)
365                 {
366                     for (String r : cmr)
367                         if (!"*".equals(r))
368                             roles.add(r);
369                 }
370             }
371         }
372         setRoles(roles);
373         
374         if (isStarted())
375         {
376             for (ConstraintMapping mapping : _constraintMappings)
377             {
378                 processConstraintMapping(mapping);
379             }
380         }
381     }
382 
383     /* ------------------------------------------------------------ */
384     /**
385      * Set the known roles.
386      * This may be overridden by a subsequent call to {@link #setConstraintMappings(ConstraintMapping[])} or
387      * {@link #setConstraintMappings(List, Set)}.
388      * @see #setStrict(boolean)
389      * @param roles The known roles (or null to determine them from the mappings)
390      */
391     public void setRoles(Set<String> roles)
392     {
393         _roles.clear();
394         _roles.addAll(roles);
395     }
396 
397 
398 
399     /* ------------------------------------------------------------ */
400     /**
401      * @see org.eclipse.jetty.security.ConstraintAware#addConstraintMapping(org.eclipse.jetty.security.ConstraintMapping)
402      */
403     public void addConstraintMapping(ConstraintMapping mapping)
404     {
405         _constraintMappings.add(mapping);
406         if (mapping.getConstraint()!=null && mapping.getConstraint().getRoles()!=null)
407             for (String role :  mapping.getConstraint().getRoles())
408                 addRole(role);
409 
410         if (isStarted())
411         {
412             processConstraintMapping(mapping);
413         }
414     }
415 
416     /* ------------------------------------------------------------ */
417     /**
418      * @see org.eclipse.jetty.security.ConstraintAware#addRole(java.lang.String)
419      */
420     public void addRole(String role)
421     {
422         boolean modified = _roles.add(role);
423         if (isStarted() && modified && _strict)
424         {
425             // Add the new role to currently defined any role role infos
426             for (Map<String,RoleInfo> map : (Collection<Map<String,RoleInfo>>)_constraintMap.values())
427             {
428                 for (RoleInfo info : map.values())
429                 {
430                     if (info.isAnyRole())
431                         info.addRole(role);
432                 }
433             }
434         }
435     }
436 
437     /* ------------------------------------------------------------ */
438     /**
439      * @see org.eclipse.jetty.security.SecurityHandler#doStart()
440      */
441     @Override
442     protected void doStart() throws Exception
443     {
444         _constraintMap.clear();
445         if (_constraintMappings!=null)
446         {
447             for (ConstraintMapping mapping : _constraintMappings)
448             {
449                 processConstraintMapping(mapping);
450             }
451         }
452         super.doStart();
453     }
454     
455     
456     /* ------------------------------------------------------------ */
457     @Override
458     protected void doStop() throws Exception
459     {
460         _constraintMap.clear();
461         _constraintMappings.clear();
462         _roles.clear();
463         super.doStop();
464     }
465     
466     
467     /* ------------------------------------------------------------ */
468     /**
469      * Create and combine the constraint with the existing processed
470      * constraints.
471      * 
472      * @param mapping
473      */
474     protected void processConstraintMapping(ConstraintMapping mapping)
475     {
476         Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.get(mapping.getPathSpec());
477         if (mappings == null)
478         {
479             mappings = new StringMap();
480             _constraintMap.put(mapping.getPathSpec(),mappings);
481         }
482         RoleInfo allMethodsRoleInfo = mappings.get(null);
483         if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden())
484             return;
485        
486         if (mapping.getMethodOmissions() != null && mapping.getMethodOmissions().length > 0)
487         {
488            
489             processConstraintMappingWithMethodOmissions(mapping, mappings);
490             return;
491         }
492 
493         String httpMethod = mapping.getMethod();       
494         RoleInfo roleInfo = mappings.get(httpMethod);
495         if (roleInfo == null)
496         {
497             roleInfo = new RoleInfo();
498             mappings.put(httpMethod,roleInfo);
499             if (allMethodsRoleInfo != null)
500             {
501                 roleInfo.combine(allMethodsRoleInfo);
502             }
503         }
504         if (roleInfo.isForbidden())
505             return;
506 
507         //add in info from the constraint
508         configureRoleInfo(roleInfo, mapping);
509         
510         if (roleInfo.isForbidden())
511         {
512             if (httpMethod == null)
513             {
514                 mappings.clear();
515                 mappings.put(null,roleInfo);
516             }
517         }
518         else
519         {
520             //combine with any entry that covers all methods
521             if (httpMethod == null)
522             {
523                 for (Map.Entry<String, RoleInfo> entry : mappings.entrySet())
524                 {
525                     if (entry.getKey() != null)
526                     {
527                         RoleInfo specific = entry.getValue();
528                         specific.combine(roleInfo);
529                     }
530                 }
531             }
532         }
533     }
534 
535     /* ------------------------------------------------------------ */
536     /** Constraints that name method omissions are dealt with differently.
537      * We create an entry in the mappings with key "method.omission". This entry
538      * is only ever combined with other omissions for the same method to produce a
539      * consolidated RoleInfo. Then, when we wish to find the relevant constraints for
540      *  a given Request (in prepareConstraintInfo()), we consult 3 types of entries in 
541      * the mappings: an entry that names the method of the Request specifically, an
542      * entry that names constraints that apply to all methods, entries of the form
543      * method.omission, where the method of the Request is not named in the omission.
544      * @param mapping
545      * @param mappings
546      */
547     protected void processConstraintMappingWithMethodOmissions (ConstraintMapping mapping, Map<String, RoleInfo> mappings)
548     {
549         String[] omissions = mapping.getMethodOmissions();
550 
551         for (String omission:omissions)
552         {
553             //for each method omission, see if there is already a RoleInfo for it in mappings
554             RoleInfo ri = mappings.get(omission+OMISSION_SUFFIX);
555             if (ri == null)
556             {
557                 //if not, make one
558                 ri = new RoleInfo();
559                 mappings.put(omission+OMISSION_SUFFIX, ri);
560             }
561 
562             //initialize RoleInfo or combine from ConstraintMapping
563             configureRoleInfo(ri, mapping);
564         }
565     }
566     
567     
568     /* ------------------------------------------------------------ */
569     /**
570      * Initialize or update the RoleInfo from the constraint
571      * @param ri
572      * @param mapping
573      */
574     protected void configureRoleInfo (RoleInfo ri, ConstraintMapping mapping)
575     {
576         Constraint constraint = mapping.getConstraint();
577         boolean forbidden = constraint.isForbidden();
578         ri.setForbidden(forbidden);
579         
580         //set up the data constraint (NOTE: must be done after setForbidden, as it nulls out the data constraint
581         //which we need in order to do combining of omissions in prepareConstraintInfo
582         UserDataConstraint userDataConstraint = UserDataConstraint.get(mapping.getConstraint().getDataConstraint());
583         ri.setUserDataConstraint(userDataConstraint);
584         
585 
586         //if forbidden, no point setting up roles
587         if (!ri.isForbidden())
588         {
589             //add in the roles
590             boolean checked = mapping.getConstraint().getAuthenticate();
591             ri.setChecked(checked);
592             if (ri.isChecked())
593             {
594                 if (mapping.getConstraint().isAnyRole())
595                 {
596                     if (_strict)
597                     {
598                         // * means "all defined roles"
599                         for (String role : _roles)
600                             ri.addRole(role);
601                     }
602                     else
603                         // * means any role
604                         ri.setAnyRole(true);
605                 }
606                 else
607                 {
608                     String[] newRoles = mapping.getConstraint().getRoles();
609                     for (String role : newRoles)
610                     {
611                         if (_strict &&!_roles.contains(role))
612                             throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
613                         ri.addRole(role);
614                     }
615                 }
616             }
617         }
618     }
619    
620     
621     /* ------------------------------------------------------------ */
622     /** 
623      * Find constraints that apply to the given path.
624      * In order to do this, we consult 3 different types of information stored in the mappings for each path - each mapping
625      * represents a merged set of user data constraints, roles etc -:
626      * <ol>
627      * <li>A mapping of an exact method name </li>
628      * <li>A mapping will null key that matches every method name</li>
629      * <li>Mappings with keys of the form "method.omission" that indicates it will match every method name EXCEPT that given</li>
630      * </ol>
631      * 
632      * @see org.eclipse.jetty.security.SecurityHandler#prepareConstraintInfo(java.lang.String, org.eclipse.jetty.server.Request)
633      */
634     protected Object prepareConstraintInfo(String pathInContext, Request request)
635     {
636         Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext);
637 
638         if (mappings != null)
639         {
640             String httpMethod = request.getMethod();
641             RoleInfo roleInfo = mappings.get(httpMethod);
642             if (roleInfo == null)
643             {
644                 //No specific http-method names matched
645                 List<RoleInfo> applicableConstraints = new ArrayList<RoleInfo>();
646 
647                 //Get info for constraint that matches all methods if it exists
648                 RoleInfo all = mappings.get(null);
649                 if (all != null)
650                     applicableConstraints.add(all);
651           
652                 
653                 //Get info for constraints that name method omissions where target method name is not omitted
654                 //(ie matches because target method is not omitted, hence considered covered by the constraint)
655                 for (Entry<String, RoleInfo> entry: mappings.entrySet())
656                 {
657                     if (entry.getKey() != null && entry.getKey().contains(OMISSION_SUFFIX) && !(httpMethod+OMISSION_SUFFIX).equals(entry.getKey()))
658                         applicableConstraints.add(entry.getValue());
659                 }
660                 
661                 if (applicableConstraints.size() == 1)
662                     roleInfo = applicableConstraints.get(0);
663                 else
664                 {
665                     roleInfo = new RoleInfo();
666                     roleInfo.setUserDataConstraint(UserDataConstraint.None);
667                     
668                     for (RoleInfo r:applicableConstraints)
669                         roleInfo.combine(r);
670                 }
671 
672             }
673             return roleInfo;
674         }
675         return null;
676     }
677     
678     
679     /* ------------------------------------------------------------ */
680     /** 
681      * @see org.eclipse.jetty.security.SecurityHandler#checkUserDataPermissions(java.lang.String, org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object)
682      */
683     protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException
684     {
685         if (constraintInfo == null)
686             return true;
687 
688         RoleInfo roleInfo = (RoleInfo)constraintInfo;
689         if (roleInfo.isForbidden())
690             return false;
691 
692 
693         UserDataConstraint dataConstraint = roleInfo.getUserDataConstraint();
694         if (dataConstraint == null || dataConstraint == UserDataConstraint.None)
695         {
696             return true;
697         }
698         AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection();
699         Connector connector = connection.getConnector();
700 
701         if (dataConstraint == UserDataConstraint.Integral)
702         {
703             if (connector.isIntegral(request))
704                 return true;
705             if (connector.getIntegralPort() > 0)
706             {
707                 String url = connector.getIntegralScheme() + "://" + request.getServerName() + ":" + connector.getIntegralPort() + request.getRequestURI();
708                 if (request.getQueryString() != null)
709                     url += "?" + request.getQueryString();
710                 response.setContentLength(0);
711                 response.sendRedirect(url);
712             }
713             else
714                 response.sendError(Response.SC_FORBIDDEN,"!Integral");
715 
716             request.setHandled(true);
717             return false;
718         }
719         else if (dataConstraint == UserDataConstraint.Confidential)
720         {
721             if (connector.isConfidential(request))
722                 return true;
723 
724             if (connector.getConfidentialPort() > 0)
725             {
726                 String url = connector.getConfidentialScheme() + "://" + request.getServerName() + ":" + connector.getConfidentialPort()
727                         + request.getRequestURI();
728                 if (request.getQueryString() != null)
729                     url += "?" + request.getQueryString();
730 
731                 response.setContentLength(0);
732                 response.sendRedirect(url);
733             }
734             else
735                 response.sendError(Response.SC_FORBIDDEN,"!Confidential");
736 
737             request.setHandled(true);
738             return false;
739         }
740         else
741         {
742             throw new IllegalArgumentException("Invalid dataConstraint value: " + dataConstraint);
743         }
744 
745     }
746     
747     /* ------------------------------------------------------------ */
748     /** 
749      * @see org.eclipse.jetty.security.SecurityHandler#isAuthMandatory(org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object)
750      */
751     protected boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo)
752     {
753         if (constraintInfo == null)
754         {
755             return false;
756         }
757         return ((RoleInfo)constraintInfo).isChecked();
758     }
759     
760     
761     /* ------------------------------------------------------------ */
762     /** 
763      * @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)
764      */
765     @Override
766     protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo, UserIdentity userIdentity)
767             throws IOException
768     {
769         if (constraintInfo == null)
770         {
771             return true;
772         }
773         RoleInfo roleInfo = (RoleInfo)constraintInfo;
774 
775         if (!roleInfo.isChecked())
776         {
777             return true;
778         }
779 
780         if (roleInfo.isAnyRole() && request.getAuthType()!=null)
781             return true;
782 
783         for (String role : roleInfo.getRoles())
784         {
785             if (userIdentity.isUserInRole(role, null))
786                 return true;
787         }
788         return false;
789     }
790 
791     /* ------------------------------------------------------------ */
792     @Override
793     public void dump(Appendable out,String indent) throws IOException
794     {
795         dumpThis(out);
796         dump(out,indent,
797                 Collections.singleton(getLoginService()),
798                 Collections.singleton(getIdentityService()),
799                 Collections.singleton(getAuthenticator()),
800                 Collections.singleton(_roles),
801                 _constraintMap.entrySet(),
802                 getBeans(),
803                 TypeUtil.asList(getHandlers()));
804     }
805 
806 }