Skip to content

Instantly share code, notes, and snippets.

@wilsonkhlam
Last active August 31, 2020 10:13
Show Gist options
  • Save wilsonkhlam/41fa17e08382a23b0173985e56b10696 to your computer and use it in GitHub Desktop.
Save wilsonkhlam/41fa17e08382a23b0173985e56b10696 to your computer and use it in GitHub Desktop.
Passing SSL and Client Cert Authentication Data to Tomcat through HTTP Headers
global
log stdout format raw daemon
maxconn 2000
daemon
defaults
mode http
option dontlognull
retries 3
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http-in
bind *:443 ssl crt /ssl-cert/server-combined.pem ca-file /ssl-cert/ca/client-intermediate/certs/client-intermediate.crt ca-verify-file /ssl-cert/ca/root/certs/root.crt verify optional ssl-min-ver TLSv1.2 no-tls-tickets
bind *:80
default_backend webservers
mode http
option httplog
log stderr format raw daemon
frontend monitoring-in
bind *:8080
default_backend monitoring
mode http
option httplog
log stderr format raw daemon
backend monitoring
stats enable
stats auth admin:admin
stats uri /haproxy?stats
backend webservers
balance roundrobin
option forwardfor
http-request del-header ssl_client_cert
http-request del-header ssl_cipher
http-request del-header ssl_session_id
http-request del-header ssl_cipher_usekeysize
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-request set-header ssl_client_cert -----BEGIN\ CERTIFICATE-----\ %[ssl_c_der,base64]\ -----END\ CERTIFICATE-----\ if { ssl_fc_has_crt }
http-request set-header ssl_cipher %[ssl_fc_cipher] if { ssl_fc }
http-request set-header ssl_session_id %[ssl_fc_session_id,hex] if { ssl_fc }
http-request set-header ssl_cipher_usekeysize %[ssl_fc_alg_keysize] if { ssl_fc }
option http-server-close
option tcp-check
server srv1 tomcat:8080 check port 8080
@wilsonkhlam
Copy link
Author

On Tomcat side, the following should be enabled:

  1. SSLValve at engine level
  • Tomcat XML config:
 <Engine ...>
   <Valve className="org.apache.catalina.valves.SSLValve" />
   <Host ... />
 </Engine>
  • Spring Boot embedded Tomcat:
@Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> reverseProxySslValveCustomizer() {
     return factory -> {
          // Populate SSL information from reverse proxy to javax.servlet.request.* attribute
          // so that SSLAuthentication can perform authentication
        factory.getEngineValves().add(new SSLValve());
     };
}
  1. For Mutual Authentication Only
  • Tomcat XML config

web.xml

<login-config>
     <auth-method>CLIENT-CERT</auth-method>
</login-config>

server.xml

<Realm className="org.apache.catalina.realm.AuthenticatedUserRealm"/>

AuthenticatedUserRealm is the simplest one. You may use other realms if you need to load user roles from database or LDAP

To customize user name (e.g. use CN only instead of full Subject DN from the certificate), you may implement your own org.apache.catalina.realm.X509UsernameRetriever and set the class name through x509UsernameRetrieverClassName in realm setting.

  • Spring Boot embedded Tomcat:
@Bean public TomcatContextCustomizer tomcatContextCustomizer() {
     return context -> {
          AuthenticatedUserRealm realm = new AuthenticatedUserRealm();
          // realm.setX509UsernameRetrieverClassName(CnOnlyX509UsernameRetriever.class.getName());
          context.setRealm(realm);

          // enable to perform authentication even outside security constraints
          context.setPreemptiveAuthentication(true);
     };	
}
		
@Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> reverseProxyClientAuthCustomizer() {
     return factory -> {
	  // Work with AuthenticatedUserRealm to populate request.getUserPrincipal, request.getRemoteUser 
          factory.getContextValves().add(new SSLAuthenticator());
     };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment