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