Search code examples
spring-bootspring-securitycloud-foundrymutual-authentication

Spring boot x509 testing - pcf


In Cloud Foundry I have it configured so that a client certificate is forwarded to my spring boot application.

The certificate is placed in a x-forwarded-client-cert header, the spring boot application reads this?, and checks if the CN is whitelisted and sends the appropriate response. Unfortunately I am unable to replicate this behavior via a test. I keep on getting (in debug output):

"no client certificate found in request"

I'm using REST Assured and my test looks like this:

String cert = StreamUtils.copyToString(
  new ClassPathResource("certs/client/client_mod.crt").getInputStream(), Charset.defaultCharset());

cert = cert.replace("\r\n", "").replace("\n", "");

given()
  .spec(spec)
  .header("x-forwarded-client-cert", cert)
  .when()
  .get(HealthResource.BASE_URL + "/ip-reverse-lookup")
  .then()
  .statusCode(HttpStatus.OK.value());

The base uri for this is http://localhost. The client certificate "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" has been removed and the newlines are removed (as you can see in the code above).

In my application.yml I have this:

server:
  ssl:
    enabled: false
    key-store:
    key-store-password:
    trust-store:
    trust-store-password:
    client-auth: need

The configure method of the class that extends WebSecurityConfigurerAdapter looks like this:

http
  .x509()
  .subjectPrincipalRegex("CN=(.*?)(?:,|$)")
  .userDetailsService(customUserDetailsService)
  .and()
  .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
  .and()
  .csrf().disable();

Any help/suggestions would be appreciated.

Thanks.


Solution

  • Due to the containerization and networking architecture you need to take the following points into consideration for your implementation & test.

    When you configure Cloud Foundry to check client certificates (if present) to be trustable, they will be checked against the trusted CAs / Certificates. This is done on the HAProxy of the general networking components of the CF landscape. And as you are correctly stating, it is (if included and trusted) put into the x-forwarded-client-cert which is secured to be not mutable from the outside.

    Your application runs in a container on a lower level and is connected to its public hostname / url via the HAProxy / GoRouter. When the request reaches your application, at this point there is no longer a certificate on TLS level (mTLS to be precise). The SSL connection is terminated on the HAProxy. Internally your application / container receives the request as HTTP. See for more details [1] [2]

    So your Spring Application just receives the information about the X.509 / mTLS certificate in the header added to the request. Therefore it does not make sense to add / configure x509 support to the Spring application, as no real mTLS will ever reach the endpoint. That is also the reason why you receive the log message posted above. Rather you need to get your application to read out the header and do your logic based on it.