All Downloads are FREE. Search and download functionalities are using the official Maven repository.

repairability_test_files.NPEfix.NPEfix19.nineteen.NPEfix19_nineteen_s Maven / Gradle / Ivy

The newest version!
/*
 * 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.sling.security.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.PropertyUnbounded;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype = true,
        description = "Request filter adding Content Disposition attachment for certain paths/content types",
        label=" Apache Sling Content Disposition Filter")
@Service(value = Filter.class)
@Properties({
        @Property(name = "sling.filter.scope", value = { "request" }, propertyPrivate = true),
        @Property(name = "service.ranking", intValue = -25000, propertyPrivate = true) })
public class ContentDispositionFilter implements Filter {

    /** Logger. */
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Property(label = "Content Disposition Paths",
            description = "These paths are checked by the filter. "+
                    "Each entry is of the form 'path [ \":\" CSV of excluded content types ]'. " +
                    "Invalid entries are logged and ignored."
            , unbounded = PropertyUnbounded.ARRAY, value = { "" })
    private static final String PROP_CONTENT_DISPOSTION_PATHS = "sling.content.disposition.paths";

    @Property(label = "Content Disposition Excluded Paths",
            description = "These paths are excluded by the filter. "+
                    "Each entry is of the form 'path'. "
            , unbounded = PropertyUnbounded.ARRAY, value = { "" })
    private static final String PROP_CONTENT_DISPOSTION_EXCLUDED_PATHS = "sling.content.disposition.excluded.paths";

    private static final boolean DEFAULT_ENABLE_CONTENT_DISPOSTION_ALL_PATHS = false;
    @Property(boolValue = DEFAULT_ENABLE_CONTENT_DISPOSTION_ALL_PATHS ,
            label = "Enable Content Disposition for all paths",
            description ="This flag controls whether to enable" +
                    " Content Disposition for all paths.")
    private static final String PROP_ENABLE_CONTENT_DISPOSTION_ALL_PATHS = "sling.content.disposition.all.paths";

    /**
     * Set of paths
     */
    Set contentDispositionPaths;

    /**
     * Array of prefixes of paths
     */
    private String[] contentDispositionPathsPfx;

    Set contentDispositionExcludedPaths;

    private Map> contentTypesMapping;

    private boolean enableContentDispositionAllPaths;

    @Activate
    private void activate(final ComponentContext ctx) {
        final Dictionary props = ctx.getProperties();

        String[] contentDispostionProps = PropertiesUtil.toStringArray(props.get(PROP_CONTENT_DISPOSTION_PATHS));

        Set paths = new HashSet();
        List pfxs = new ArrayList();
        Map> contentTypesMap = new HashMap>();

        for (String path : contentDispostionProps) {
            path = path.trim();
            if (path.length() > 0) {
                int idx = path.indexOf('*');
                int colonIdx = path.indexOf(":");

                if (colonIdx > -1 && colonIdx < idx) {
                    // ':'  in paths is not allowed
                    logger.info("':' in paths is not allowed.");
                } else {
                    String p = null;
                    if (idx >= 0) {
                        if (idx > 0) {
                            p = path.substring(0, idx);
                            pfxs.add(p);
                        } else {
                            // we don't allow "*" - that would defeat the
                            // purpose.
                            logger.info("catch-all wildcard for paths not allowed.");
                        }
                    } else {
                        if (colonIdx > -1) {
                            p = path.substring(0, colonIdx);
                        } else {
                            p = path;
                        }
                        paths.add(p);
                    }
                    if (colonIdx != -1 && p != null) {
                        Set  contentTypes = getContentTypes(path.substring(colonIdx+1));
                        contentTypesMap.put(p, contentTypes);
                    }
                }

            }
        }

        contentDispositionPaths = paths.isEmpty() ? Collections.emptySet() : paths;
        contentDispositionPathsPfx = pfxs.toArray(new String[pfxs.size()]);
        contentTypesMapping = contentTypesMap.isEmpty()?Collections.>emptyMap(): contentTypesMap;

        enableContentDispositionAllPaths =  PropertiesUtil.toBoolean(props.get(PROP_ENABLE_CONTENT_DISPOSTION_ALL_PATHS),DEFAULT_ENABLE_CONTENT_DISPOSTION_ALL_PATHS);


        String[] contentDispostionExcludedPathsArray = PropertiesUtil.toStringArray(props.get(PROP_CONTENT_DISPOSTION_EXCLUDED_PATHS));

        contentDispositionExcludedPaths = new HashSet(Arrays.asList(contentDispostionExcludedPathsArray));

        logger.info("Initialized. content disposition paths: {}, content disposition paths-pfx {}, content disposition excluded paths: {}. Enable Content Disposition for all paths is set to {}", new Object[]{
                contentDispositionPaths, contentDispositionPathsPfx, contentDispositionExcludedPaths, enableContentDispositionAllPaths}
        );
    }


    public void init(FilterConfig filterConfig) throws ServletException {
        // nothing to do
    }

    public void destroy() {
        // nothing to do
    }

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {

        final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
        final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;

        final RewriterResponse rewriterResponse = new RewriterResponse(slingRequest, slingResponse);

        chain.doFilter(request, rewriterResponse);
    }

    //---------- PRIVATE METHODS ---------

    private static Set getContentTypes(String contentTypes) {
        Set contentTypesSet = new HashSet();
        if (contentTypes != null && contentTypes.length() > 0) {
            String[] contentTypesArray = contentTypes.split(",");
            for (String contentType : contentTypesArray) {
                contentTypesSet.add(contentType);
            }
        }
        return contentTypesSet;
    }

    //----------- INNER CLASSES ------------

    protected class RewriterResponse extends SlingHttpServletResponseWrapper {

        private static final String CONTENT_DISPOSTION = "Content-Disposition";

        private static final String CONTENT_DISPOSTION_ATTACHMENT = "attachment";

        private static final String PROP_JCR_DATA = "jcr:data";

        private static final String JCR_CONTENT_LEAF = "jcr:content";

        static final String ATTRIBUTE_NAME =
                "org.apache.sling.security.impl.ContentDispositionFilter.RewriterResponse.contentType";

        /** The current request. */
        private final SlingHttpServletRequest request;

        public RewriterResponse(SlingHttpServletRequest request, SlingHttpServletResponse wrappedResponse) {
            super(wrappedResponse);
            this.request = request;
        }

        /**
         * @see javax.servlet.ServletResponseWrapper#setContentType(java.lang.String)
         */
        public void setContentType(String type) {
            String previousContentType = (String) request.getAttribute(ATTRIBUTE_NAME);

            if (previousContentType != null && previousContentType.equals(type)) {
                return;
            }
            request.setAttribute(ATTRIBUTE_NAME, type);
            Resource resource = request.getResource();
            String resourcePath = resource.getPath();

            if (!contentDispositionExcludedPaths.contains(resourcePath)) {

                if (enableContentDispositionAllPaths) {
                    setContentDisposition(resource);
                } else {

                    boolean contentDispositionAdded = false;
                    if (contentDispositionPaths.contains(resourcePath)) {

                        if (contentTypesMapping.containsKey(resourcePath)) {
                            Set  exceptions = contentTypesMapping.get(resourcePath);
                            if (!exceptions.contains(type)) {
                                contentDispositionAdded = setContentDisposition(resource);
                            }
                        } else {
                            contentDispositionAdded = setContentDisposition(resource);
                        }
                    }
                    if (!contentDispositionAdded) {
                        for (String path : contentDispositionPathsPfx) {
                            if (resourcePath.startsWith(path)) {
                                if (contentTypesMapping.containsKey(path)) {
                                    Set  exceptions = contentTypesMapping.get(path);
                                    if (!exceptions.contains(type)) {
                                        setContentDisposition(resource);
                                        break;
                                    }
                                } else {
                                    setContentDisposition(resource);
                                    break;
                                }

                            }
                        }
                    }
                }
            }
            super.setContentType(type);
        }

        //---------- PRIVATE METHODS ---------

        private boolean setContentDisposition(Resource resource) {
            boolean contentDispositionAdded = false;
            if (!this.containsHeader(CONTENT_DISPOSTION) && this.isJcrData(resource)) {
                this.addHeader(CONTENT_DISPOSTION, CONTENT_DISPOSTION_ATTACHMENT);
                contentDispositionAdded = true;
            }
            return contentDispositionAdded;
        }

        private boolean isJcrData(Resource resource){
            boolean jcrData = false;
            if (resource!= null) {
                ValueMap props = resource.adaptTo(ValueMap.class);
                if (props.containsKey(PROP_JCR_DATA) ) {
                    jcrData = true;
                } else {
                    Resource jcrContent = resource.getChild(JCR_CONTENT_LEAF);
                    if (jcrContent!= null) {
                        props = jcrContent.adaptTo(ValueMap.class);
                        if (props.containsKey(PROP_JCR_DATA) ) {
                            jcrData = true;
                        }
                    }
                }
            }
            return jcrData;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy