org.pepstock.jem.ant.tasks.AntBatchSecurityManager.java Source code

Java tutorial

Introduction

Here is the source code for org.pepstock.jem.ant.tasks.AntBatchSecurityManager.java

Source

/**
JEM, the BEE - Job Entry Manager, the Batch Execution Environment
Copyright (C) 2012-2015   Simone "Busy" Businaro
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.pepstock.jem.ant.tasks;

import java.io.FilePermission;
import java.net.InetAddress;
import java.net.SocketPermission;
import java.net.UnknownHostException;
import java.security.Permission;
import java.util.Collection;
import java.util.PropertyPermission;

import org.apache.commons.lang3.StringUtils;
import org.pepstock.jem.log.LogAppl;
import org.pepstock.jem.node.NodeMessage;
import org.pepstock.jem.node.security.BatchSecurityManager;
import org.pepstock.jem.node.security.Permissions;
import org.pepstock.jem.node.security.Role;
import org.pepstock.jem.node.security.Roles;
import org.pepstock.jem.util.Parser;
import org.pepstock.jem.util.rmi.RmiKeys;

/**
 * Is the SecurityManager under which the job is running. Every user that launch
 * a job will have a set of roles each of which will have a set of permissions.
 * The BatchSecurityManager verify if the job is doing what the user is
 * permitted to do.
 * 
 * @author Simone "Busy" Businaro
 * @version 1.0
 * 
 */
class AntBatchSecurityManager extends BatchSecurityManager {

    // this is a constant and but be maintained if ANT community will change the security manager
    // this is necessary because is not allowed to change a security manager (only is ANT one)
    private static final String ANT_PERMISSIONS = org.apache.tools.ant.types.Permissions.class.getName();
    private static final String ANT_SECURITY_MANAGER = ANT_PERMISSIONS + "$MySM";

    private boolean isAdministrator = false;

    private boolean isGrantor = false;

    private boolean internalAction = false;

    /**
     * Constructs the object using the roles of the job user
     * 
     * @param roles the roles of the current user executing the jcl
     */
    AntBatchSecurityManager(Collection<Role> roles) {
        // passes the roles to the parent
        super(roles);
        // reads permission to understand 
        // which roles ootb that the  user has got
        loadPermissions(roles);
    }

    /**
     * @return the internalActions
     */
    final boolean isInternalAction() {
        return internalAction;
    }

    /**
     * @param internalAction the internalActions to set
     */
    final void setInternalAction(boolean internalAction) {
        this.internalAction = internalAction;
    }

    /**
     * @return the isAdministrator
     */
    final boolean isAdministrator() {
        return isAdministrator;
    }

    /**
     * @param isAdministrator the isAdministrator to set
     */
    final void setAdministrator(boolean isAdministrator) {
        this.isAdministrator = isAdministrator;
    }

    /**
     * @return the isGrantor
     */
    final boolean isGrantor() {
        return isGrantor;
    }

    /**
     * @param isGrantor the isGrantor to set
     */
    final void setGrantor(boolean isGrantor) {
        this.isGrantor = isGrantor;
    }

    /**
     * Load all the user permissions from roles
     * 
     * @param roles list of the roles of job user
     */
    private void loadPermissions(Collection<Role> roles) {
        // scans all roles
        for (Role role : roles) {
            // checks if is administrator
            if (role.getName().equalsIgnoreCase(Roles.ADMINISTRATOR)) {
                // if yes, sets administrator to true
                setAdministrator(true);
            }
            // checks if is grantor
            if (role.getName().equalsIgnoreCase(Roles.GRANTOR)) {
                // if yes, sets grantor to true
                setGrantor(true);
            }
        }
    }

    /**
     * Check the batch permission
     * 
     * @param permission is a shiro permission that can be:
     *            <p>
     * @see org.pepstock.jem.node.security.RegExpPermission or
     *      <p>
     * @see org.pepstock.jem.node.security.StringPermission
     * @return true if user has the right permission, false otherwise
     */
    @Override
    public final boolean checkBatchPermission(String permission) {
        // if is administrator or 
        // is executing code of JEM and not the custom one,
        // it can do everything
        if (isAdministrator() || isInternalAction()) {
            return true;
        }
        return super.checkBatchPermission(permission);
    }

    /**
     * Scans the stack trace element to understand if setSecurity manager is allowed.
     * <br>
     * ONLY ANT engine can set security manager and it does with
     * <code>org.apache.tools.ant.types.Permissions</code> class.
     * <br>
     * if it arrives with <code>org.apache.tools.ant.types.Permissions$MySM</code> means that
     * ANT security manager delegates us to check but we can't do it.
     * <br>
     * If it tries to change it by a ANT task, is not allowed!
     * 
     * @return <code>true</code> if ANT is initializing the task otherwise o=always false.
     */
    private boolean isAllowedSetSecurityManager() {
        StackTraceElement[] elements = Thread.getAllStackTraces().get(Thread.currentThread());
        boolean thisFound = false;
        for (StackTraceElement element : elements) {
            // before must be in the stack trace this class
            if (element.getClassName().equalsIgnoreCase(getClass().getName())) {
                thisFound = true;
                // checks if is called by Security manager of ANT
                // if yes, it's delegating... that means that some one try to set the security manager
                // and this is NOT allowed.
            } else if (element.getClassName().equalsIgnoreCase(ANT_SECURITY_MANAGER) && thisFound) {
                return false;
                // if it is called by the permission, that means teh ANT is intsalling own security
                // manager, MySM, and that's ALLOWED!!
            } else if (element.getClassName().equalsIgnoreCase(ANT_PERMISSIONS) && thisFound) {
                return true;
            }
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.SecurityManager#checkPermission(java.security.Permission)
     */
    @Override
    public void checkPermission(Permission perm) {
        // checks if someone add a security manager
        if (perm instanceof RuntimePermission && "setSecurityManager".equalsIgnoreCase(perm.getName())) {
            if (!isAllowedSetSecurityManager()) {
                LogAppl.getInstance().emit(NodeMessage.JEMC274E);
                throw new SecurityException(NodeMessage.JEMC274E.toMessage().getMessage());
            }
            return;
        }
        // this check is necessary to avoid that someone
        // set jem properties, accessing outside of GFS
        if (perm instanceof PropertyPermission && "write".equalsIgnoreCase(perm.getActions())
                && perm.getName().startsWith("jem")) {
            LogAppl.getInstance().emit(NodeMessage.JEMC127E);
            throw new SecurityException(NodeMessage.JEMC127E.toMessage().getMessage());
        }
        // checks is administrator. if true return.
        if (isAdministrator() || isInternalAction()) {
            return;
        }
        // checks the file access
        // calling the right method, in according
        // with the action of permission
        if (perm instanceof FilePermission) {
            if ("read".equalsIgnoreCase(perm.getActions())) {
                checkRead(perm.getName());
            } else if ("write".equalsIgnoreCase(perm.getActions())) {
                checkWrite(perm.getName());
            } else if ("delete".equalsIgnoreCase(perm.getActions())) {
                checkDelete(perm.getName());
            } else {
                checkRead(perm.getName());
            }
        } else if (perm instanceof SocketPermission) {
            // checks the RMI access.
            // checks to RMI is not allowed if you're not a admin
            SocketPermission sperm = (SocketPermission) perm;
            int port = Parser.parseInt(StringUtils.substringAfter(sperm.getName(), ":"), Integer.MAX_VALUE);
            int portRmi = Parser.parseInt(System.getProperty(RmiKeys.JEM_RMI_PORT), Integer.MIN_VALUE);
            // if is going to RMI port and
            // is not executing JEM code and is not grantor
            if (port == portRmi && !isInternalAction() && !isGrantor()) {
                // extracts host name
                String hostname = StringUtils.substringBefore(sperm.getName(), ":");
                try {
                    // gets hostname and localhost
                    String resolved = InetAddress.getByName(hostname).getHostAddress();
                    String localhost = InetAddress.getLocalHost().getHostAddress();
                    // if they are equals and the user
                    // desn't have the internal service permission
                    // EXCEPTION!!
                    if (resolved.equalsIgnoreCase(localhost)
                            && !checkBatchPermission(Permissions.INTERNAL_SERVICES)) {
                        LogAppl.getInstance().emit(NodeMessage.JEMC128E);
                        throw new SecurityException(NodeMessage.JEMC128E.toMessage().getMessage());
                    }
                } catch (UnknownHostException e) {
                    // if there is an error on resolving the hostname
                    LogAppl.getInstance().emit(NodeMessage.JEMC128E);
                    throw new SecurityException(NodeMessage.JEMC128E.toMessage().getMessage(), e);
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.SecurityManager#checkRead(java.lang.String)
     */
    @Override
    public final void checkRead(String file) {
        // is admin or internal action, can read everything
        if (isAdministrator() || isInternalAction()) {
            return;
        }
        super.checkRead(file);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.SecurityManager#checkWrite(java.lang.String)
     */
    @Override
    public void checkWrite(String file) {
        // is admin or internal action, can write everything
        if (isAdministrator() || isInternalAction()) {
            return;
        }
        super.checkWrite(file);
    }
}