Package org.apache.geronimo.web.security

Source Code of org.apache.geronimo.web.security.SpecSecurityBuilder$RecordingPolicyConfiguration

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.geronimo.web.security;

import java.net.URL;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.security.jacc.PolicyConfiguration;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebResourcePermission;
import javax.security.jacc.WebRoleRefPermission;
import javax.security.jacc.WebUserDataPermission;
import javax.servlet.HttpMethodConstraintElement;
import javax.servlet.Servlet;
import javax.servlet.ServletSecurityElement;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.HttpMethodConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;

import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
import org.apache.geronimo.kernel.util.JarUtils;
import org.apache.geronimo.schema.SchemaConversionUtils;
import org.apache.geronimo.security.jacc.ComponentPermissions;
import org.apache.geronimo.xbeans.javaee6.AuthConstraintType;
import org.apache.geronimo.xbeans.javaee6.RoleNameType;
import org.apache.geronimo.xbeans.javaee6.SecurityConstraintType;
import org.apache.geronimo.xbeans.javaee6.SecurityRoleRefType;
import org.apache.geronimo.xbeans.javaee6.SecurityRoleType;
import org.apache.geronimo.xbeans.javaee6.ServletMappingType;
import org.apache.geronimo.xbeans.javaee6.ServletType;
import org.apache.geronimo.xbeans.javaee6.UrlPatternType;
import org.apache.geronimo.xbeans.javaee6.WebAppDocument;
import org.apache.geronimo.xbeans.javaee6.WebAppType;
import org.apache.geronimo.xbeans.javaee6.WebResourceCollectionType;
import org.apache.xbean.osgi.bundle.util.BundleUtils;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.osgi.framework.Bundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @version $Rev: 940477 $ $Date: 2010-05-03 10:54:42 -0400 (Mon, 03 May 2010) $
*/
public class SpecSecurityBuilder {

    private static final Logger logger = LoggerFactory.getLogger(SpecSecurityBuilder.class);

    private final Set<String> securityRoles = new HashSet<String>();

    private final Map<String, URLPattern> uncheckedPatterns = new HashMap<String, URLPattern>();

    private final Map<UncheckedItem, HTTPMethods> uncheckedResourcePatterns = new HashMap<UncheckedItem, HTTPMethods>();

    private final Map<UncheckedItem, HTTPMethods> uncheckedUserPatterns = new HashMap<UncheckedItem, HTTPMethods>();

    private final Map<String, URLPattern> excludedPatterns = new HashMap<String, URLPattern>();

    private final Map<String, URLPattern> rolesPatterns = new HashMap<String, URLPattern>();

    private final Set<URLPattern> allSet = new HashSet<URLPattern>();

    private final Map<String, URLPattern> allMap = new HashMap<String, URLPattern>(); //uncheckedPatterns union excludedPatterns union rolesPatterns.

    private final RecordingPolicyConfiguration policyConfiguration = new RecordingPolicyConfiguration(true);

    /**
     * webApp is xmlbean object of the initial web.xml ( May be merged all the web-fragment.xml files)
     */
    private WebAppType initialWebApp;

    private Bundle bundle;

    private boolean annotationScanRequired;

    private Set<String> urlPatternsConfiguredInDeploymentPlans = new HashSet<String>();

    /**
     *   dynamicSecurityWebApp contains all the servlet security constraints configured by ServletRegistration.Dynamic interface
     */
    private WebAppType dynamicSecurityWebApp;

    /**
     * annotationSecurityWebApp contains all the servlet security constraints configured by ServletConstraint annotation
     */
    private WebAppType annotationSecurityWebApp;

    public SpecSecurityBuilder(WebAppType webApp) {
        this(webApp, null, false);
    }

    public SpecSecurityBuilder(WebAppType initialWebApp, Bundle bundle, boolean annotationScanRequired) {
        this.initialWebApp = initialWebApp;
        if (annotationScanRequired && bundle == null) {
            throw new IllegalArgumentException("Bundle parameter could not be null while annotation scanning is required");
        }
        this.bundle = bundle;
        this.annotationScanRequired = annotationScanRequired;
        initialize();
    }

    public SpecSecurityBuilder(Bundle bundle, boolean annotationScanRequired) {
        this.bundle = bundle;
        this.annotationScanRequired = annotationScanRequired;
        URL specDDUrl = BundleUtils.getEntry(bundle, "WEB-INF/web.xml");
        if (specDDUrl == null) {
            initialWebApp = WebAppType.Factory.newInstance();
        } else {
            try {
                String specDD = JarUtils.readAll(specDDUrl);
                XmlObject parsed = XmlBeansUtil.parse(specDD);
                WebAppDocument webAppDoc = SchemaConversionUtils.convertToServletSchema(parsed);
                initialWebApp = webAppDoc.getWebApp();
            } catch (XmlException e) {
                throw new IllegalArgumentException("Error parsing web.xml for " + bundle.getSymbolicName(), e);
            } catch (Exception e) {
                throw new IllegalArgumentException("Error reading web.xml for " + bundle.getSymbolicName(), e);
            }
        }
        initialize();
    }

    public SpecSecurityBuilder(Bundle bundle, String deploymentDescriptor, boolean annotationScanRequired) {
        this.bundle = bundle;
        this.annotationScanRequired = annotationScanRequired;
        if (deploymentDescriptor == null || deploymentDescriptor.length() == 0) {
            initialWebApp = WebAppType.Factory.newInstance();
        } else {
            try {
                XmlObject parsed = XmlBeansUtil.parse(deploymentDescriptor);
                WebAppDocument webAppDoc = SchemaConversionUtils.convertToServletSchema(parsed);
                initialWebApp = webAppDoc.getWebApp();
            } catch (XmlException e) {
                throw new IllegalArgumentException("Error parsing web.xml for " + bundle.getSymbolicName(), e);
            } catch (Exception e) {
                throw new IllegalArgumentException("Error reading web.xml for " + bundle.getSymbolicName(), e);
            }
        }
        initialize();
    }

    public void declareRoles(String... roleNames) {
        //Let's go ahead to directly add the roles to the securityRoles set. The set will be used in the collectRoleNames method.
        for (String roleName : roleNames) {
            if (roleName == null || roleName.trim().length() == 0) {
                throw new IllegalArgumentException("RoleName of null value or empty string is not allowed in declareRoles method");
            }
            securityRoles.add(roleName.trim());
        }
    }

    public Set<String> setServletSecurity(ServletSecurityElement constraint, Collection<String> urlPatterns) {
        if (dynamicSecurityWebApp == null) {
            dynamicSecurityWebApp = WebAppType.Factory.newInstance();
        }
        Set<String> uneffectedUrlPatterns = new HashSet<String>();
        for (String urlPattern : urlPatterns) {
            if (urlPatternsConfiguredInDeploymentPlans.contains(urlPattern)) {
                uneffectedUrlPatterns.add(urlPattern);
            }
        }
        Collection<String> effectedUrlPatterns = null;
        if (uneffectedUrlPatterns.size() == 0) {
            effectedUrlPatterns = urlPatterns;
        } else {
            effectedUrlPatterns = new HashSet<String>();
            effectedUrlPatterns.addAll(urlPatterns);
            effectedUrlPatterns.removeAll(uneffectedUrlPatterns);
        }
        //Update SecurityConstraint configured by ServletSecurity annotations if required
        if (annotationSecurityWebApp != null) {
            overrideSecurityConstraints(annotationSecurityWebApp, effectedUrlPatterns);
        }
        //Update SecurityConstraint configured by previous setServletSecurity invocations
        overrideSecurityConstraints(dynamicSecurityWebApp, effectedUrlPatterns);
        //Update Role List
        //Roles that are implicitly declared as a result of their use within the setServletSecurity or setRunAsRole methods of the ServletRegistration interface
        //need not be declared.
        //Set SecurityConstraint
        if (constraint.getHttpMethodConstraints().size() > 0) {
            for (HttpMethodConstraintElement httpMethodConstraint : constraint.getHttpMethodConstraints()) {
                //Generate a security-constraint for each HttpMethodConstraint
                addNewHTTPMethodSecurityConstraint(dynamicSecurityWebApp, httpMethodConstraint.getRolesAllowed(), httpMethodConstraint.getTransportGuarantee(), httpMethodConstraint
                        .getEmptyRoleSemantic(), httpMethodConstraint.getMethodName(), effectedUrlPatterns);
               declareRoles(httpMethodConstraint.getRolesAllowed());
            }
        }
        addNewHTTPSecurityConstraint(dynamicSecurityWebApp, constraint.getRolesAllowed(), constraint.getTransportGuarantee(), constraint.getEmptyRoleSemantic(), constraint.getMethodNames()
                .toArray(new String[0]), effectedUrlPatterns);
        declareRoles(constraint.getRolesAllowed());
        return uneffectedUrlPatterns;
    }

    private void overrideSecurityConstraints(WebAppType webApp, Collection<String> urlPatterns) {
        for (SecurityConstraintType securityConstraint : webApp.getSecurityConstraintArray()) {
            int iCurrentWebResourceCollectionIndex = 0;
            for (WebResourceCollectionType webResourceCollection : securityConstraint.getWebResourceCollectionArray()) {
                Set<String> validateAnnotationUrlPatterns = new HashSet<String>();
                for (UrlPatternType urlPattern : webResourceCollection.getUrlPatternArray()) {
                    if (!urlPatterns.contains(urlPattern.getStringValue())) {
                        validateAnnotationUrlPatterns.add(urlPattern.getStringValue());
                    }
                }
                if (validateAnnotationUrlPatterns.size() == 0) {
                    securityConstraint.removeWebResourceCollection(iCurrentWebResourceCollectionIndex);
                    continue;
                } else if (validateAnnotationUrlPatterns.size() < webResourceCollection.getUrlPatternArray().length) {
                    for (int i = 0, iLoopSize = webResourceCollection.getUrlPatternArray().length; i < iLoopSize; i++) {
                        webResourceCollection.removeUrlPattern(0);
                    }
                    for (String validateAnnotationUrlPattern : validateAnnotationUrlPatterns) {
                        webResourceCollection.addNewUrlPattern().setStringValue(validateAnnotationUrlPattern);
                    }
                }
                iCurrentWebResourceCollectionIndex++;
            }
        }
    }

    public ComponentPermissions buildSpecSecurityConfig() {
        if (dynamicSecurityWebApp != null) {
            for (SecurityConstraintType securityConstraint : dynamicSecurityWebApp.getSecurityConstraintArray()) {
                initialWebApp.addNewSecurityConstraint().set(securityConstraint);
            }
        }
        if (annotationSecurityWebApp != null) {
            for (SecurityConstraintType securityConstraint : annotationSecurityWebApp.getSecurityConstraintArray()) {
                initialWebApp.addNewSecurityConstraint().set(securityConstraint);
            }
        }
        collectRoleNames(initialWebApp.getSecurityRoleArray());
        try {
            for (ServletType servletType : initialWebApp.getServletArray()) {
                processRoleRefPermissions(servletType);
            }
            //add the role-ref permissions for unmapped jsps
            addUnmappedJSPPermissions();
            analyzeSecurityConstraints(initialWebApp.getSecurityConstraintArray());
            removeExcludedDups();
            return buildComponentPermissions();
        } catch (PolicyContextException e) {
            throw new IllegalStateException("Should not happen", e);
        }
    }

