spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.23k stars 40.7k forks source link

Support Apache Tomcat SSLValve #8755

Closed mmoayyed closed 7 years ago

mmoayyed commented 7 years ago

Hello,

I looked around in the docs/code and failed to find a reference to this particular request, so here it goes: is Spring Boot interested in receiving a pull request that adds support for Apache Tomcat's SSL_Valve?

We are currently customizing the embedded container instance ourselves (via Boot 1.5.2) to insert the valve, and I am wondering if this might be something you may want to offer via Boot directly.

Thank you.

philwebb commented 7 years ago

@mmoayyed How complicated was your customization code? My initial feeling is that we might not want to add support directly for Boot if it's not too hard to do with a customizer.

mmoayyed commented 7 years ago

It was quite simple actually; I believe our use case had to do with X509 authentication or some such.

We have also added a few other customizations to enable AJP as well as the ability to have the container listen on yet another port other than server.port based on available recipes. I'd be happy to contribute these back as well if you find usefulness in them. Less code for us, and perhaps more capabilities for Boot?

mmoayyed commented 7 years ago

PS Pinging @hdeadman as well, since he was the one who proposed the request initially to me and might be able to explain the case better than I could.

philwebb commented 7 years ago

I'm not sure to be honest. It's a difficult balance as to when we add direct support or when we recommend the use of a customizer. More recently we've tried to shy away from any change what can't be uniformly applied across all servlet containers.

It rather depends on how common the use-case is and if it's something we think many other users will benefit from. If it's not an oft-requested feature we'll generally leave it out of Boot (less for us to maintain and test).

hdeadman commented 7 years ago

I submited a pull request to CAS https://github.com/apereo/cas/pull/2484 that only supported Tomcat because I figured that if in the future, someone came to CAS and requested similar support for Jetty or Undertow, at that point it might be worth requesting that the feature be added to Spring boot.

I don't know what the Jetty equivalent of a valve is but the SSLValve could probably be implemented as a servlet filter since it just takes a base 64 encoded certificate off of an HTTP header and puts a Certificate object on the request where the servlet spec expects it to be. I remember someone complaining that it's parsing logic wasn't very forgiving but it works if you set the header right on the load balancer.

This is what haproxy config looks like, it requests client cert and puts cert on header in format that SSLValve can parse.

frontend web-vip
   bind 192.168.2.10:443 ssl crt /var/lib/haproxy/certs/www.example.com.pem ca-file /var/lib/haproxy/certs/ca.pem verify optional
   mode http
   acl www-cert ssl_fc_sni if { www.example.com }
   acl empty-path path /
   http-request redirect location /cas/ if empty-path www-cert
   http-request del-header ssl_client_cert unless { ssl_fc_has_crt }
   http-request set-header ssl_client_cert -----BEGIN\ CERTIFICATE-----\ %[ssl_c_der,base64]\ -----END\ CERTIFICATE-----\  if { ssl_fc_has_crt }
   acl cas-path path_beg -i /cas
   reqadd X-Forwarded-Proto:\ https
   use_backend cas-pool if cas-path

 backend cas-pool
   option httpclose
   option forwardfor
   cookie SERVERID-cas insert indirect nocache
   server cas-1 192.168.2.10:8080 check cookie cas-1

Important line is:

http-request set-header ssl_client_cert -----BEGIN\ CERTIFICATE-----\ %[ssl_c_der,base64]\ -----END\ CERTIFICATE-----\  if { ssl_fc_has_crt }

On a Big-IP F5 SSL Proxy you can write in an i-rule:

HTTP::header insert "ssl_client_cert" [X509::whole [SSL::cert 0]]

and that will also be handled by the SSLValve.

If you are doing X509 authentication, the client cert request usually happens at the proxy/load balancer and communicating it to the app server via an HTTP header is a fairly easy way to get it there if the app server knows how to reconstitute it.

Does spring boot ever add filters to the application? If so, could the SSLValve be turned into a filter (that ran pre-security filters) so it would work on all containers?

http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/7.0.0/org/apache/catalina/valves/SSLValve.java

philwebb commented 7 years ago

Having discussed this a little we'd prefer to not add direct support at this time. The customizers provide a nice escape hatch and we'd like to keep the surface area of the code we need to support as small as possible.

Thanks anyway for the suggestion.