Package com.alibaba.citrus.service.requestcontext.basic.impl

Source Code of com.alibaba.citrus.service.requestcontext.basic.impl.ResponseHeaderSecurityFilter$DefinitionParser

/*
* Copyright 2010 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed 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 com.alibaba.citrus.service.requestcontext.basic.impl;

import static com.alibaba.citrus.springext.util.SpringExtUtil.*;
import static com.alibaba.citrus.util.BasicConstant.*;
import static com.alibaba.citrus.util.ObjectUtil.*;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;

import com.alibaba.citrus.logconfig.support.SecurityLogger;
import com.alibaba.citrus.service.requestcontext.basic.CookieHeaderValueInterceptor;
import com.alibaba.citrus.service.requestcontext.basic.CookieInterceptor;
import com.alibaba.citrus.service.requestcontext.basic.HeaderNameInterceptor;
import com.alibaba.citrus.service.requestcontext.basic.HeaderValueInterceptor;
import com.alibaba.citrus.service.requestcontext.basic.RedirectLocationInterceptor;
import com.alibaba.citrus.service.requestcontext.basic.RequestContextLifecycleInterceptor;
import com.alibaba.citrus.service.requestcontext.basic.ResponseHeaderRejectedException;
import com.alibaba.citrus.service.requestcontext.basic.StatusMessageInterceptor;
import com.alibaba.citrus.service.requestcontext.util.CookieSupport;
import com.alibaba.citrus.springext.support.parser.AbstractSingleBeanDefinitionParser;
import com.alibaba.citrus.util.HumanReadableSize;
import com.alibaba.citrus.util.StringEscapeUtil;

/**
* ����header�е�crlf����status message��HTML entitiesת�壬����cookie���ܴ�С��
*
* @author Michael Zhou
*/
public class ResponseHeaderSecurityFilter implements RequestContextLifecycleInterceptor, HeaderNameInterceptor,
        HeaderValueInterceptor, CookieInterceptor, CookieHeaderValueInterceptor, StatusMessageInterceptor,
        RedirectLocationInterceptor {
    public static final HumanReadableSize MAX_SET_COOKIE_SIZE_DEFAULT = new HumanReadableSize("7k");
    private static final String COOKIE_LENGTH_ATTR = "_COOKIE_LENGTH_";
    private static final Pattern crlf = Pattern.compile("\\r\\n|\\r|\\n");
    private final SecurityLogger log = new SecurityLogger();
    private final CookieLengthAccumulator cookieLengthAccumulator;
    private HumanReadableSize maxSetCookieSize;

    public ResponseHeaderSecurityFilter() {
        this(null);
    }

    public ResponseHeaderSecurityFilter(HttpServletRequest request) {
        // ע�⣬��request�޷���@Autowired��ע�룬��Ϊ��ʱBeanPostProcessor��δ��ʼ������ͨ��constructorע���ǿ��еġ�
        assertProxy(request);

        if (request == null) {
            cookieLengthAccumulator = new ThreadLocalBasedCookieLengthAccumulator();
        } else {
            cookieLengthAccumulator = new RequestBasedCookieLengthAccumulator(request);
        }
    }

    public void setLogName(String logName) {
        log.setLogName(logName);
    }

    public HumanReadableSize getMaxSetCookieSize() {
        return maxSetCookieSize == null || maxSetCookieSize.getValue() <= 0 ? MAX_SET_COOKIE_SIZE_DEFAULT
                : maxSetCookieSize;
    }

    public void setMaxSetCookieSize(HumanReadableSize maxSetCookieSize) {
        this.maxSetCookieSize = maxSetCookieSize;
    }

    public void prepare() {
    }

    public void commit() {
        cookieLengthAccumulator.reset();
    }

    public String checkHeaderName(String name) {
        if (containsCRLF(name)) {
            String msg = "Invalid response header: " + StringEscapeUtil.escapeJava(name);
            log.getLogger().error(msg);
            throw new ResponseHeaderRejectedException(msg);
        }

        return name;
    }

    public String checkHeaderValue(String name, String value) {
        return defaultIfNull(filterCRLF(value, "header " + name), value);
    }

    public Cookie checkCookie(Cookie cookie) {
        String name = cookie.getName();

        if (containsCRLF(name)) {
            log.getLogger().error("Invalid cookie name: " + StringEscapeUtil.escapeJava(name));
            return null;
        }

        String value = cookie.getValue();
        String filteredValue = filterCRLF(value, "cookie " + name);

        if (filteredValue == null) {
            return cookie;
        } else {
            CookieSupport newCookie = new CookieSupport(cookie);
            newCookie.setValue(filteredValue);
            return newCookie;
        }
    }

    public String checkCookieHeaderValue(String name, String value, boolean setHeader) {
        if (value != null) {
            int maxSetCookieSize = (int) getMaxSetCookieSize().getValue();
            int length = cookieLengthAccumulator.getLength();

            if (length + value.length() > maxSetCookieSize) {
                log.getLogger().error(
                        "Cookie size exceeds the max value: {} + {} > maxSize {}.  Cookie is ignored: {}",
                        new Object[] { length, value.length(), getMaxSetCookieSize(), value });

                return EMPTY_STRING;
            } else {
                if (setHeader) {
                    cookieLengthAccumulator.setCookie(value);
                } else {
                    cookieLengthAccumulator.addCookie(value);
                }
            }
        }

        return value;
    }

    public String checkStatusMessage(int sc, String msg) {
        return StringEscapeUtil.escapeHtml(msg);
    }

    public String checkRedirectLocation(String location) {
        return defaultIfNull(filterCRLF(location, "redirectLocation"), location);
    }

    private boolean containsCRLF(String str) {
        if (str != null) {
            for (int i = 0; i < str.length(); i++) {
                switch (str.charAt(i)) {
                    case '\r':
                    case '\n':
                        return true;
                }
            }
        }

        return false;
    }

    /**
     * ���������CRLF���򷵻�<code>null</code>�������ȥ����CRLF���滻�ɿո�
     */
    private String filterCRLF(String value, String logInfo) {
        if (containsCRLF(value)) {
            log.getLogger().warn("Found CRLF in {}: {}", logInfo, StringEscapeUtil.escapeJava(value));

            StringBuffer sb = new StringBuffer();
            Matcher m = crlf.matcher(value);

            while (m.find()) {
                m.appendReplacement(sb, " ");
            }

            m.appendTail(sb);

            return sb.toString();
        }

        return null;
    }

    private static abstract class CookieLengthAccumulator {
        public final void addCookie(String cookie) {
            setLength(getLength() + cookie.length());
        }

        public final void setCookie(String cookie) {
            setLength(cookie.length());
        }

        public abstract int getLength();

        protected abstract void setLength(int length);

        protected abstract void reset();
    }

    private final class ThreadLocalBasedCookieLengthAccumulator extends CookieLengthAccumulator {
        private final ThreadLocal<Integer> cookieLengthHolder = new ThreadLocal<Integer>();

        @Override
        public int getLength() {
            Object value = cookieLengthHolder.get();

            if (value instanceof Integer) {
                return (Integer) value;
            } else {
                return 0;
            }
        }

        @Override
        protected void setLength(int length) {
            cookieLengthHolder.set(length);
        }

        @Override
        protected void reset() {
            cookieLengthHolder.remove();
        }
    }

    private final class RequestBasedCookieLengthAccumulator extends CookieLengthAccumulator {
        private final HttpServletRequest request;

        private RequestBasedCookieLengthAccumulator(HttpServletRequest request) {
            this.request = request;
        }

        @Override
        public int getLength() {
            Object value = request.getAttribute(COOKIE_LENGTH_ATTR);

            if (value instanceof Integer) {
                return (Integer) value;
            } else {
                return 0;
            }
        }

        @Override
        protected void setLength(int length) {
            request.setAttribute(COOKIE_LENGTH_ATTR, length);
        }

        @Override
        protected void reset() {
            request.removeAttribute(COOKIE_LENGTH_ATTR);
        }
    }

    public static class DefinitionParser extends AbstractSingleBeanDefinitionParser<ResponseHeaderSecurityFilter> {
        @Override
        protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
            attributesToProperties(element, builder, "logName", "maxSetCookieSize");
            addConstructorArg(builder, true, HttpServletRequest.class); // ����request
        }
    }
}
TOP

Related Classes of com.alibaba.citrus.service.requestcontext.basic.impl.ResponseHeaderSecurityFilter$DefinitionParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.