    private void analyzeSecurityConstraints(SecurityConstraintType[] securityConstraintArray) {
        for (SecurityConstraintType securityConstraintType : securityConstraintArray) {
            Map<String, URLPattern> currentPatterns;
            if (securityConstraintType.isSetAuthConstraint()) {
                if (securityConstraintType.getAuthConstraint().getRoleNameArray().length == 0) {
                    currentPatterns = excludedPatterns;
                } else {
                    currentPatterns = rolesPatterns;
                }
            } else {
                currentPatterns = uncheckedPatterns;
            }
            String transport = "";
            if (securityConstraintType.isSetUserDataConstraint()) {
                transport = securityConstraintType.getUserDataConstraint().getTransportGuarantee().getStringValue().trim().toUpperCase();
            }
            WebResourceCollectionType[] webResourceCollectionTypeArray = securityConstraintType.getWebResourceCollectionArray();
            for (WebResourceCollectionType webResourceCollectionType : webResourceCollectionTypeArray) {
                //Calculate HTTP methods list
                Set<String> httpMethods = new HashSet<String>();
                //While using HTTP omission methods and empty methods (which means all methods) as the configurations, isExcluded value is true
                //While using HTTP methods as the configurations, isExcluded value is false
                boolean isExcludedList = true;
                if (webResourceCollectionType.getHttpMethodArray().length > 0) {
                    isExcludedList = false;
                    for (String httpMethod : webResourceCollectionType.getHttpMethodArray()) {
                        if (httpMethod != null) {
                            httpMethods.add(httpMethod.trim());
                        }
                    }
                } else if (webResourceCollectionType.getHttpMethodOmissionArray().length > 0) {
                    for (String httpMethodOmission : webResourceCollectionType.getHttpMethodOmissionArray()) {
                        if (httpMethodOmission != null) {
                            httpMethods.add(httpMethodOmission.trim());
                        }
                    }
                }
                for (UrlPatternType urlPatternType : webResourceCollectionType.getUrlPatternArray()) {
                    String url = urlPatternType.getStringValue().trim();
                    URLPattern pattern = currentPatterns.get(url);
                    if (pattern == null) {
                        pattern = new URLPattern(url, httpMethods, isExcludedList);
                        currentPatterns.put(url, pattern);
                    } else {
                        pattern.addMethods(httpMethods, isExcludedList);
                    }
                    URLPattern allPattern = allMap.get(url);
                    if (allPattern == null) {
                        allPattern = new URLPattern(url, httpMethods, isExcludedList);
                        allSet.add(allPattern);
                        allMap.put(url, allPattern);
                    } else {
                        allPattern.addMethods(httpMethods, isExcludedList);
                    }
                    if (currentPatterns == rolesPatterns) {
                        RoleNameType[] roleNameTypeArray = securityConstraintType.getAuthConstraint().getRoleNameArray();
                        for (RoleNameType roleNameType : roleNameTypeArray) {
                            String role = roleNameType.getStringValue().trim();
                            if (role.equals("*")) {
                                pattern.addAllRoles(securityRoles);
                            } else {
                                pattern.addRole(role);
                            }
                        }
                    }
                    pattern.setTransport(transport);
                }
            }
        }
    }

    private void removeExcludedDups() {
        for (Map.Entry<String, URLPattern> excluded : excludedPatterns.entrySet()) {
            String url = excluded.getKey();
            URLPattern pattern = excluded.getValue();
            removeExcluded(url, pattern, uncheckedPatterns);
            removeExcluded(url, pattern, rolesPatterns);
        }
    }

    private void removeExcluded(String url, URLPattern pattern, Map<String, URLPattern> patterns) {
        URLPattern testPattern = patterns.get(url);
        if (testPattern != null) {
            if (!testPattern.removeMethods(pattern)) {
                patterns.remove(url);
            }
        }
    }

    private ComponentPermissions buildComponentPermissions() throws PolicyContextException {
        for (URLPattern pattern : excludedPatterns.values()) {
            String name = pattern.getQualifiedPattern(allSet);
            String actions = pattern.getMethods();
            policyConfiguration.addToExcludedPolicy(new WebResourcePermission(name, actions));
            policyConfiguration.addToExcludedPolicy(new WebUserDataPermission(name, actions));
        }
        for (URLPattern pattern : rolesPatterns.values()) {
            String name = pattern.getQualifiedPattern(allSet);
            String actions = pattern.getMethods();
            WebResourcePermission permission = new WebResourcePermission(name, actions);
            for (String roleName : pattern.getRoles()) {
                policyConfiguration.addToRole(roleName, permission);
            }
            HTTPMethods methods = pattern.getHTTPMethods();
            int transportType = pattern.getTransport();
            addOrUpdatePattern(uncheckedUserPatterns, name, methods, transportType);
        }
        for (URLPattern pattern : uncheckedPatterns.values()) {
            String name = pattern.getQualifiedPattern(allSet);
            HTTPMethods methods = pattern.getHTTPMethods();
            addOrUpdatePattern(uncheckedResourcePatterns, name, methods, URLPattern.NA);
            int transportType = pattern.getTransport();
            addOrUpdatePattern(uncheckedUserPatterns, name, methods, transportType);
        }
        /**
         * A <code>WebResourcePermission</code> and a <code>WebUserDataPermission</code> must be instantiated for
         * each <tt>url-pattern</tt> in the deployment descriptor and the default pattern "/", that is not combined
         * by the <tt>web-resource-collection</tt> elements of the deployment descriptor with ever HTTP method
         * value.  The permission objects must be contructed using the qualified pattern as their name and with
         * actions defined by the subset of the HTTP methods that do not occur in combination with the pattern.
         * The resulting permissions that must be added to the unchecked policy statements by calling the
         * <code>addToUncheckedPolcy</code> method on the <code>PolicyConfiguration</code> object.
         */
        for (URLPattern pattern : allSet) {
            String name = pattern.getQualifiedPattern(allSet);
            HTTPMethods methods = pattern.getComplementedHTTPMethods();
            if (methods.isNone()) {
                continue;
            }
            addOrUpdatePattern(uncheckedResourcePatterns, name, methods, URLPattern.NA);
            addOrUpdatePattern(uncheckedUserPatterns, name, methods, URLPattern.NA);
        }
        if (!allMap.containsKey("/")) {
            URLPattern pattern = new URLPattern("/", Collections.EMPTY_SET, false);
            String name = pattern.getQualifiedPattern(allSet);
            HTTPMethods methods = pattern.getComplementedHTTPMethods();
            addOrUpdatePattern(uncheckedResourcePatterns, name, methods, URLPattern.NA);
            addOrUpdatePattern(uncheckedUserPatterns, name, methods, URLPattern.NA);
        }
        //Create the uncheckedPermissions for WebResourcePermissions
        for (UncheckedItem item : uncheckedResourcePatterns.keySet()) {
            HTTPMethods methods = uncheckedResourcePatterns.get(item);
            String actions = URLPattern.getMethodsWithTransport(methods, item.getTransportType());
            policyConfiguration.addToUncheckedPolicy(new WebResourcePermission(item.getName(), actions));
        }
        //Create the uncheckedPermissions for WebUserDataPermissions
        for (UncheckedItem item : uncheckedUserPatterns.keySet()) {
            HTTPMethods methods = uncheckedUserPatterns.get(item);
            String actions = URLPattern.getMethodsWithTransport(methods, item.getTransportType());
            policyConfiguration.addToUncheckedPolicy(new WebUserDataPermission(item.getName(), actions));
        }
        return policyConfiguration.getComponentPermissions();
    }

    private void addOrUpdatePattern(Map<UncheckedItem, HTTPMethods> patternMap, String name, HTTPMethods actions, int transportType) {
        UncheckedItem item = new UncheckedItem(name, transportType);
        HTTPMethods existingActions = patternMap.get(item);
        if (existingActions != null) {
            patternMap.put(item, existingActions.add(actions));
        } else {
            patternMap.put(item, new HTTPMethods(actions, false));
        }
    }

    protected void processRoleRefPermissions(ServletType servletType) throws PolicyContextException {
        String servletName = servletType.getServletName().getStringValue().trim();
        //WebRoleRefPermissions
        SecurityRoleRefType[] securityRoleRefTypeArray = servletType.getSecurityRoleRefArray();
        Set<String> unmappedRoles = new HashSet<String>(securityRoles);
        for (SecurityRoleRefType securityRoleRefType : securityRoleRefTypeArray) {
            String roleName = securityRoleRefType.getRoleName().getStringValue().trim();
            String roleLink = securityRoleRefType.getRoleLink().getStringValue().trim();
            //jacc 3.1.3.2
            /*   The name of the WebRoleRefPermission must be the servlet-name in whose
            * context the security-role-ref is defined. The actions of the  WebRoleRefPermission
            * must be the value of the role-name (that is the  reference), appearing in the security-role-ref.
            * The deployment tools must  call the addToRole method on the PolicyConfiguration object to add the
            * WebRoleRefPermission object resulting from the translation to the role
            * identified in the role-link appearing in the security-role-ref.
            */
            policyConfiguration.addToRole(roleLink, new WebRoleRefPermission(servletName, roleName));
            unmappedRoles.remove(roleName);
        }
        for (String roleName : unmappedRoles) {
            policyConfiguration.addToRole(roleName, new WebRoleRefPermission(servletName, roleName));
        }
    }

    protected void addUnmappedJSPPermissions() throws PolicyContextException {
        for (String roleName : securityRoles) {
            policyConfiguration.addToRole(roleName, new WebRoleRefPermission("", roleName));
        }
    }

    protected void collectRoleNames(SecurityRoleType[] securityRoles) {
        for (SecurityRoleType securityRole : securityRoles) {
            this.securityRoles.add(securityRole.getRoleName().getStringValue().trim());
        }
    }

    /**
     * 1. Scan ServletConstraint annotations to build a map for conflict checking
     * 2. Build a url-pattern
     */
    private void initialize() {
        // Initialize urlPatternsConfiguredInDeploymentPlans map, which contains all the url patterns configured in portable deployment plan
        for (SecurityConstraintType secuirtyConstrait : initialWebApp.getSecurityConstraintArray()) {
            for (WebResourceCollectionType webResourceCollection : secuirtyConstrait.getWebResourceCollectionArray()) {
                for (UrlPatternType urlPattern : webResourceCollection.getUrlPatternArray()) {
                    urlPatternsConfiguredInDeploymentPlans.add(urlPattern.getStringValue());
                }
            }
        }
        //Scan ServletConstraint annotations if required
        if (annotationScanRequired) {
            annotationSecurityWebApp = WebAppType.Factory.newInstance();
            scanServletConstraintAnnotations();
        }
    }

    private void scanServletConstraintAnnotations() {
        try {
            Map<String, Set<String>> servletClassNameUrlPatternsMap = genetateServletClassUrlPatternsMap();
            for (ServletType servlet : initialWebApp.getServletArray()) {
                if (servlet.getServletClass() == null || servlet.getServletClass().getStringValue().isEmpty()) {
                    continue;
                }
                String servletClassName = servlet.getServletClass().getStringValue();
                Class<?> cls = bundle.loadClass(servletClassName);
                if (!Servlet.class.isAssignableFrom(cls)) {
                    continue;
                }
                ServletSecurity servletSecurity = cls.getAnnotation(ServletSecurity.class);
                if (servletSecurity == null) {
                    continue;
                }
                Set<String> urlPatterns = servletClassNameUrlPatternsMap.get(servletClassName);
                if (urlPatterns == null || urlPatterns.isEmpty()) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("No url pattern for the servlet class " + servletClassName + " is found in the deployment plan, SecurityConstraint annotation is ignored");
                    }
                    continue;
                }
                HttpConstraint httpConstraint = servletSecurity.value();
                if (servletSecurity.httpMethodConstraints().length > 0) {
                    String[] omissionMethods = new String[servletSecurity.httpMethodConstraints().length];
                    int iIndex = 0;
                    for (HttpMethodConstraint httpMethodConstraint : servletSecurity.httpMethodConstraints()) {
                        //Generate a security-constraint for each HttpMethodConstraint
                        String httpMethod = httpMethodConstraint.value().trim();
                        omissionMethods[iIndex++] = httpMethod;
                        addNewHTTPMethodSecurityConstraint(annotationSecurityWebApp, httpMethodConstraint.rolesAllowed(), httpMethodConstraint.transportGuarantee(), httpMethodConstraint
                                .emptyRoleSemantic(), httpMethod, urlPatterns);
                    }
                    addNewHTTPSecurityConstraint(annotationSecurityWebApp, httpConstraint.rolesAllowed(), httpConstraint.transportGuarantee(), httpConstraint.value(), omissionMethods, urlPatterns);
                } else {
                    addNewHTTPSecurityConstraint(annotationSecurityWebApp, httpConstraint.rolesAllowed(), httpConstraint.transportGuarantee(), httpConstraint.value(), new String[] {}, urlPatterns);
                }
            }
        } catch (ClassNotFoundException e) {
            //Should never occur, as webservice builder  have already checked it.
            logger.error("Fail to load class", e);
        }
    }

    /**
     * Create Security Constraint based on the arguments
     * @param webApp
     * @param rolesAllowed
     * @param transportGuarantee
     * @param emptyRoleSemantic
     * @return null when emptyRoleSemantic=PERMIT AND rolesAllowed={} AND transportGuarantee=NONE
     */
    private SecurityConstraintType addNewSecurityConstraint(WebAppType webApp, String[] rolesAllowed, TransportGuarantee transportGuarantee, ServletSecurity.EmptyRoleSemantic emptyRoleSemantic) {
        //IF emptyRoleSemantic=PERMIT AND rolesAllowed={} AND transportGuarantee=NONE then
        //  No Constraint
        //END IF
        if (rolesAllowed.length > 0 || transportGuarantee.equals(TransportGuarantee.CONFIDENTIAL) || emptyRoleSemantic.equals(ServletSecurity.EmptyRoleSemantic.DENY)) {
            SecurityConstraintType securityConstraint = webApp.addNewSecurityConstraint();
            if (transportGuarantee.equals(TransportGuarantee.CONFIDENTIAL)) {
                securityConstraint.addNewUserDataConstraint().addNewTransportGuarantee().setStringValue(TransportGuarantee.CONFIDENTIAL.name());
            }
            if (emptyRoleSemantic.equals(ServletSecurity.EmptyRoleSemantic.DENY)) {
                securityConstraint.addNewAuthConstraint();
            } else {
                AuthConstraintType authConstraint = securityConstraint.addNewAuthConstraint();
                for (String roleAllowed : rolesAllowed) {
                    authConstraint.addNewRoleName().setStringValue(roleAllowed);
                }
            }
            return securityConstraint;
        }
        return null;
    }

    private SecurityConstraintType addNewHTTPSecurityConstraint(WebAppType webApp, String[] rolesAllowed, TransportGuarantee transportGuarantee, ServletSecurity.EmptyRoleSemantic emptyRoleSemantic,
            String[] omissionMethods, Collection<String> urlPatterns) {
        SecurityConstraintType securityConstraint = addNewSecurityConstraint(webApp, rolesAllowed, transportGuarantee, emptyRoleSemantic);
        if (omissionMethods.length > 0 || securityConstraint != null) {
            if (securityConstraint == null) {
                securityConstraint = webApp.addNewSecurityConstraint();
            }
            WebResourceCollectionType webResourceCollection = securityConstraint.getWebResourceCollectionArray().length == 0 ? securityConstraint.addNewWebResourceCollection() : securityConstraint
                    .getWebResourceCollectionArray(0);
            for (String omissionMethod : omissionMethods) {
                webResourceCollection.addNewHttpMethodOmission().setStringValue(omissionMethod);
            }
            for (String urlPattern : urlPatterns) {
                webResourceCollection.addNewUrlPattern().setStringValue(urlPattern);
            }
        }
        return securityConstraint;
    }

    private SecurityConstraintType addNewHTTPMethodSecurityConstraint(WebAppType webApp, String[] rolesAllowed, TransportGuarantee transportGuarantee,
            ServletSecurity.EmptyRoleSemantic emptyRoleSemantic, String httpMethod, Collection<String> urlPatterns) {
        SecurityConstraintType securityConstraint = addNewSecurityConstraint(webApp, rolesAllowed, transportGuarantee, emptyRoleSemantic);
        if (securityConstraint == null) {
            securityConstraint = webApp.addNewSecurityConstraint();
        }
        WebResourceCollectionType webResourceCollection = securityConstraint.getWebResourceCollectionArray().length == 0 ? securityConstraint.addNewWebResourceCollection() : securityConstraint
                .getWebResourceCollectionArray(0);
        for (String urlPattern : urlPatterns) {
            webResourceCollection.addNewUrlPattern().setStringValue(urlPattern);
        }
        webResourceCollection.addNewHttpMethod().setStringValue(httpMethod);
        return securityConstraint;
    }

    /**
     * The return map contains the servlet class -> url patterns pairs, which are not configured in the security-constraint elements in the deployment plan.
     * Because the security-constraint configurations in the deployment plan have the highest priority, those constraints configured by annotations should not override them
     * @return
     */
    private Map<String, Set<String>> genetateServletClassUrlPatternsMap() {
        Map<String, Set<String>> servletNameUrlPatternsMap = new HashMap<String, Set<String>>();
        for (ServletMappingType servletMapping : initialWebApp.getServletMappingArray()) {
            String servletName = servletMapping.getServletName().getStringValue();
            Set<String> urlPatterns = servletNameUrlPatternsMap.get(servletName);
            if (urlPatterns == null) {
                urlPatterns = new HashSet<String>();
                servletNameUrlPatternsMap.put(servletName, urlPatterns);
            }
            for (UrlPatternType urlPattern : servletMapping.getUrlPatternArray()) {
                if (!urlPatternsConfiguredInDeploymentPlans.contains(urlPattern.getStringValue())) {
                    urlPatterns.add(urlPattern.getStringValue());
                }
            }
        }
        Map<String, Set<String>> servletClassUrlPatternsMap = new HashMap<String, Set<String>>();
        for (ServletType servlet : initialWebApp.getServletArray()) {
            if (servlet.getServletClass() == null || servlet.getServletClass().getStringValue().isEmpty()) {
                continue;
            }
            String servletClassName = servlet.getServletClass().getStringValue();
            Set<String> urlPatterns = servletClassUrlPatternsMap.get(servlet.getServletClass().getStringValue());
            if (urlPatterns == null) {
                urlPatterns = new HashSet<String>();
                servletClassUrlPatternsMap.put(servletClassName, urlPatterns);
            }
            Set<String> servletMappingUrlPatterns = servletNameUrlPatternsMap.get(servlet.getServletName().getStringValue());
            if (servletMappingUrlPatterns != null) {
                urlPatterns.addAll(servletMappingUrlPatterns);
            }
        }
        return servletClassUrlPatternsMap;
    }

    public void clear() {
        securityRoles.clear();
        uncheckedPatterns.clear();
        uncheckedResourcePatterns.clear();
        uncheckedUserPatterns.clear();
        excludedPatterns.clear();
        rolesPatterns.clear();
        allSet.clear();
        allMap.clear();
        initialWebApp = null;
        bundle = null;
        urlPatternsConfiguredInDeploymentPlans = null;
        dynamicSecurityWebApp = null;
        annotationSecurityWebApp = null;
    }

    private static class RecordingPolicyConfiguration implements PolicyConfiguration {

        private final PermissionCollection excludedPermissions = new Permissions();

        private final PermissionCollection uncheckedPermissions = new Permissions();

        private final Map<String, PermissionCollection> rolePermissions = new HashMap<String, PermissionCollection>();

        private final StringBuilder audit;

        private RecordingPolicyConfiguration(boolean audit) {
            if (audit) {
                this.audit = new StringBuilder();
            } else {
                this.audit = null;
            }
        }

        public String getContextID() throws PolicyContextException {
            return null;
        }

        public void addToRole(String roleName, PermissionCollection permissions) {
            throw new IllegalStateException("not implemented");
        }

        public void addToRole(String roleName, Permission permission) throws PolicyContextException {
            if (audit != null) {
                audit.append("Role: ").append(roleName).append(" -> ").append(permission).append('\n');
            }
            PermissionCollection permissionsForRole = rolePermissions.get(roleName);
            if (permissionsForRole == null) {
                permissionsForRole = new Permissions();
                rolePermissions.put(roleName, permissionsForRole);
            }
            permissionsForRole.add(permission);
        }

        public void addToUncheckedPolicy(PermissionCollection permissions) {
            throw new IllegalStateException("not implemented");
        }

        public void addToUncheckedPolicy(Permission permission) throws PolicyContextException {
            if (audit != null) {
                audit.append("Unchecked -> ").append(permission).append('\n');
            }
            uncheckedPermissions.add(permission);
        }

        public void addToExcludedPolicy(PermissionCollection permissions) {
            throw new IllegalStateException("not implemented");
        }

        public void addToExcludedPolicy(Permission permission) throws PolicyContextException {
            if (audit != null) {
                audit.append("Excluded -> ").append(permission).append('\n');
            }
            excludedPermissions.add(permission);
        }

        public void removeRole(String roleName) throws PolicyContextException {
            throw new IllegalStateException("not implemented");
        }

        public void removeUncheckedPolicy() throws PolicyContextException {
            throw new IllegalStateException("not implemented");
        }

        public void removeExcludedPolicy() throws PolicyContextException {
            throw new IllegalStateException("not implemented");
        }

        public void linkConfiguration(PolicyConfiguration link) throws PolicyContextException {
            throw new IllegalStateException("not implemented");
        }

        public void delete() throws PolicyContextException {
            throw new IllegalStateException("not implemented");
        }

        public void commit() throws PolicyContextException {
            throw new IllegalStateException("not implemented");
        }

        public boolean inService() throws PolicyContextException {
            throw new IllegalStateException("not implemented");
        }

        public ComponentPermissions getComponentPermissions() {
            return new ComponentPermissions(excludedPermissions, uncheckedPermissions, rolePermissions);
        }

        public String getAudit() {
            if (audit == null) {
                return "no audit kept";
            }
            return audit.toString();
        }
    }
}
TOP

Related Classes of org.apache.geronimo.web.security.SpecSecurityBuilder$RecordingPolicyConfiguration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.