All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.security.ConstraintSecurityHandler Maven / Gradle / Ivy

There is a newer version: 11.0.0.beta1
Show newest version
//
//  ========================================================================
//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.servlet.HttpConstraintElement;
import javax.servlet.HttpMethodConstraintElement;
import javax.servlet.ServletSecurityElement;
import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;

import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;

/* ------------------------------------------------------------ */
/**
 * ConstraintSecurityHandler
 * 
 * Handler to enforce SecurityConstraints. This implementation is servlet spec
 * 3.1 compliant and pre-computes the constraint combinations for runtime
 * efficiency.
 *
 */
public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
{
    private static final Logger LOG = Log.getLogger(SecurityHandler.class); //use same as SecurityHandler
    
    private static final String OMISSION_SUFFIX = ".omission";
    private static final String ALL_METHODS = "*";
    private final List _constraintMappings= new CopyOnWriteArrayList<>();
    private final Set _roles = new CopyOnWriteArraySet<>();
    private final PathMap> _constraintMap = new PathMap<>();
    private boolean _denyUncoveredMethods = false;


    /* ------------------------------------------------------------ */
    public static Constraint createConstraint()
    {
        return new Constraint();
    }
    
    /* ------------------------------------------------------------ */
    /**
     * @param constraint
     */
    public static Constraint createConstraint(Constraint constraint)
    {
        try
        {
            return (Constraint)constraint.clone();
        }
        catch (CloneNotSupportedException e)
        {
            throw new IllegalStateException (e);
        }
    }
    
    /* ------------------------------------------------------------ */
    /**
     * Create a security constraint
     * 
     * @param name
     * @param authenticate
     * @param roles
     * @param dataConstraint
     */
    public static Constraint createConstraint (String name, boolean authenticate, String[] roles, int dataConstraint)
    {
        Constraint constraint = createConstraint();
        if (name != null)
            constraint.setName(name);
        constraint.setAuthenticate(authenticate);
        constraint.setRoles(roles);
        constraint.setDataConstraint(dataConstraint);
        return constraint;
    }
    

    /* ------------------------------------------------------------ */
    /**
     * @param name
     * @param element
     */
    public static Constraint createConstraint (String name, HttpConstraintElement element)
    {
        return createConstraint(name, element.getRolesAllowed(), element.getEmptyRoleSemantic(), element.getTransportGuarantee());     
    }


    /* ------------------------------------------------------------ */
    /**
     * @param name
     * @param rolesAllowed
     * @param permitOrDeny
     * @param transport
     */
    public static Constraint createConstraint (String name, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
    {
        Constraint constraint = createConstraint();
        
        if (rolesAllowed == null || rolesAllowed.length==0)
        {           
            if (permitOrDeny.equals(EmptyRoleSemantic.DENY))
            {
                //Equivalent to  with no roles
                constraint.setName(name+"-Deny");
                constraint.setAuthenticate(true);
            }
            else
            {
                //Equivalent to no 
                constraint.setName(name+"-Permit");
                constraint.setAuthenticate(false);
            }
        }
        else
        {
            //Equivalent to  with list of s
            constraint.setAuthenticate(true);
            constraint.setRoles(rolesAllowed);
            constraint.setName(name+"-RolesAllowed");           
        } 

        //Equivalent to //CONFIDENTIAL
        constraint.setDataConstraint((transport.equals(TransportGuarantee.CONFIDENTIAL)?Constraint.DC_CONFIDENTIAL:Constraint.DC_NONE));
        return constraint; 
    }
    
    

    /* ------------------------------------------------------------ */
    /**
     * @param pathSpec
     * @param constraintMappings
     */
    public static List getConstraintMappingsForPath(String pathSpec, List constraintMappings)
    {
        if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
            return Collections.emptyList();
        
        List mappings = new ArrayList();
        for (ConstraintMapping mapping:constraintMappings)
        {
            if (pathSpec.equals(mapping.getPathSpec()))
            {
               mappings.add(mapping);
            }
        }
        return mappings;
    }
    
    
    /* ------------------------------------------------------------ */
    /** Take out of the constraint mappings those that match the 
     * given path.
     * 
     * @param pathSpec
     * @param constraintMappings a new list minus the matching constraints
     */
    public static List removeConstraintMappingsForPath(String pathSpec, List constraintMappings)
    {
        if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
            return Collections.emptyList();
        
        List mappings = new ArrayList();
        for (ConstraintMapping mapping:constraintMappings)
        {
            //Remove the matching mappings by only copying in non-matching mappings
            if (!pathSpec.equals(mapping.getPathSpec()))
            {
               mappings.add(mapping);
            }
        }
        return mappings;
    }
    
    
    
    /* ------------------------------------------------------------ */
    /** Generate Constraints and ContraintMappings for the given url pattern and ServletSecurityElement
     * 
     * @param name
     * @param pathSpec
     * @param securityElement
     * @return
     */
    public static List createConstraintsWithMappingsForPath (String name, String pathSpec, ServletSecurityElement securityElement)
    {
        List mappings = new ArrayList();

        //Create a constraint that will describe the default case (ie if not overridden by specific HttpMethodConstraints)
        Constraint httpConstraint = null;
        ConstraintMapping httpConstraintMapping = null;
        
        if (securityElement.getEmptyRoleSemantic() != EmptyRoleSemantic.PERMIT ||
            securityElement.getRolesAllowed().length != 0 ||
            securityElement.getTransportGuarantee() != TransportGuarantee.NONE)
        {
            httpConstraint = ConstraintSecurityHandler.createConstraint(name, securityElement);

            //Create a mapping for the pathSpec for the default case
            httpConstraintMapping = new ConstraintMapping();
            httpConstraintMapping.setPathSpec(pathSpec);
            httpConstraintMapping.setConstraint(httpConstraint); 
            mappings.add(httpConstraintMapping);
        }
        

        //See Spec 13.4.1.2 p127
        List methodOmissions = new ArrayList();
        
        //make constraint mappings for this url for each of the HttpMethodConstraintElements
        Collection methodConstraintElements = securityElement.getHttpMethodConstraints();
        if (methodConstraintElements != null)
        {
            for (HttpMethodConstraintElement methodConstraintElement:methodConstraintElements)
            {
                //Make a Constraint that captures the  and  elements supplied for the HttpMethodConstraintElement
                Constraint methodConstraint = ConstraintSecurityHandler.createConstraint(name, methodConstraintElement);
                ConstraintMapping mapping = new ConstraintMapping();
                mapping.setConstraint(methodConstraint);
                mapping.setPathSpec(pathSpec);
                if (methodConstraintElement.getMethodName() != null)
                {
                    mapping.setMethod(methodConstraintElement.getMethodName());
                    //See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
                    methodOmissions.add(methodConstraintElement.getMethodName());
                }
                mappings.add(mapping);
            }
        }
        //See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
        //UNLESS the default constraint contains all default values. In that case, we won't add it. See Servlet Spec 3.1 pg 129
        if (methodOmissions.size() > 0  && httpConstraintMapping != null)
            httpConstraintMapping.setMethodOmissions(methodOmissions.toArray(new String[methodOmissions.size()]));
     
        return mappings;
    }
    
    


    /* ------------------------------------------------------------ */
    /**
     * @return Returns the constraintMappings.
     */
    @Override
    public List getConstraintMappings()
    {
        return _constraintMappings;
    }

    /* ------------------------------------------------------------ */
    @Override
    public Set getRoles()
    {
        return _roles;
    }

    /* ------------------------------------------------------------ */
    /**
     * Process the constraints following the combining rules in Servlet 3.0 EA
     * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
     *
     * @param constraintMappings
     *            The constraintMappings to set, from which the set of known roles
     *            is determined.
     */
    public void setConstraintMappings(List constraintMappings)
    {
        setConstraintMappings(constraintMappings,null);
    }

    /**
     * Process the constraints following the combining rules in Servlet 3.0 EA
     * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
     *
     * @param constraintMappings
     *            The constraintMappings to set as array, from which the set of known roles
     *            is determined.  Needed to retain API compatibility for 7.x
     */
    public void setConstraintMappings( ConstraintMapping[] constraintMappings )
    {
        setConstraintMappings( Arrays.asList(constraintMappings), null);
    }

    /* ------------------------------------------------------------ */
    /**
     * Process the constraints following the combining rules in Servlet 3.0 EA
     * spec section 13.7.1 Note that much of the logic is in the RoleInfo class.
     *
     * @param constraintMappings
     *            The constraintMappings to set.
     * @param roles The known roles (or null to determine them from the mappings)
     */
    @Override
    public void setConstraintMappings(List constraintMappings, Set roles)
    {
        _constraintMappings.clear();
        _constraintMappings.addAll(constraintMappings);

        if (roles==null)
        {
            roles = new HashSet<>();
            for (ConstraintMapping cm : constraintMappings)
            {
                String[] cmr = cm.getConstraint().getRoles();
                if (cmr!=null)
                {
                    for (String r : cmr)
                        if (!ALL_METHODS.equals(r))
                            roles.add(r);
                }
            }
        }
        setRoles(roles);
        
        if (isStarted())
        {
            for (ConstraintMapping mapping : _constraintMappings)
            {
                processConstraintMapping(mapping);
            }
        }
    }

    /* ------------------------------------------------------------ */
    /**
     * Set the known roles.
     * This may be overridden by a subsequent call to {@link #setConstraintMappings(ConstraintMapping[])} or
     * {@link #setConstraintMappings(List, Set)}.
     * @param roles The known roles (or null to determine them from the mappings)
     */
    public void setRoles(Set roles)
    {
        _roles.clear();
        _roles.addAll(roles);
    }



    /* ------------------------------------------------------------ */
    /**
     * @see org.eclipse.jetty.security.ConstraintAware#addConstraintMapping(org.eclipse.jetty.security.ConstraintMapping)
     */
    @Override
    public void addConstraintMapping(ConstraintMapping mapping)
    {
        _constraintMappings.add(mapping);
        if (mapping.getConstraint()!=null && mapping.getConstraint().getRoles()!=null)
        {
            //allow for lazy role naming: if a role is named in a security constraint, try and
            //add it to the list of declared roles (ie as if it was declared with a security-role
            for (String role :  mapping.getConstraint().getRoles())
            {
                if ("*".equals(role) || "**".equals(role))
                    continue;
                addRole(role);
            }
        }

        if (isStarted())
        {
            processConstraintMapping(mapping);
        }
    }

    /* ------------------------------------------------------------ */
    /**
     * @see org.eclipse.jetty.security.ConstraintAware#addRole(java.lang.String)
     */
    @Override
    public void addRole(String role)
    {
        //add to list of declared roles
        boolean modified = _roles.add(role);
        if (isStarted() && modified)
        {
            // Add the new role to currently defined any role role infos
            for (Map map : _constraintMap.values())
            {
                for (RoleInfo info : map.values())
                {
                    if (info.isAnyRole())
                        info.addRole(role);
                }
            }
        }
    }

    /* ------------------------------------------------------------ */
    /**
     * @see org.eclipse.jetty.security.SecurityHandler#doStart()
     */
    @Override
    protected void doStart() throws Exception
    {
        _constraintMap.clear();
        if (_constraintMappings!=null)
        {
            for (ConstraintMapping mapping : _constraintMappings)
            {
                processConstraintMapping(mapping);
            }
        }
        
        //Servlet Spec 3.1 pg 147 sec 13.8.4.2 log paths for which there are uncovered http methods
        checkPathsWithUncoveredHttpMethods();        
       
        super.doStart();
    }

    
    /* ------------------------------------------------------------ */
    @Override
    protected void doStop() throws Exception
    {
        super.doStop();
        _constraintMap.clear();
    }
    
    
    /* ------------------------------------------------------------ */
    /**
     * Create and combine the constraint with the existing processed
     * constraints.
     * 
     * @param mapping
     */
    protected void processConstraintMapping(ConstraintMapping mapping)
    {
        Map mappings = _constraintMap.get(mapping.getPathSpec());
        if (mappings == null)
        {
            mappings = new HashMap();
            _constraintMap.put(mapping.getPathSpec(),mappings);
        }
        RoleInfo allMethodsRoleInfo = mappings.get(ALL_METHODS);
        if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden())
            return;

        if (mapping.getMethodOmissions() != null && mapping.getMethodOmissions().length > 0)
        {
            processConstraintMappingWithMethodOmissions(mapping, mappings);
            return;
        }

        String httpMethod = mapping.getMethod();
        if (httpMethod==null)
            httpMethod=ALL_METHODS;
        RoleInfo roleInfo = mappings.get(httpMethod);
        if (roleInfo == null)
        {
            roleInfo = new RoleInfo();
            mappings.put(httpMethod,roleInfo);
            if (allMethodsRoleInfo != null)
            {
                roleInfo.combine(allMethodsRoleInfo);
            }
        }
        if (roleInfo.isForbidden())
            return;

        //add in info from the constraint
        configureRoleInfo(roleInfo, mapping);
        
        if (roleInfo.isForbidden())
        {
            if (httpMethod.equals(ALL_METHODS))
            {
                mappings.clear();
                mappings.put(ALL_METHODS,roleInfo);
            }
        }
    }

    /* ------------------------------------------------------------ */
    /** Constraints that name method omissions are dealt with differently.
     * We create an entry in the mappings with key "<method>.omission". This entry
     * is only ever combined with other omissions for the same method to produce a
     * consolidated RoleInfo. Then, when we wish to find the relevant constraints for
     *  a given Request (in prepareConstraintInfo()), we consult 3 types of entries in 
     * the mappings: an entry that names the method of the Request specifically, an
     * entry that names constraints that apply to all methods, entries of the form
     * <method>.omission, where the method of the Request is not named in the omission.
     * @param mapping
     * @param mappings
     */
    protected void processConstraintMappingWithMethodOmissions (ConstraintMapping mapping, Map mappings)
    {
        String[] omissions = mapping.getMethodOmissions();
        StringBuilder sb = new StringBuilder();
        for (int i=0; i 0)
                sb.append(".");
            sb.append(omissions[i]);
        }
        sb.append(OMISSION_SUFFIX);
        RoleInfo ri = new RoleInfo();
        mappings.put(sb.toString(), ri);
        configureRoleInfo(ri, mapping);
    }

    
    /* ------------------------------------------------------------ */
    /**
     * Initialize or update the RoleInfo from the constraint
     * @param ri
     * @param mapping
     */
    protected void configureRoleInfo (RoleInfo ri, ConstraintMapping mapping)
    { 
        Constraint constraint = mapping.getConstraint();
        boolean forbidden = constraint.isForbidden();
        ri.setForbidden(forbidden);
        
        //set up the data constraint (NOTE: must be done after setForbidden, as it nulls out the data constraint
        //which we need in order to do combining of omissions in prepareConstraintInfo
        UserDataConstraint userDataConstraint = UserDataConstraint.get(mapping.getConstraint().getDataConstraint());
        ri.setUserDataConstraint(userDataConstraint);

        //if forbidden, no point setting up roles
        if (!ri.isForbidden())
        {
            //add in the roles
            boolean checked = mapping.getConstraint().getAuthenticate();
            ri.setChecked(checked);

            if (ri.isChecked())
            {
                if (mapping.getConstraint().isAnyRole())
                {
                    // * means matches any defined role
                    for (String role : _roles)
                        ri.addRole(role);
                    ri.setAnyRole(true);
                }
                else if (mapping.getConstraint().isAnyAuth())
                {
                    //being authenticated is sufficient, not necessary to check roles
                    ri.setAnyAuth(true);
                }
                else
                {   
                    //user must be in one of the named roles
                    String[] newRoles = mapping.getConstraint().getRoles();
                     for (String role : newRoles)
                     {
                         //check role has been defined
                         if (!_roles.contains(role))
                             throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
                        ri.addRole(role);
                     }
                 }
             }
         }
     }

   
    /* ------------------------------------------------------------ */
    /** 
     * Find constraints that apply to the given path.
     * In order to do this, we consult 3 different types of information stored in the mappings for each path - each mapping
     * represents a merged set of user data constraints, roles etc -:
     * 
    *
  1. A mapping of an exact method name
  2. *
  3. A mapping with key * that matches every method name
  4. *
  5. Mappings with keys of the form "<method>.<method>.<method>.omission" that indicates it will match every method name EXCEPT those given
  6. *
* * @see org.eclipse.jetty.security.SecurityHandler#prepareConstraintInfo(java.lang.String, org.eclipse.jetty.server.Request) */ @Override protected RoleInfo prepareConstraintInfo(String pathInContext, Request request) { Map mappings = _constraintMap.match(pathInContext); if (mappings != null) { String httpMethod = request.getMethod(); RoleInfo roleInfo = mappings.get(httpMethod); if (roleInfo == null) { //No specific http-method names matched List applicableConstraints = new ArrayList(); //Get info for constraint that matches all methods if it exists RoleInfo all = mappings.get(ALL_METHODS); if (all != null) applicableConstraints.add(all); //Get info for constraints that name method omissions where target method name is not omitted //(ie matches because target method is not omitted, hence considered covered by the constraint) for (Entry entry: mappings.entrySet()) { if (entry.getKey() != null && entry.getKey().endsWith(OMISSION_SUFFIX) && ! entry.getKey().contains(httpMethod)) applicableConstraints.add(entry.getValue()); } if (applicableConstraints.size() == 0 && isDenyUncoveredHttpMethods()) { roleInfo = new RoleInfo(); roleInfo.setForbidden(true); } else if (applicableConstraints.size() == 1) roleInfo = applicableConstraints.get(0); else { roleInfo = new RoleInfo(); roleInfo.setUserDataConstraint(UserDataConstraint.None); for (RoleInfo r:applicableConstraints) roleInfo.combine(r); } } return roleInfo; } return null; } @Override protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response, RoleInfo roleInfo) throws IOException { if (roleInfo == null) return true; if (roleInfo.isForbidden()) return false; UserDataConstraint dataConstraint = roleInfo.getUserDataConstraint(); if (dataConstraint == null || dataConstraint == UserDataConstraint.None) return true; HttpConfiguration httpConfig = HttpChannel.getCurrentHttpChannel().getHttpConfiguration(); if (dataConstraint == UserDataConstraint.Confidential || dataConstraint == UserDataConstraint.Integral) { if (request.isSecure()) return true; if (httpConfig.getSecurePort() > 0) { String scheme = httpConfig.getSecureScheme(); int port = httpConfig.getSecurePort(); String url = URIUtil.newURI(scheme, request.getServerName(), port,request.getRequestURI(),request.getQueryString()); response.setContentLength(0); response.sendRedirect(url); } else response.sendError(HttpStatus.FORBIDDEN_403,"!Secure"); request.setHandled(true); return false; } else { throw new IllegalArgumentException("Invalid dataConstraint value: " + dataConstraint); } } @Override protected boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo) { return constraintInfo != null && ((RoleInfo)constraintInfo).isChecked(); } /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.security.SecurityHandler#checkWebResourcePermissions(java.lang.String, org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object, org.eclipse.jetty.server.UserIdentity) */ @Override protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo, UserIdentity userIdentity) throws IOException { if (constraintInfo == null) { return true; } RoleInfo roleInfo = (RoleInfo)constraintInfo; if (!roleInfo.isChecked()) { return true; } //handle ** role constraint if (roleInfo.isAnyAuth() && request.getUserPrincipal() != null) { return true; } //check if user is any of the allowed roles boolean isUserInRole = false; for (String role : roleInfo.getRoles()) { if (userIdentity.isUserInRole(role, null)) { isUserInRole = true; break; } } //handle * role constraint if (roleInfo.isAnyRole() && request.getUserPrincipal() != null && isUserInRole) { return true; } //normal role check if (isUserInRole) { return true; } return false; } /* ------------------------------------------------------------ */ @Override public void dump(Appendable out,String indent) throws IOException { // TODO these should all be beans dumpBeans(out,indent, Collections.singleton(getLoginService()), Collections.singleton(getIdentityService()), Collections.singleton(getAuthenticator()), Collections.singleton(_roles), _constraintMap.entrySet()); } /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.security.ConstraintAware#setDenyUncoveredHttpMethods(boolean) */ @Override public void setDenyUncoveredHttpMethods(boolean deny) { _denyUncoveredMethods = deny; } /* ------------------------------------------------------------ */ @Override public boolean isDenyUncoveredHttpMethods() { return _denyUncoveredMethods; } /* ------------------------------------------------------------ */ /** * Servlet spec 3.1 pg. 147. */ @Override public boolean checkPathsWithUncoveredHttpMethods() { Set paths = getPathsWithUncoveredHttpMethods(); if (paths != null && !paths.isEmpty()) { for (String p:paths) LOG.warn("{} has uncovered http methods for path: {}",ContextHandler.getCurrentContext(), p); if (LOG.isDebugEnabled()) LOG.debug(new Throwable()); return true; } return false; } /* ------------------------------------------------------------ */ /** * Servlet spec 3.1 pg. 147. * The container must check all the combined security constraint * information and log any methods that are not protected and the * urls at which they are not protected * * @return list of paths for which there are uncovered methods */ public Set getPathsWithUncoveredHttpMethods () { //if automatically denying uncovered methods, there are no uncovered methods if (_denyUncoveredMethods) return Collections.emptySet(); Set uncoveredPaths = new HashSet(); for (String path:_constraintMap.keySet()) { Map methodMappings = _constraintMap.get(path); //Each key is either: // : an exact method name // : * which means that the constraint applies to every method // : a name of the form ...omission, which means it applies to every method EXCEPT those named if (methodMappings.get(ALL_METHODS) != null) continue; //can't be any uncovered methods for this url path boolean hasOmissions = omissionsExist(path, methodMappings); for (String method:methodMappings.keySet()) { if (method.endsWith(OMISSION_SUFFIX)) { Set omittedMethods = getOmittedMethods(method); for (String m:omittedMethods) { if (!methodMappings.containsKey(m)) uncoveredPaths.add(path); } } else { //an exact method name if (!hasOmissions) //a http-method does not have http-method-omission to cover the other method names uncoveredPaths.add(path); } } } return uncoveredPaths; } /* ------------------------------------------------------------ */ /** * Check if any http method omissions exist in the list of method * to auth info mappings. * * @param path * @param methodMappings * @return */ protected boolean omissionsExist (String path, Map methodMappings) { if (methodMappings == null) return false; boolean hasOmissions = false; for (String m:methodMappings.keySet()) { if (m.endsWith(OMISSION_SUFFIX)) hasOmissions = true; } return hasOmissions; } /* ------------------------------------------------------------ */ /** * Given a string of the form <method>.<method>.omission * split out the individual method names. * * @param omission * @return */ protected Set getOmittedMethods (String omission) { if (omission == null || !omission.endsWith(OMISSION_SUFFIX)) return Collections.emptySet(); String[] strings = omission.split("\\."); Set methods = new HashSet(); for (int i=0;i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy