org.pepstock.jem.node.security.SecurityUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.pepstock.jem.node.security.SecurityUtils.java

Source

/**
JEM, the BEE - Job Entry Manager, the Batch Execution Environment
Copyright (C) 2012-2015   Andrea "Stock" Stocchero
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.node.security;

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.pepstock.catalog.gdg.Root;
import org.pepstock.jem.log.LogAppl;
import org.pepstock.jem.node.DataPathsContainer;
import org.pepstock.jem.node.OutputSystem;
import org.pepstock.jem.node.configuration.ConfigKeys;

/**
 * Utility class to check if the permission checking on the user of the job (exclude the administrators), 
 * to be authorized to access in READ or WRITE
 * to the folders and than files of JEM cluster, must be performed or not.
 * 
 * @author Andrea "Stock" Stocchero
 * @version 1.0   
 *
 */
public class SecurityUtils {

    /**
     * if the file name must be checked with permissions of local file system
     */
    public static final int TO_BE_LOCAL_FS_CHECKED = 3;

    /**
     * if the file name must be checked with permissions of GFS
     */
    public static final int TO_BE_GFS_CHECKED = 2;

    /**
     * if the file name must be checked with permissions 
     */
    public static final int TO_BE_CHECKED = 1;

    /**
     * No security check
     */
    public static final int TO_BE_IGNORED = 0;

    /**
     * Not authorized! Exception!
     */
    public static final int TO_BE_REJECTED = -1;

    private static final String OUTPUT_PATH = System.getProperty(ConfigKeys.JEM_OUTPUT_PATH_NAME);

    private static final String SOURCE_PATH = System.getProperty(ConfigKeys.JEM_SOURCE_PATH_NAME);

    private static final String LIBRARY_PATH = System.getProperty(ConfigKeys.JEM_LIBRARY_PATH_NAME);

    private static final String BINARY_PATH = System.getProperty(ConfigKeys.JEM_BINARY_PATH_NAME);

    private static final String CLASS_PATH = System.getProperty(ConfigKeys.JEM_CLASSPATH_PATH_NAME);

    private static final String PERSISTENCE_PATH = System.getProperty(ConfigKeys.JEM_PERSISTENCE_PATH_NAME);

    private static final String HOME = System.getProperty(ConfigKeys.JEM_HOME);

    private String temp = null;

    /**
     * Constructs the object creating the temporary folder, using the JEM node
     * Operating system configuration. 
     */
    public SecurityUtils() {
        try {
            // creates a temporary file only to the absolute path
            // of the file, used as temporary files folder
            // it doesn't use the system property to avoid errors if not set
            temp = FilenameUtils.normalize(File.createTempFile("security", "tmp").getParentFile().getAbsolutePath(),
                    true);
        } catch (IOException e) {
            // debug
            LogAppl.getInstance().debug(e.getMessage(), e);
        }
    }

    /**
     * Checks if the file name must be checked, ignored or rejected 
     * 
     * @param fileName to check!
     * @return if authorized or must be checked
     */
    public int checkReadFileName(String fileName) {

        // checks if filename is located on a data paths
        String dataPath = DataPathsContainer.getInstance().getAbsoluteDataPath(fileName);
        // if yes (not null!) the permission must be checked
        if (dataPath != null) {
            return TO_BE_CHECKED;
        }

        // gets the boolean if is going to source or output folders
        boolean textFolder = fileName.startsWith(OUTPUT_PATH) || fileName.startsWith(SOURCE_PATH);
        // gets the boolean if is going to binary or library or class folders
        boolean binaryFolder = fileName.startsWith(LIBRARY_PATH) || fileName.startsWith(BINARY_PATH)
                || fileName.startsWith(CLASS_PATH);

        // if is going on the previous checked folder, DOESN'T
        // perform any permission check
        if (textFolder || binaryFolder) {
            return TO_BE_IGNORED;
        }

        // if you're going on the persistence path, a Security exception will be thrown
        // because it's not allowed to read anything on persistence folder
        if (fileName.startsWith(PERSISTENCE_PATH)) {
            return TO_BE_REJECTED;
        }

        // if you're reading classes, jar or zip, DOESN'T
        // perform any permission check
        // this is done when JAVA programs are executed
        String ext = FilenameUtils.getExtension(fileName);
        if ("class".equalsIgnoreCase(ext) || "jar".equalsIgnoreCase(ext) || "zip".equalsIgnoreCase(ext)) {
            return TO_BE_IGNORED;
        }

        // any access to the JEM home to read configuration files are not allowed.
        // Security exception will be thrown
        if (fileName.startsWith(HOME) && FilenameUtils.wildcardMatch(fileName,
                HOME + File.separator + "*" + File.separator + "config*")) {
            return TO_BE_REJECTED;
        }
        // if you are here,  DOESN'T
        // perform any permission check
        return TO_BE_IGNORED;
    }

    /**
     * Checks if the file name must be checked, ignored or rejected 
     * 
     * @param fileName to check!
     * @return if authorized or must be checked
     */
    public int checkWriteFileName(String fileName) {
        // to write a "root.properties" file is not allowed
        // because that file is use for GDG to maintain the catalog
        // and the risk is to create an inconsistent situation on GDG
        if (fileName.endsWith(Root.ROOT_FILE_NAME)) {
            return TO_BE_REJECTED;
        }

        // checks if filename is located on a data paths
        String dataPath = DataPathsContainer.getInstance().getAbsoluteDataPath(fileName);
        // if yes (not null!) the permission must be checked
        if (dataPath != null) {
            return TO_BE_CHECKED;
        }

        // gets if you are going on toher GFS file systems
        boolean gfsFolder = fileName.startsWith(LIBRARY_PATH) || fileName.startsWith(BINARY_PATH)
                || fileName.startsWith(CLASS_PATH) || fileName.startsWith(SOURCE_PATH);

        // if yes, ad additional permission check must be performed (the user must have
        // the GFS file system permission)
        if (gfsFolder) {
            return TO_BE_GFS_CHECKED;
        }

        // if you're using the temporary folder, GO! No check
        if (fileName.startsWith(temp)) {
            return TO_BE_IGNORED;
        }

        // if you're trying to access to the output path
        if (fileName.startsWith(OUTPUT_PATH)) {
            // checks if you're access to the OUTPUT path, not to the sub folder
            // because subfolder are ALWAYS accessible in write because used to write
            // user data as SYSOUT
            if (FilenameUtils.getFullPathNoEndSeparator(fileName).equalsIgnoreCase(OUTPUT_PATH)) {
                String file = FilenameUtils.getName(fileName);
                // checks you are trying to write on the system files,
                // files managed by JEM node. This is NOT allowed.
                // throws a SECURITY exception
                if (OutputSystem.JCL_FILE.equalsIgnoreCase(file) || OutputSystem.JOB_FILE.equalsIgnoreCase(file)
                        || OutputSystem.JOBLOG_FILE.equalsIgnoreCase(file)
                        || OutputSystem.MESSAGESLOG_FILE.equalsIgnoreCase(file)) {
                    return TO_BE_REJECTED;
                }
            }
            // if here, you can write on OUTPUT path
            return TO_BE_IGNORED;
        }

        // if you are trying to write on JEM home.
        // This is NOT allowed.
        // throws a SECURITY exception
        if (fileName.startsWith(HOME)) {
            return TO_BE_REJECTED;
        }

        // if you are trying to write on persistent path.
        // This is NOT allowed.
        // throws a SECURITY exception
        if (fileName.startsWith(PERSISTENCE_PATH)) {
            return TO_BE_REJECTED;
        }

        // if arrives here, means is local file system
        return TO_BE_LOCAL_FS_CHECKED;
    }

    /**
     * Based on filename, it returns the permission to check when the file is not located to DATA path.
     * @param fileName to check!
     * @return permission of GFS to check
     */
    public String getGfsPermission(String fileName) {
        // here selects which permission you msut have
        // to access to GFS
        if (fileName.startsWith(LIBRARY_PATH)) {
            return Permissions.GFS_LIBRARY;
        } else if (fileName.startsWith(BINARY_PATH)) {
            return Permissions.GFS_BINARY;
        } else if (fileName.startsWith(CLASS_PATH)) {
            return Permissions.GFS_CLASS;
        } else if (fileName.startsWith(SOURCE_PATH)) {
            return Permissions.GFS_SOURCES;
        }
        return Permissions.GFS_LIBRARY;
    }

    /**
     * Extract the right file name, used inside the permissions
     * @param fileName complete path
     * @return relative file name
     */
    public String normalizeFileName(String fileName) {
        // gets data path
        String dataPath = DataPathsContainer.getInstance().getAbsoluteDataPath(fileName);
        // if not a data path, return file name as is
        if (dataPath != null) {
            // extract the filename, without the path of DATA path
            // because the permission are based on the file name
            // without the mount point of data path
            String file = StringUtils.substringAfter(fileName, dataPath);
            if (FilenameUtils.separatorsToSystem(file).startsWith(File.separator)) {
                return file.substring(1);
            } else {
                return file;
            }
        }
        return fileName;
    }

}