Override the ChannelProcessingFilter with Spring Security 3.0.5 does not work

后端 未结 3 869
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-06 03:17

The default behavior of the Channel Processors is to do a sendRedirect (which is redirect temporary with 302 code). I need to change this behavior so that a permanent (301) redi

相关标签:
3条回答
  • 2021-02-06 03:40

    I found another way to achieve the same thing with much less code and complexity. You can simply use a BeanPostProcessor to get the SecureChannelProcessor and InsecureChannelProcessor and then set your own entry point on them. That way, you can still use the defaults on everything else.

    The BeanPostProcessor:

    @Component
    public class ChannelProcessorsPostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
    
            if (bean instanceof SecureChannelProcessor) ((SecureChannelProcessor)bean).setEntryPoint(new MyEntryRetryPoint("https://", 443));
            else if (bean instanceof InsecureChannelProcessor) ((InsecureChannelProcessor)bean).setEntryPoint(new MyEntryRetryPoint("http://", 80));
    
            return bean;
        }
    
        @Override
        public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
    
            return bean;
        }
    }
    
    0 讨论(0)
  • 2021-02-06 03:41

    I think it's better to write a redirect strategy:

    @Component
    public class PermanentRedirectStrategy implements RedirectStrategy {
        private boolean contextRelative;
    
        @Override
        public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
            response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
            response.setHeader("Location", response.encodeRedirectURL(calculateRedirectUrl(request.getContextPath(), url)));
        }
    
        /**
         * Unfortunately DefaultRedirectStrategy.calculateRedirectUrl is private
         * If this weren't the case, we could extend this class from DefaultRedirectStrategy
         * to use its method directly without copying it
         */
        private String calculateRedirectUrl(String contextPath, String url) {
            if (!UrlUtils.isAbsoluteUrl(url)) {
                if (contextRelative) {
                    return url;
                } else {
                    return contextPath + url;
                }
            }
    
            // Full URL, including http(s)://
    
            if (!contextRelative) {
                return url;
            }
    
            // Calculate the relative URL from the fully qualified URL, minus the last
            // occurence of the scheme and base context
            url = url.substring(url.lastIndexOf("://") + 3); // strip off scheme
            url = url.substring(url.indexOf(contextPath) + contextPath.length());
    
            if (url.length() > 1 && url.charAt(0) == '/') {
                url = url.substring(1);
            }
    
            return url;
        }
    }
    

    and then setting it to the existing entry point:

    @Component
    public class ChannelProcessorsPostProcessor implements BeanPostProcessor {
        @Autowired
        private RedirectStrategy permanentRedirectStrategy;
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            ChannelEntryPoint entryPoint = null;
    
            if (bean instanceof SecureChannelProcessor) {
                entryPoint = ((SecureChannelProcessor) bean).getEntryPoint();
            } else if (bean instanceof InsecureChannelProcessor) {
                entryPoint = ((InsecureChannelProcessor) bean).getEntryPoint();
            }
    
            if (entryPoint != null && AbstractRetryEntryPoint.class.isAssignableFrom(entryPoint.getClass())) {
                ((AbstractRetryEntryPoint) entryPoint).setRedirectStrategy(permanentRedirectStrategy);
            }
    
            return bean;
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    }
    
    0 讨论(0)
  • 2021-02-06 03:52

    Solution:

    The issue is that we cannot have both the security:http as well as the myChannelProcessingFilter (the one I had overridden) to deal with the access argument of the security:intercept-url, hence I removed the http tag and added the access thing in the myChannelProcessingFilter, where I wanted it to process. The XML that resolved it is follows

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:security="http://www.springframework.org/schema/security"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:util="http://www.springframework.org/schema/util"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
              http://www.springframework.org/schema/security
              http://www.springframework.org/schema/security/spring-security-3.0.3.xsd
              http://www.springframework.org/schema/util
              http://www.springframework.org/schema/util/spring-util.xsd">
    
        <!-- 
            The http element responsible for creating a FilterChainProxy and the filter beans which it uses. 
            Common problems like incorrect filter ordering are no longer an issue as the filter positions are predefined. 
        -->
        <security:http auto-config="false" 
                entry-point-ref="authenticationProcessingFilterEntryPoint" 
                access-decision-manager-ref="accessDecisionManager" >
    
            <security:custom-filter position="CHANNEL_FILTER" ref="channelProcessingFilter"/>
    
            <security:intercept-url pattern="/*.html*" access="ROLE_ANONYMOUS,admin,user"  />
            <security:intercept-url pattern="/*.jsp" access="ROLE_ANONYMOUS,admin,user" />
            <security:intercept-url pattern="/**/*.html**" access="ROLE_ANONYMOUS,user,admin" />
    
    
        </security:http>
    
        <bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter">
          <property name="channelDecisionManager" ref="channelDecisionManager"/>
          <property name="securityMetadataSource">
            <security:filter-security-metadata-source path-type="ant">
                <security:intercept-url pattern="/*.jsp**" access="REQUIRES_SECURE_CHANNEL" />
                <security:intercept-url pattern="/**/*.html**" access="REQUIRES_SECURE_CHANNEL" />
            </security:filter-security-metadata-source>
          </property>
        </bean>
    
        <bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl">
            <property name="channelProcessors">
                <list>
                    <ref bean="secureProcessor"/>
                    <ref bean="insecureProcessor"/>
                </list>
            </property>
        </bean>
    
        <bean id="secureProcessor" class="org.springframework.security.web.access.channel.SecureChannelProcessor" >
            <property name="entryPoint" ref="retryWithHttps"/>
        </bean>
    
        <bean id="insecureProcessor" class="org.springframework.security.web.access.channel.InsecureChannelProcessor">
            <property name="entryPoint" ref="retryWithHttp"/>
        </bean>
    
        <bean id="retryWithHttps" class="com.my.webapp.filter.RetryWithHttpsEntryPoint" />
        <bean id="retryWithHttp" class="com.my.webapp.filter.RetryWithHttpEntryPoint" />
    
    </beans>
    
    0 讨论(0)
提交回复
热议问题