piecework.content.concrete.FileSystemContentProvider.java Source code

Java tutorial

Introduction

Here is the source code for piecework.content.concrete.FileSystemContentProvider.java

Source

/*
 * Copyright 2013 University of Washington
 *
 * Licensed under the Educational Community License, Version 1.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.opensource.org/licenses/ecl1.php
 *
 * 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 piecework.content.concrete;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;
import piecework.Constants;
import piecework.content.ContentProvider;
import piecework.content.ContentResource;
import piecework.enumeration.AlarmSeverity;
import piecework.enumeration.Scheme;
import piecework.exception.ForbiddenError;
import piecework.exception.InternalServerError;
import piecework.exception.PieceworkException;
import piecework.model.ContentProfile;
import piecework.persistence.ContentProfileProvider;
import piecework.security.AccessTracker;
import piecework.util.FileUtility;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;

/**
 * @author James Renfro
 */
@Service
public class FileSystemContentProvider implements ContentProvider {

    private static final Logger LOG = Logger.getLogger(FileSystemContentProvider.class);

    @Autowired
    AccessTracker accessTracker;

    @Autowired
    private Environment environment;

    private File root;

    private String filesystemRoot;

    @PostConstruct
    public void init() {
        if (environment != null && StringUtils.isEmpty(filesystemRoot))
            filesystemRoot = environment.getProperty("base.filesystem.root", ".");

        if (StringUtils.isNotEmpty(filesystemRoot))
            this.root = new File(filesystemRoot);
    }

    @Override
    public ContentResource findByLocation(ContentProfileProvider modelProvider, String rawPath)
            throws PieceworkException {
        if (!rawPath.startsWith("file:")) {
            LOG.error("Should not be looking for a file resource without the file prefix");
            return null;
        }

        String path = rawPath.substring("file:".length());

        ContentProfile contentProfile = modelProvider.contentProfile();
        // Show never use FileSystemContentProvider unless the content profile explicitly
        // specifies a base path
        if (contentProfile == null || StringUtils.isEmpty(contentProfile.getBaseDirectory()))
            return null;

        File file = new File(path);

        try {
            // Check that base directory is a descendent of Piecework's filesystem root
            File baseDirectory = new File(contentProfile.getBaseDirectory());
            boolean isBaseDirectoryDescendent = FileUtility.isAncestorOf(root, baseDirectory);

            // The base directory is not a descendent of root, then try to find it under the root
            if (!isBaseDirectoryDescendent) {
                baseDirectory = new File(root, contentProfile.getBaseDirectory());
                isBaseDirectoryDescendent = FileUtility.isAncestorOf(root, baseDirectory);
            }

            boolean isFileDescendent = FileUtility.isAncestorOf(baseDirectory, file);

            if (!isFileDescendent) {
                file = new File(baseDirectory, path);
                isFileDescendent = FileUtility.isAncestorOf(baseDirectory, file);
            }

            boolean isFileReadAllowed = isBaseDirectoryDescendent && isFileDescendent;
            if (!isFileReadAllowed) {
                accessTracker.alarm(AlarmSeverity.MINOR, "Attempt to access file " + file.getAbsolutePath()
                        + " outside of " + root.getAbsolutePath() + " forbidden", modelProvider.principal());
                throw new ForbiddenError();
            }
        } catch (IOException ioe) {
            LOG.error("Unable to determine if file is within approved limits of file system", ioe);
            throw new InternalServerError(Constants.ExceptionCodes.system_misconfigured, ioe.getMessage());
        }

        FileSystemResource resource = new FileSystemResource(file);

        if (resource.exists())
            return new FileSystemContentResource(resource);

        LOG.error("No file exists at this path: " + file.getAbsolutePath());
        return null;
    }

    @Override
    public Scheme getScheme() {
        return Scheme.FILESYSTEM;
    }

    @Override
    public String getKey() {
        return "default-filesystem";
    }

    public void setFilesystemRoot(String filesystemRoot) {
        this.filesystemRoot = filesystemRoot;
    }
}