com.googlecode.fascinator.portal.security.FascinatorWebSecurityExpressionRoot.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.fascinator.portal.security.FascinatorWebSecurityExpressionRoot.java

Source

/* 
 * The Fascinator - Portal - Security
 * Copyright (C) 2013 Queensland Cyber Infrastructure Foundation (http://www.qcif.edu.au/)
 * 
 * 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 2 of the License, or
 * (at your option) 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package com.googlecode.fascinator.portal.security;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.json.simple.JSONArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.WebSecurityExpressionRoot;

import com.googlecode.fascinator.api.access.AccessControl;
import com.googlecode.fascinator.api.access.AccessControlException;
import com.googlecode.fascinator.api.storage.DigitalObject;
import com.googlecode.fascinator.api.storage.Storage;
import com.googlecode.fascinator.api.storage.StorageException;
import com.googlecode.fascinator.common.FascinatorHome;
import com.googlecode.fascinator.common.JsonObject;
import com.googlecode.fascinator.common.JsonSimple;
import com.googlecode.fascinator.common.JsonSimpleConfig;
import com.googlecode.fascinator.common.storage.StorageUtils;

/**
 * Spring security check methods for Fascinator portal.
 * 
 * @author Andrew Brazzatti
 * @author Jianfeng Li
 * 
 */
public class FascinatorWebSecurityExpressionRoot extends WebSecurityExpressionRoot {
    private Logger log = LoggerFactory.getLogger(FascinatorWebSecurityExpressionRoot.class);
    private Storage storage;
    private JsonSimpleConfig systemConfiguration;
    private AccessControl accessControl;
    private JsonSimple workflowConfigJson;

    private static final String OID_PATTERN = ".+([0-9a-f]{32}).*";

