Skip to content

Lab M02P03-Server

The communication over HTTP with TLS is standard nowadays. You can easily enable TLS in Spring boot application. To do so, you need X.509 SSL certificate which is signed by trusted authority like Comodo, or ZeroSSL. You can easily generate SSL certificate for testing purposes using Java or openssl tool. This lab helps you to understand required steps how to secure HTTP communication chanel for your application.

It consists of two parts: * Server side configuration * Example of client with certificate authentication with mutual TLS

Part I - The Server

Web server as Tomcat can be configured to accept HTTPS connections only. Spring Boot support embedded web servers, and also simplifies SSL configuration of a server using server.ssl.* properties. You need also server certificate. Following steps wil guide you through the process of adding TLS on top of HTTP.

  1. For this lab or dev purposes, you can crete self-signed server certificate. You will need openssl tools. The openssl is part of every Linux distribution, or you can use gitbash on Windows, which is part of git for Windows installation.

  2. Execute next commands to generate required artifacts. Note: the winpty command is used to fix openssl stuck issue for Windows version (gitbash) For simplicity use password whenever you are asked to provide password. For server certificate CN use localhost, and for key alias use also localhost.

    a) Generate self-signed CA certificate:

      winpty openssl req -x509 -sha256 -days 3650 -newkey rsa:4096 -keyout rootCA.key -out rootCA.crt
    

    b) Certificate signing request (CSR) for server certificate:

      winpty openssl req -new -newkey rsa:4096 -keyout localhost.key -out localhost.csr
    
    and config file localhost.ext:
      authorityKeyIdentifier=keyid,issuer
      basicConstraints=CA:FALSE
      subjectAltName = @alt_names
      [alt_names]
      DNS.1 = localhost
    

    c) Sign the request with rootCA.crt certificate and its private key:

      winpty openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in localhost.csr -out localhost.crt -days 365 -CAcreateserial -extfile localhost.ext
    
    and check the request:
     winpty openssl x509 -in localhost.crt -text
    

    d) Create PKCS12 keystore:

      winpty openssl pkcs12 -export -out localhost.p12 -name "localhost" -inkey localhost.key -in localhost.crt
    
    If you like to use Java JKS as keystore, convert keystore with this command:

      keytool -importkeystore -srckeystore localhost.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS
    
  3. Copy keystore file localhost.p12 into resource folder.

  4. Add following configuration into application.yaml

      server:
        port: 8443
      ssl:
        keyAlias: "localhost"
        key-store: "classpath:localhost.p12"
        key-store-password: "password"
        key-store-type: "PKCS12"
    
    5. Now start the application, and test API with postman. The server is accessible on [https://localhost:8443]. The server certificate is not trusted as it is not signed by trusted authority. You can import Root CA certificate into browser to make server certificate to be trusted.

  5. There is still Basic HTTP Authentication used in the application. So let's switch to X.509 client certificate authentication. With help of the Spring Security the implementation of x.509 authentication is matter of configuration of the SecurityFilterChain where required Authentication filter is added. So change httpBasic() to x509(). Modify the SecurityFilterChain bean in SecurityConfig as following:

      @Bean
      public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    
        http
            .authorizeHttpRequests((authz) -> authz
                .requestMatchers("/library/**").authenticated()
                   .anyRequest().permitAll()
            )
        .x509(customize -> customize.subjectPrincipalRegex("CN=(.*?)(?:,|$)"));
    
        return http.build();
    }
    
    7. Application uses trust store to read Root CA from for client certificate validation if mutual TLS is configured. Execute following Java keytool commands to create trust store for server. Trust store creation:

      keytool -import -trustcacerts -noprompt -alias ca -ext san=dns:localhost,ip:127.0.0.1 -file rootCA.crt -keystore truststore.jks
    

    Converting JKS to PCKS12:

      keytool -importkeystore -srckeystore truststore.jks -destkeystore truststore.p12 -srcstoretype JKS -deststoretype PKCS12 -deststorepass password
    
    Copy the truststore.p12 into resource folder.

  6. Add also following configuration into application.yaml under server:ssl section.

    yaml server: ssl: trust-store: "classpath:truststore.jks" trust-store-password: "password" client-auth: "need"

  7. Restart application and try to access API. You can use web browser. What is the result?

Part II - The Client

Spring Boot provides the concept of SSL bundles for configuring and consuming custom SSL trust material, such as keystores, certificates, and private keys. Once configured, a bundle can be applied to one or more connections using configuration properties or APIs. The programmatic configuration of HTTP Client to add SSL Context is also not a big deal. Check m02p03-security-https-client-lab how to implement API client with mutual TLS using Spring Boot and RestTemplate.

Every client needs its own client certificate issued by CA (Certificate Authority).

  1. Client certificate generation for username=user@email.com. Use user@email.com as CN:

      winpty openssl req -new -newkey rsa:4096 -nodes -keyout clientUser.key -out clientUser.csr
    

    Sign client certificate with root CA (created in Part I.):

      winpty openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in clientUser.csr -out clientUser.crt -days 365 -CAcreateserial
    

    Create client store with certificate and key:

      winpty openssl pkcs12 -export -out clientUser.p12 -name "clientUser" -inkey clientUser.key -in clientUser.crt
    

  2. Postman as client. You can test API call with mutual TLS, if you set certificates in Postman tool configuration.