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

org.apache.geronimo.web.security.SpecSecurityBuilder Maven / Gradle / Ivy

The newest version!
/*
 * 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.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
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 org.apache.geronimo.security.jacc.ComponentPermissions;
import org.apache.geronimo.web.info.SecurityConstraintInfo;
import org.apache.geronimo.web.info.SecurityRoleRefInfo;
import org.apache.geronimo.web.info.ServletInfo;
import org.apache.geronimo.web.info.WebAppInfo;
import org.apache.geronimo.web.info.WebResourceCollectionInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @version $Rev: 1025519 $ $Date: 2010-10-20 19:55:31 +0800 (Wed, 20 Oct 2010) $
 */
public class SpecSecurityBuilder {

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

    private final Set securityRoles = new HashSet();

    private final Map uncheckedPatterns = new HashMap();

    private final Map uncheckedResourcePatterns = new HashMap();

    private final Map uncheckedUserPatterns = new HashMap();

    private final Map excludedPatterns = new HashMap();

    private final Map> rolesPatterns = new HashMap>();

    private final Set allSet = new HashSet();

    private final Map allMap = new HashMap(); //uncheckedPatterns union excludedPatterns union rolesPatterns.

    private final RecordingPolicyConfiguration policyConfiguration = new RecordingPolicyConfiguration(true);

    private WebAppInfo webAppInfo;

    public SpecSecurityBuilder(WebAppInfo webAppInfo) {
        this.webAppInfo = webAppInfo;
    }

    public ComponentPermissions buildSpecSecurityConfig() {
        securityRoles.addAll(webAppInfo.securityRoles);
        try {
            for (ServletInfo servlet : webAppInfo.servlets) {
                processRoleRefPermissions(servlet);
            }
            //add the role-ref permissions for unmapped jsps
            addUnmappedJSPPermissions();
            analyzeSecurityConstraints(webAppInfo.securityConstraints);
            removeExcludedDups();
            return buildComponentPermissions();
        } catch (PolicyContextException e) {
            throw new IllegalStateException("Should not happen", e);
        }
    }

    private void analyzeSecurityConstraints(List securityConstraints) {
        for (SecurityConstraintInfo securityConstraint : securityConstraints) {
            Map currentPatterns = null;
            Set roleNames = null;
            if (securityConstraint.authConstraint != null) {
                if (securityConstraint.authConstraint.roleNames.size() == 0) {
                    currentPatterns = excludedPatterns;
                } else {
                    roleNames = new HashSet(securityConstraint.authConstraint.roleNames);
                    if(roleNames.remove("*")) {
                        roleNames.addAll(securityRoles);
                    }
                }
            } else {
                currentPatterns = uncheckedPatterns;
            }
            String transport = securityConstraint.userDataConstraint == null ? "NONE" : securityConstraint.userDataConstraint;
            
            boolean isRolebasedPatten = (currentPatterns == null);
            
            for (WebResourceCollectionInfo webResourceCollection : securityConstraint.webResourceCollections) {
                //Calculate HTTP methods list
                for (String urlPattern : webResourceCollection.urlPatterns) {
                    if (isRolebasedPatten) {
                        for (String roleName : roleNames) {
                            Map currentRolePatterns = rolesPatterns.get(roleName);
                            if (currentRolePatterns == null) {
                                currentRolePatterns = new HashMap();
                                rolesPatterns.put(roleName, currentRolePatterns);
                            }
                            analyzeURLPattern(urlPattern, webResourceCollection.httpMethods, webResourceCollection.omission, transport, currentRolePatterns);
                        }
                    } else {
                        analyzeURLPattern(urlPattern, webResourceCollection.httpMethods, webResourceCollection.omission, transport, currentPatterns);
                    }
                    URLPattern allPattern = allMap.get(urlPattern);
                    if (allPattern == null) {
                        allPattern = new URLPattern(urlPattern, webResourceCollection.httpMethods, webResourceCollection.omission);
                        allSet.add(allPattern);
                        allMap.put(urlPattern, allPattern);
                    } else {
                        allPattern.addMethods(webResourceCollection.httpMethods, webResourceCollection.omission);
                    }

                }
            }
        }
    }

    private void analyzeURLPattern(String urlPattern, Set httpMethods, boolean omission, String transport, Map currentPatterns) {
        URLPattern pattern = currentPatterns.get(urlPattern);
        if (pattern == null) {
            pattern = new URLPattern(urlPattern, httpMethods, omission);
            currentPatterns.put(urlPattern, pattern);
        } else {
            pattern.addMethods(httpMethods, omission);
        }
        pattern.setTransport(transport);
    }

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

    private void removeExcluded(String url, URLPattern pattern, Map 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 (Map.Entry> entry : rolesPatterns.entrySet()) {
            Set currentRolePatterns = new HashSet(entry.getValue().values());
            for (URLPattern pattern : entry.getValue().values()) {
                String name = pattern.getQualifiedPattern(currentRolePatterns);
                String actions = pattern.getMethods();
                WebResourcePermission permission = new WebResourcePermission(name, actions);
                policyConfiguration.addToRole(entry.getKey(), 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 WebResourcePermission and a WebUserDataPermission must be instantiated for
         * each url-pattern in the deployment descriptor and the default pattern "/", that is not combined
         * by the web-resource-collection 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
         * addToUncheckedPolcy method on the PolicyConfiguration 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. emptySet(), 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 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(ServletInfo servlet) throws PolicyContextException {
        String servletName = servlet.servletName.trim();
        //WebRoleRefPermissions
        Set unmappedRoles = new HashSet(securityRoles);
        for (SecurityRoleRefInfo securityRoleRef : servlet.securityRoleRefs) {
            //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(securityRoleRef.roleLink, new WebRoleRefPermission(servletName, securityRoleRef.roleName));
            unmappedRoles.remove(securityRoleRef.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));
        }
    }

    public void clear() {
        securityRoles.clear();
        uncheckedPatterns.clear();
        uncheckedResourcePatterns.clear();
        uncheckedUserPatterns.clear();
        excludedPatterns.clear();
        rolesPatterns.clear();
        allSet.clear();
        allMap.clear();
    }

    private static class RecordingPolicyConfiguration implements PolicyConfiguration {

        private final PermissionCollection excludedPermissions = new Permissions();

        private final PermissionCollection uncheckedPermissions = new Permissions();

        private final Map rolePermissions = new HashMap();

        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();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy