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.HashMap;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Map.Entry;
31  import java.util.Set;
32  import java.util.concurrent.CopyOnWriteArrayList;
33  import java.util.concurrent.CopyOnWriteArraySet;
34  
35  import javax.servlet.HttpConstraintElement;
36  import javax.servlet.HttpMethodConstraintElement;
37  import javax.servlet.ServletSecurityElement;
38  import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
39  import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
40  
41  import org.eclipse.jetty.http.HttpStatus;
42  import org.eclipse.jetty.http.PathMap;
43  import org.eclipse.jetty.server.HttpChannel;
44  import org.eclipse.jetty.server.HttpConfiguration;
45  import org.eclipse.jetty.server.Request;
46  import org.eclipse.jetty.server.Response;
47  import org.eclipse.jetty.server.UserIdentity;
48  import org.eclipse.jetty.util.StringMap;
49  import org.eclipse.jetty.util.security.Constraint;
50  
51  /* ------------------------------------------------------------ */
52  /**
53   * Handler to enforce SecurityConstraints. This implementation is servlet spec
54   * 3.0 compliant and pre-computes the constraint combinations for runtime
55   * efficiency.
56   *
57   */
58  public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
59  {
60      private static final String OMISSION_SUFFIX = ".omission";
61      private static final String ALL_METHODS = "*";
62      private final List<ConstraintMapping> _constraintMappings= new CopyOnWriteArrayList<>();
63      private final Set<String> _roles = new CopyOnWriteArraySet<>();
64      private final PathMap<Map<String, RoleInfo>> _constraintMap = new PathMap<>();
65      private boolean _strict = true;
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     /* ------------------------------------------------------------ */
274     /** Get the strict mode.
275      * @return true if the security handler is running in strict mode.
276      */
277     public boolean isStrict()
278     {
279         return _strict;
280     }
281 
282     /* ------------------------------------------------------------ */
283     /** Set the strict mode of the security handler.
284      * <p>
285      * When in strict mode (the default), the full servlet specification
286      * will be implemented.
287      * If not in strict mode, some additional flexibility in configuration
288      * is allowed:<ul>
289      * <li>All users do not need to have a role defined in the deployment descriptor
290      * <li>The * role in a constraint applies to ANY role rather than all roles defined in
291      * the deployment descriptor.
292      * </ul>
293      *
294      * @param strict the strict to set
295      * @see #setRoles(Set)
296      * @see #setConstraintMappings(List, Set)
297      */
298     public void setStrict(boolean strict)
299     {
300         _strict = strict;
301     }
302 
303     /* ------------------------------------------------------------ */
304     /**
305      * @return Returns the constraintMappings.
306      */
307     @Override
308     public List<ConstraintMapping> getConstraintMappings()
309     {
310         return _constraintMappings;
311     }
312 
313     /* ------------------------------------------------------------ */
314     @Override
315     public Set<String> getRoles()
316     {
317         return _roles;
318     }
319 
320     /* ------------------------------------------------------------ */
321     /**
322      * Process the constraints following the combining rules in Servlet 3.0 EA
323      * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
324      *
325      * @param constraintMappings
326      *            The constraintMappings to set, from which the set of known roles
327      *            is determined.
328      */
329     public void setConstraintMappings(List<ConstraintMapping> constraintMappings)
330     {
331         setConstraintMappings(constraintMappings,null);
332     }
333 
334     /**
335      * Process the constraints following the combining rules in Servlet 3.0 EA
336      * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
337      *
338      * @param constraintMappings
339      *            The constraintMappings to set as array, from which the set of known roles
340      *            is determined.  Needed to retain API compatibility for 7.x
341      */
342     public void setConstraintMappings( ConstraintMapping[] constraintMappings )
343     {
344         setConstraintMappings( Arrays.asList(constraintMappings), null);
345     }
346 
347     /* ------------------------------------------------------------ */
348     /**
349      * Process the constraints following the combining rules in Servlet 3.0 EA
350      * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
351      *
352      * @param constraintMappings
353      *            The constraintMappings to set.
354      * @param roles The known roles (or null to determine them from the mappings)
355      */
356     @Override
357     public void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles)
358     {
359         _constraintMappings.clear();
360         _constraintMappings.addAll(constraintMappings);
361 
362         if (roles==null)
363         {
364             roles = new HashSet<>();
365             for (ConstraintMapping cm : constraintMappings)
366             {
367                 String[] cmr = cm.getConstraint().getRoles();
368                 if (cmr!=null)
369                 {
370                     for (String r : cmr)
371                         if (!ALL_METHODS.equals(r))
372                             roles.add(r);
373                 }
374             }
375         }
376         setRoles(roles);
377         
378         if (isStarted())
379         {
380             for (ConstraintMapping mapping : _constraintMappings)
381             {
382                 processConstraintMapping(mapping);
383             }
384         }
385     }
386 
387     /* ------------------------------------------------------------ */
388     /**
389      * Set the known roles.
390      * This may be overridden by a subsequent call to {@link #setConstraintMappings(ConstraintMapping[])} or
391      * {@link #setConstraintMappings(List, Set)}.
392      * @see #setStrict(boolean)
393      * @param roles The known roles (or null to determine them from the mappings)
394      */
395     public void setRoles(Set<String> roles)
396     {
397         _roles.clear();
398         _roles.addAll(roles);
399     }
400 
401 
402 
403     /* ------------------------------------------------------------ */
404     /**
405      * @see org.eclipse.jetty.security.ConstraintAware#addConstraintMapping(org.eclipse.jetty.security.ConstraintMapping)
406      */
407     @Override
408     public void addConstraintMapping(ConstraintMapping mapping)
409     {
410         _constraintMappings.add(mapping);
411         if (mapping.getConstraint()!=null && mapping.getConstraint().getRoles()!=null)
412             for (String role :  mapping.getConstraint().getRoles())
413                 addRole(role);
414 
415         if (isStarted())
416         {
417             processConstraintMapping(mapping);
418         }
419     }
420 
421     /* ------------------------------------------------------------ */
422     /**
423      * @see org.eclipse.jetty.security.ConstraintAware#addRole(java.lang.String)
424      */
425     @Override
426     public void addRole(String role)
427     {
428         boolean modified = _roles.add(role);
429         if (isStarted() && modified && isStrict())
430         {
431             // Add the new role to currently defined any role role infos
432             for (Map<String,RoleInfo> map : _constraintMap.values())
433             {
434                 for (RoleInfo info : map.values())
435                 {
436                     if (info.isAnyRole())
437                         info.addRole(role);
438                 }
439             }
440         }
441     }
442 
443     /* ------------------------------------------------------------ */
444     /**
445      * @see org.eclipse.jetty.security.SecurityHandler#doStart()
446      */
447     @Override
448     protected void doStart() throws Exception
449     {
450         _constraintMap.clear();
451         if (_constraintMappings!=null)
452         {
453             for (ConstraintMapping mapping : _constraintMappings)
454             {
455                 processConstraintMapping(mapping);
456             }
457         }
458         super.doStart();
459     }
460     
461     
462     /* ------------------------------------------------------------ */
463     @Override
464     protected void doStop() throws Exception
465     {
466         super.doStop();
467         _constraintMap.clear();
468     }
469     
470     
471     /* ------------------------------------------------------------ */
472     /**
473      * Create and combine the constraint with the existing processed
474      * constraints.
475      * 
476      * @param mapping
477      */
478     protected void processConstraintMapping(ConstraintMapping mapping)
479     {
480         Map<String, RoleInfo> mappings = _constraintMap.get(mapping.getPathSpec());
481         if (mappings == null)
482         {
483             mappings = new HashMap<String,RoleInfo>();
484             _constraintMap.put(mapping.getPathSpec(),mappings);
485         }
486         RoleInfo allMethodsRoleInfo = mappings.get(ALL_METHODS);
487         if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden())
488             return;
489 
490         if (mapping.getMethodOmissions() != null && mapping.getMethodOmissions().length > 0)
491         {
492             processConstraintMappingWithMethodOmissions(mapping, mappings);
493             return;
494         }
495 
496         String httpMethod = mapping.getMethod();
497         if (httpMethod==null)
498             httpMethod=ALL_METHODS;
499         RoleInfo roleInfo = mappings.get(httpMethod);
500         if (roleInfo == null)
501         {
502             roleInfo = new RoleInfo();
503             mappings.put(httpMethod,roleInfo);
504             if (allMethodsRoleInfo != null)
505             {
506                 roleInfo.combine(allMethodsRoleInfo);
507             }
508         }
509         if (roleInfo.isForbidden())
510             return;
511 
512         //add in info from the constraint
513         configureRoleInfo(roleInfo, mapping);
514         
515         if (roleInfo.isForbidden())
516         {
517             if (httpMethod.equals(ALL_METHODS))
518             {
519                 mappings.clear();
520                 mappings.put(ALL_METHODS,roleInfo);
521             }
522         }
523         else
524         {
525             //combine with any entry that covers all methods
526             if (httpMethod == null)
527             {
528                 for (Map.Entry<String, RoleInfo> entry : mappings.entrySet())
529                 {
530                     if (entry.getKey() != null)
531                     {
532                         RoleInfo specific = entry.getValue();
533                         specific.combine(roleInfo);
534                     }
535                 }
536             }
537         }
538     }
539 
540     /* ------------------------------------------------------------ */
541     /** Constraints that name method omissions are dealt with differently.
542      * We create an entry in the mappings with key "method.omission". This entry
543      * is only ever combined with other omissions for the same method to produce a
544      * consolidated RoleInfo. Then, when we wish to find the relevant constraints for
545      *  a given Request (in prepareConstraintInfo()), we consult 3 types of entries in 
546      * the mappings: an entry that names the method of the Request specifically, an
547      * entry that names constraints that apply to all methods, entries of the form
548      * method.omission, where the method of the Request is not named in the omission.
549      * @param mapping
550      * @param mappings
551      */
552     protected void processConstraintMappingWithMethodOmissions (ConstraintMapping mapping, Map<String, RoleInfo> mappings)
553     {
554         String[] omissions = mapping.getMethodOmissions();
555 
556         for (String omission:omissions)
557         {
558             //for each method omission, see if there is already a RoleInfo for it in mappings
559             RoleInfo ri = mappings.get(omission+OMISSION_SUFFIX);
560             if (ri == null)
561             {
562                 //if not, make one
563                 ri = new RoleInfo();
564                 mappings.put(omission+OMISSION_SUFFIX, ri);
565             }
566 
567             //initialize RoleInfo or combine from ConstraintMapping
568             configureRoleInfo(ri, mapping);
569         }
570     }
571     
572     
573     /* ------------------------------------------------------------ */
574     /**
575      * Initialize or update the RoleInfo from the constraint
576      * @param ri
577      * @param mapping
578      */
579     protected void configureRoleInfo (RoleInfo ri, ConstraintMapping mapping)
580     {
581         Constraint constraint = mapping.getConstraint();
582         boolean forbidden = constraint.isForbidden();
583         ri.setForbidden(forbidden);
584         
585         //set up the data constraint (NOTE: must be done after setForbidden, as it nulls out the data constraint
586         //which we need in order to do combining of omissions in prepareConstraintInfo
587         UserDataConstraint userDataConstraint = UserDataConstraint.get(mapping.getConstraint().getDataConstraint());
588         ri.setUserDataConstraint(userDataConstraint);
589         
590 
591         //if forbidden, no point setting up roles
592         if (!ri.isForbidden())
593         {
594             //add in the roles
595             boolean checked = mapping.getConstraint().getAuthenticate();
596             ri.setChecked(checked);
597             if (ri.isChecked())
598             {
599                 if (mapping.getConstraint().isAnyRole())
600                  {
601                      if (_strict)
602                      {
603                          // * means "all defined roles"
604                          for (String role : _roles)
605                             ri.addRole(role);
606                      }
607                      else
608                          // * means any role
609                         ri.setAnyRole(true);
610                  }
611                  else
612                  {
613                     String[] newRoles = mapping.getConstraint().getRoles();
614                      for (String role : newRoles)
615                      {
616                          if (_strict &&!_roles.contains(role))
617                              throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
618                         ri.addRole(role);
619                      }
620                  }
621              }
622          }
623      }
624 
625    
626     /* ------------------------------------------------------------ */
627     /** 
628      * Find constraints that apply to the given path.
629      * In order to do this, we consult 3 different types of information stored in the mappings for each path - each mapping
630      * represents a merged set of user data constraints, roles etc -:
631      * <ol>
632      * <li>A mapping of an exact method name </li>
633      * <li>A mapping will null key that matches every method name</li>
634      * <li>Mappings with keys of the form "method.omission" that indicates it will match every method name EXCEPT that given</li>
635      * </ol>
636      * 
637      * @see org.eclipse.jetty.security.SecurityHandler#prepareConstraintInfo(java.lang.String, org.eclipse.jetty.server.Request)
638      */
639     @Override
640     protected RoleInfo prepareConstraintInfo(String pathInContext, Request request)
641     {
642         Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext);
643 
644         if (mappings != null)
645         {
646             String httpMethod = request.getMethod();
647             RoleInfo roleInfo = mappings.get(httpMethod);
648             if (roleInfo == null)
649             {
650                 //No specific http-method names matched
651                 List<RoleInfo> applicableConstraints = new ArrayList<RoleInfo>();
652 
653                 //Get info for constraint that matches all methods if it exists
654                 RoleInfo all = mappings.get(ALL_METHODS);
655                 if (all != null)
656                     applicableConstraints.add(all);
657           
658                 
659                 //Get info for constraints that name method omissions where target method name is not omitted
660                 //(ie matches because target method is not omitted, hence considered covered by the constraint)
661                 for (Entry<String, RoleInfo> entry: mappings.entrySet())
662                 {
663                     if (entry.getKey() != null && entry.getKey().contains(OMISSION_SUFFIX) && !(httpMethod+OMISSION_SUFFIX).equals(entry.getKey()))
664                         applicableConstraints.add(entry.getValue());
665                 }
666                 
667                 if (applicableConstraints.size() == 1)
668                     roleInfo = applicableConstraints.get(0);
669                 else
670                 {
671                     roleInfo = new RoleInfo();
672                     roleInfo.setUserDataConstraint(UserDataConstraint.None);
673                     
674                     for (RoleInfo r:applicableConstraints)
675                         roleInfo.combine(r);
676                 }
677 
678             }
679             return roleInfo;
680         }
681 
682         return null;
683     }
684 
685     @Override
686     protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response, RoleInfo roleInfo) throws IOException
687     {
688         if (roleInfo == null)
689             return true;
690 
691         if (roleInfo.isForbidden())
692             return false;
693 
694         UserDataConstraint dataConstraint = roleInfo.getUserDataConstraint();
695         if (dataConstraint == null || dataConstraint == UserDataConstraint.None)
696             return true;
697 
698         HttpConfiguration httpConfig = HttpChannel.getCurrentHttpChannel().getHttpConfiguration();
699 
700         if (dataConstraint == UserDataConstraint.Confidential || dataConstraint == UserDataConstraint.Integral)
701         {
702             if (request.isSecure())
703                 return true;
704 
705             if (httpConfig.getSecurePort() > 0)
706             {
707                 String url = httpConfig.getSecureScheme() + "://" + request.getServerName() + ":" + httpConfig.getSecurePort()
708                         + request.getRequestURI();
709                 if (request.getQueryString() != null)
710                     url += "?" + request.getQueryString();
711 
712                 response.setContentLength(0);
713                 response.sendRedirect(url);
714             }
715             else
716                 response.sendError(HttpStatus.FORBIDDEN_403,"!Secure");
717 
718             request.setHandled(true);
719             return false;
720         }
721         else
722         {
723             throw new IllegalArgumentException("Invalid dataConstraint value: " + dataConstraint);
724         }
725 
726     }
727 
728     @Override
729     protected boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo)
730     {
731         return constraintInfo != null && ((RoleInfo)constraintInfo).isChecked();
732     }
733     
734     
735     /* ------------------------------------------------------------ */
736     /** 
737      * @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)
738      */
739     @Override
740     protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo, UserIdentity userIdentity)
741             throws IOException
742     {
743         if (constraintInfo == null)
744         {
745             return true;
746         }
747         RoleInfo roleInfo = (RoleInfo)constraintInfo;
748 
749         if (!roleInfo.isChecked())
750         {
751             return true;
752         }
753 
754         if (roleInfo.isAnyRole() && request.getAuthType()!=null)
755             return true;
756 
757         for (String role : roleInfo.getRoles())
758         {
759             if (userIdentity.isUserInRole(role, null))
760                 return true;
761         }
762         return false;
763     }
764 
765     /* ------------------------------------------------------------ */
766     @Override
767     public void dump(Appendable out,String indent) throws IOException
768     {
769         // TODO these should all be beans
770         dumpBeans(out,indent,
771                 Collections.singleton(getLoginService()),
772                 Collections.singleton(getIdentityService()),
773                 Collections.singleton(getAuthenticator()),
774                 Collections.singleton(_roles),
775                 _constraintMap.entrySet());
776     }
777 
778 }