Spring Security with HTTPS on CloudFoundry

后端 未结 3 1201
暗喜
暗喜 2020-12-21 08:05

I tried to access my application on CloudFoundry with the following configuration in the spring security xml



        
相关标签:
3条回答
  • 2020-12-21 08:37

    First of all, taking a step back, this (https://johnpfield.wordpress.com/2014/09/10/configuring-ssltls-for-cloud-foundry/) provides excellent context for the nature of the problem.

    The key paragraph being

    “The threat model here is that the entry point to the cloud is a high availability, secured proxy server.  Once the traffic traverses that perimeter, it is on a trusted subnet.  In fact, the actual  IP address and port number where the Tomcat application server are running are not visible from outside of the cloud. The only way to get an HTTP request to that port is to go via the secure proxy. This pattern is a well established best practice amongst security architecture practitioners.”

    Therefore, we may not want or need SSL all the way down, but read on to see how to avoid the https redirect issue when using Spring Security deployed on Cloud Foundry.

    You will have a load balancer, HAProxy or some kind of proxy terminating SSL at the boundary of your Cloud Foundry installation. As a convention, whatever you are using should be configured to set X-Forwarded-For and X-Forwarded-Proto headers. The request header “X-Forwarded-Proto" contains the value http or https depending on the original request and you need to use this header parameter for your security decisions further down the stack.

    The cleanest way to do this is at the container level, so that Spring Security behaves the same independent of deployment container. Some typical options to configure this are as follows

    1) Tomcat

    Tomcat should be configured with a RemoteIPValve as described nicely here

    The good news is that the Java buildpack for Cloud Foundry already does this for you as seen here

    2) Spring Boot (Embedded Tomcat)

    Because Tomcat is embedded, the Tomcat config in the Java buildpack will not be activated (see the buildpack Detection Criterion), and therefore some internal Spring Boot configuration is required. Luckily, it’s pretty trivial to configure as you would expect with Spring Boot and you can switch on Tomcat’s RemoteIPValve as explained here by simply defining

    server.tomcat.remote_ip_header=x-forwarded-for

    server.tomcat.protocol_header=x-forwarded-proto

    Both approaches lead to the same outcome of the Tomcat valve overriding the ServletRequest.isSecure() behaviour so that the application has no knowledge of the usage of any proxying. Note that the valve will only be used when the “X-Forwarded-Proto" header is set.

    Alternatively, if you really want to go low-level you can dig into the guts of Spring Security, as demonstrated here. As part of that effort, there are some useful findings on how to make the “X-Forwarded-Proto" header available via the Servlet API for other containers (WebLogic, JBoss, Jetty, Glassfish) shared on the comments of https://github.com/BroadleafCommerce/BroadleafCommerce/issues/424

    As an additional note, CloudFlare can also act as the SSL-terminating reverse proxy (this is the recommended approach via PWS as discussed here) and it does indeed forward the relevant headers.

    References

    https://stackoverflow.com/a/28300485/752167

    http://experts.hybris.com/answers/33612/view.html

    https://github.com/cloudfoundry/java-buildpack/commit/540633bc932299ef4335fde16d4069349c66062e

    https://support.run.pivotal.io/entries/24898367-Spring-security-with-https

    http://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html#howto-use-tomcat-behind-a-proxy-server

    0 讨论(0)
  • 2020-12-21 08:41

    I have the same issue when I tried to secure my pages with HTTPS using Spring Security.

    From the discussion on CloudFoundry Support, seems they "terminate SSL connections at the router". See "Is it possible to visit my application via SSL (HTTPS)?".

    And after more than a year, no further information I can find regarding this issue.

    0 讨论(0)
  • 2020-12-21 08:43

    In case it's still useful ... I found this post gave the clue to solve something similar to this.

    The problem was the org.springframework.security.web.access.channel.SecureChannelProcessor bean was using ServletRequest.isSecure() to decide whether to accept the connection or redirect, which was getting confused inside the cloud.

    The following override to that bean seemed to do the job under BlueMix - not sure if the $WSSC request header will apply to all environments.

    @Component
    public class ChannelProcessorsPostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
            if (bean instanceof SecureChannelProcessor) {
                final SecureChannelProcessor scp = (SecureChannelProcessor) bean;
                return new ChannelProcessor() {
                    @Override
                    public void decide(FilterInvocation invocation,
                            Collection<ConfigAttribute> config) throws IOException,
                            ServletException {
                        HttpServletRequest httpRequest = invocation.getHttpRequest();
                        // Running under BlueMix (CloudFoundry in general?), the
                        //   invocation.getHttpRequest().isSecure() in SecureChannelProcessor
                        //   was always returning false
                        if ("https".equals(httpRequest.getHeader("$WSSC"))) {
                            return;
                        }
                        scp.decide(invocation, config);
                    }
    
                    @Override
                    public boolean supports(ConfigAttribute attribute) {
                        return scp.supports(attribute);
                    }
                };
            }
    
            return bean;
        }
    
        @Override
        public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
    
            return bean;
        }
    }
    
    0 讨论(0)
提交回复
热议问题