    public FascinatorWebSecurityExpressionRoot(Authentication a, FilterInvocation fi) {
        super(a, fi);
        try {
            systemConfiguration = new JsonSimpleConfig();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public FascinatorWebSecurityExpressionRoot(Authentication authentication, FilterInvocation fi, Storage storage,
            AccessControl accessControl) {
        this(authentication, fi);
        this.storage = storage;
        this.accessControl = accessControl;
    }

    public boolean hasDownloadAccess() {
        return hasDownloadAccess(OID_PATTERN);
    }

    public boolean hasDownloadAccess(String oidPattern) {
        if (isAdmin()) {
            return true;
        }
        String oid = getOid(oidPattern);
        DigitalObject digitalObject = getDigitalObject(oid);
        Properties tfObjMeta;
        try {
            tfObjMeta = digitalObject.getMetadata();

            if (isPublished(tfObjMeta)) {
                return true;
            }

            if (isOwner(tfObjMeta)) {
                return true;
            }

            if (isInAllowedRoles(oid)) {
                return true;
            }

            if (isInAllowedUsers(oid)) {
                return true;
            }
            // TODO: Check whether attachment is set to public or not
        } catch (Exception e) {
            log.error("hasDownloadAccess check failed", e);

        }
        return false;
    }

    private boolean isAdmin() {
        if (authentication.getAuthorities().contains("admin")) {
            return true;
        }
        return false;
    }

    /**
     * get view access of an object defined in request. reference to
     * /fascinator-
     * portal/src/main/config/portal/default/default/scripts/detail.py
     * 
     * @return boolean
     */
    public boolean hasViewAccess() {
        return hasViewAccess(OID_PATTERN);
    }

    public boolean hasViewAccess(String oidPattern) {
        String oid = getOid(oidPattern);
        if (oid != null) {
            try {
                DigitalObject digitalObject = getDigitalObject(oid);
                if (digitalObject != null) {

                    Properties tfObjMeta = digitalObject.getMetadata();

                    if (isPublished(tfObjMeta)) {
                        return true;
                    }

                    if (isOwner(tfObjMeta)) {
                        return true;
                    }

                    if (isInAllowedRoles(oid)) {
                        return true;
                    }

                    if (isInAllowedUsers(oid)) {
                        return true;
                    }

                } else {
                    return false;
                }

            } catch (Exception e) {
                log.error("Failed to check view access: ", e);
            }
        }
        return false;
    }

    public boolean isInAllowedUsers() {
        return isInAllowedUsers(OID_PATTERN);
    }

    public boolean isInAllowedUsers(String oid) {
        String userName = (String) authentication.getPrincipal();
        try {
            List<String> allowedUsers = accessControl.getUsers(oid);
            if (allowedUsers != null) {
                for (String allowedUserName : allowedUsers) {
                    if (allowedUserName.equals(userName)) {
                        return true;
                    }
                }
            }
        } catch (AccessControlException e) {
            return false;
        }
        return false;
    }

    public boolean isPublished() {
        String oid = getOid(OID_PATTERN);
        if (oid != null) {
            try {
                DigitalObject digitalObject = getDigitalObject(oid);
                if (digitalObject != null) {
                    Properties tfObjMeta = digitalObject.getMetadata();
                    return isPublished(tfObjMeta);
                }
            } catch (Exception e) {
                log.error("Failed to check property of isPublished.", e);
            }
        }
        return false;
    }

    private boolean isPublished(Properties tfObjMeta) {
        if ("true".equals(tfObjMeta.get("published"))) {
            return true;
        }
        return false;
    }

    public boolean isOwner() {
        return isOwner(OID_PATTERN);
    }

    public boolean isOwner(String oidPattern) {
        String oid = getOid(oidPattern);
        if (oid != null) {
            try {
                DigitalObject digitalObject = getDigitalObject(oid);
                if (digitalObject != null) {
                    Properties tfObjMeta = digitalObject.getMetadata();
                    return isOwner(tfObjMeta);
                }
            } catch (Exception e) {
                log.error("Failed to check ownership", e);
            }
        }
        return false;
    }

    private boolean isOwner(Properties tfObjMeta) {
        String userName = (String) authentication.getPrincipal();
        // check if the current user is the record owner
        String owner = tfObjMeta.getProperty("owner");
        if (userName.equals(owner)) {
            return true;
        }
        return false;
    }

    public boolean isInAllowedRoles() {
        String oid = getOid(OID_PATTERN);
        return isInAllowedRoles(oid);
    }

    /**
     * Check whether user has the correct role to edit
     */
    public boolean isInAllowedRoles(String oid) {
        List<String> allowedRoles;
        try {
            allowedRoles = accessControl.getRoles(oid);
            if (allowedRoles != null) {
                Collection<GrantedAuthority> userRoles = authentication.getAuthorities();
                for (GrantedAuthority grantedAuthority : userRoles) {
                    if (allowedRoles.contains(grantedAuthority.getAuthority())) {
                        return true;
                    }
                }
            }
        } catch (Exception e) {
            log.error("Failed to check allowed roles", e);
        }
        return false;
    }

    /**
     * Check editing access
     */
    public boolean hasWorkflowAccess() {
        return hasWorkflowAccess(OID_PATTERN);
    }

    /**
     * Check editing access
     */
    public boolean hasWorkflowAccess(String oidPattern) {
        boolean hasAccess = false;
        try {
            String oid = getOid(oidPattern);
            if (oid != null) {
                DigitalObject digitalObject = getDigitalObject(oid);
                JsonObject workflowStageConfiguration = getWorkflowStageConfig(digitalObject);

                if (isGuestOwnerEditAllowed(workflowStageConfiguration)) {
                    return true;
                }

                if (isOwnerEditAllowed(digitalObject, workflowStageConfiguration)) {
                    return true;
                }

                if (isInAllowedRoles(oid)) {
                    return true;
                }

            } else {
                hasAccess = false;
            }
        } catch (Exception e) {
            log.error("Failed to check workflow access: ", e);
            hasAccess = false;
        }
        return hasAccess;
    }

    public boolean isOwnerEditAllowed() {
        String oid = getOid(OID_PATTERN);
        try {
            if (oid != null) {
                DigitalObject digitalObject = getDigitalObject(oid);
                JsonObject workflowStageConfiguration = getWorkflowStageConfig(digitalObject);
                return isOwnerEditAllowed(digitalObject, workflowStageConfiguration);
            }
        } catch (Exception e) {
            log.error("Failed to check OwnerEditAllowed property", e);
        }
        return false;
    }

    private boolean isOwnerEditAllowed(DigitalObject digitalObject, JsonObject workflowStageConfiguration) {
        String ownerEditAllowed = (String) workflowStageConfiguration.get("owner_edit_allowed");

        if (ownerEditAllowed != null && Boolean.parseBoolean(ownerEditAllowed)) {
            // Check if user is the owner of the object
            Properties tfObjMeta;
            try {
                tfObjMeta = digitalObject.getMetadata();
            } catch (StorageException e) {
                log.error("Failed to read metadata from object", e);
                return false;
            }
            if (isOwner(tfObjMeta)) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public boolean hasAPIAccess() {
        String apiKey = request.getParameter("apiKey");
        if (!StringUtils.isEmpty(apiKey)) {
            Object clientObject = systemConfiguration.getObject("api", "clients", apiKey);
            if (clientObject != null) {
                return true;
            }

        }
        return false;
    }

    public boolean isGuestOwnerEditAllowed() {
        String oid = getOid(OID_PATTERN);
        try {
            if (oid != null) {
                DigitalObject digitalObject = getDigitalObject(oid);
                JsonObject workflowStageConfiguration = getWorkflowStageConfig(digitalObject);
                return isGuestOwnerEditAllowed(workflowStageConfiguration);
            }
        } catch (Exception e) {
            log.error("Failed to check GuestOwnerEditAllowed property", e);
        }
        return false;
    }

    private boolean isGuestOwnerEditAllowed(JsonObject workflowStageConfiguration) {
        String guestOwnerEditAllowed = (String) workflowStageConfiguration.get("guest_owner_edit_allowed");
        if (guestOwnerEditAllowed != null && Boolean.parseBoolean(guestOwnerEditAllowed)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Extract object ID from requestURI using
     * 
     * @param oidPatthern
     */
    private String getOid(String oidPatthern) {
        Pattern p = Pattern.compile(oidPatthern);
        String requestURI = request.getRequestURI();
        if (!StringUtils.isEmpty(request.getQueryString())) {
            requestURI = requestURI + "?" + request.getQueryString();
        }
        Matcher m = p.matcher(requestURI);

        if (m.matches()) {
            return m.group(1);
        }
        return null;
    }

    /**
     * get the workflow configuration of a digital object at the current stage
     * 
     * @param digitalObject
     * @throws StorageException
     * @throws IOException
     */
    private JsonObject getWorkflowStageConfig(DigitalObject digitalObject) throws StorageException, IOException {
        JsonSimple workflowMetadata = getWorkflowMetadata(digitalObject);
        String workflowId = workflowMetadata.getString(null, "id");
        JsonSimple workflowConfiguration = getWorkflowConfiguration(workflowId);

        JSONArray workflowStages = workflowConfiguration.getArray("stages");
        JsonObject workflowStageConfiguration = null;
        for (int i = 0; i < workflowStages.size(); i++) {
            JsonObject workflowStage = (JsonObject) workflowStages.get(i);
            if (workflowMetadata.getJsonObject().get("step").equals(workflowStage.get("name"))) {
                workflowStageConfiguration = workflowStage;
                break;
            }
        }
        return workflowStageConfiguration;
    }

    /**
     * get the workflow configuration definition of given workflow ID
     * 
     * @param String workflowId
     * @return JsonSimple
     * @throws IOException
     */
    private JsonSimple getWorkflowConfiguration(String workflowId) throws IOException {
        if (workflowConfigJson == null) {
            String workflowConfigFileLocation = (String) systemConfiguration
                    .getObject(new Object[] { "portal", "packageTypes", workflowId }).get("jsonconfig");
            File workflowConfigFile = FascinatorHome.getPathFile("harvest/workflows/" + workflowConfigFileLocation);
            workflowConfigJson = new JsonSimple(workflowConfigFile);
        }
        return workflowConfigJson;
    }

    private DigitalObject getDigitalObject(String oid) {
        DigitalObject digitalObject = null;
        try {
            digitalObject = StorageUtils.getDigitalObject(storage, oid);
        } catch (StorageException e) {
            log.error("When checking access, cannot get object {}", oid, e);
        }
        return digitalObject;
    }

    private JsonSimple getWorkflowMetadata(DigitalObject digitalObject) throws StorageException, IOException {
        return new JsonSimple(digitalObject.getPayload("workflow.metadata").open());
    }

}