org.apache.wicket.markup.html.PackageResourceGuard.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.wicket.markup.html.PackageResourceGuard.java

Source

/*
 * 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.wicket.markup.html;

import java.io.File;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

import org.apache.wicket.Application;
import org.apache.wicket.util.string.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Default implementation of {@link IPackageResourceGuard}. By default, the extensions 'properties',
 * 'class' and 'java' are blocked and files like 'log4j.xml' and 'applicationContext.xml'
 * 
 * A more secure implementation which by default denies access to any resource is
 * {@link SecurePackageResourceGuard}
 * 
 * @author eelcohillenius
 */
public class PackageResourceGuard implements IPackageResourceGuard {
    /** Log. */
    private static final Logger log = LoggerFactory.getLogger(PackageResourceGuard.class);

    /** Set of extensions that are denied access. */
    private Set<String> blockedExtensions = new HashSet<>(4);

    /** Set of filenames that are denied access. */
    private Set<String> blockedFiles = new HashSet<>(4);

    private boolean allowAccessToRootResources = false;

    /**
     * Construct.
     */
    public PackageResourceGuard() {
        blockedExtensions.add("properties");
        blockedExtensions.add("class");
        blockedExtensions.add("java");

        blockedFiles.add("applicationContext.xml");
        blockedFiles.add("log4j.xml");
    }

    /**
     * @see org.apache.wicket.markup.html.IPackageResourceGuard#accept(java.lang.String)
     */
    public boolean accept(String path) {
        int ixExtension = path.lastIndexOf('.');
        int len = path.length();
        final String ext;
        if (ixExtension <= 0 || ixExtension == len || (path.lastIndexOf('/') + 1) == ixExtension
                || (path.lastIndexOf('\\') + 1) == ixExtension) {
            ext = null;
        } else {
            ext = path.substring(ixExtension + 1).toLowerCase(Locale.ROOT).trim();
        }

        if ("html".equals(ext)) {
            String prefix = path.substring(0, ixExtension);

            ClassLoader classLoader = getClass().getClassLoader();
            while (true) {
                if (classLoader.getResource(prefix + ".class") != null) {
                    log.warn("Access denied to shared (static) resource because it is a Wicket markup file: "
                            + path);
                    return false;
                }

                int ixUnderscore = prefix.lastIndexOf('_');
                if (ixUnderscore == -1) {
                    break;
                }

                prefix = prefix.substring(0, ixUnderscore);
            }
        }

        if (acceptExtension(ext) == false) {
            log.warn("Access denied to shared (static) resource because of the file extension: " + path);
            return false;
        }

        String filename = Strings.lastPathComponent(path, File.separatorChar);
        if (acceptFile(filename) == false) {
            log.warn("Access denied to shared (static) resource because of the file name: " + path);
            return false;
        }

        // Only if a placeholder, e.g. $up$ is defined, access to parent directories is allowed
        if (Strings.isEmpty(Application.get().getResourceSettings().getParentFolderPlaceholder())) {
            if (path.contains("..")) {
                log.warn("Access to parent directories via '..' is by default disabled for shared resources: "
                        + path);
                return false;
            }
        }

        //
        // for windows we have to check both File.separator ('\') and the usual '/' since both can
        // be used and are used interchangeably
        //

        if (!allowAccessToRootResources) {
            String absolute = path;
            if ("\\".equals(File.separator)) {
                // handle a windows path which may have a drive letter in it

                int drive = absolute.indexOf(":\\");
                if (drive < 0) {
                    drive = absolute.indexOf(":/");
                }
                if (drive > 0) {
                    // strip the drive letter off the path
                    absolute = absolute.substring(drive + 2);
                }
            }

            if (absolute.startsWith(File.separator) || absolute.startsWith("/")) {
                absolute = absolute.substring(1);
            }
            if (!absolute.contains(File.separator) && !absolute.contains("/")) {
                log.warn("Access to root directory is by default disabled for shared resources: " + path);
                return false;
            }
        }

        return true;
    }

    /**
     * Whether the provided extension is accepted.
     * 
     * @param extension
     *            The extension, starting from the class root (packages are separated with forward
     *            slashes instead of dots).
     * @return True if accepted, false otherwise.
     */
    protected boolean acceptExtension(String extension) {
        return (!blockedExtensions.contains(extension));
    }

    /**
     * Whether the provided filename is accepted.
     * 
     * @param file
     *            filename
     * @return True if accepted, false otherwise.
     */
    protected boolean acceptFile(String file) {
        if (file != null) {
            file = file.trim();
        }
        return (!blockedFiles.contains(file));
    }

    /**
     * Gets the set of extensions that are denied access.
     * 
     * @return The set of extensions that are denied access
     */
    protected final Set<String> getBlockedExtensions() {
        return blockedExtensions;
    }

    /**
     * Gets the set of extensions that are denied access.
     * 
     * @return The set of extensions that are denied access
     */
    protected final Set<String> getBlockedFiles() {
        return blockedFiles;
    }

    /**
     * Sets the set of extensions that are denied access.
     * 
     * @param blockedExtensions
     *            Set of extensions that are denied access
     */
    protected final void setBlockedExtensions(Set<String> blockedExtensions) {
        this.blockedExtensions = blockedExtensions;
    }

    /**
     * Sets the set of filenames that are denied access.
     * 
     * @param blockedFiles
     *            Set of extensions that are denied access
     */
    protected final void setBlockedFiles(Set<String> blockedFiles) {
        this.blockedFiles = blockedFiles;
    }

    /**
     * Checks whether or not resources in the web root folder can be access.
     * 
     * @return {@code true} iff root resources can be accessed
     */
    public final boolean isAllowAccessToRootResources() {
        return allowAccessToRootResources;
    }

    /**
     * Sets whether or not resources in the web root folder can be accessed.
     * 
     * @param allowAccessToRootResources
     */
    public final void setAllowAccessToRootResources(boolean allowAccessToRootResources) {
        this.allowAccessToRootResources = allowAccessToRootResources;
    }
}