Skip to content

Instantly share code, notes, and snippets.

@neolaw84
Last active July 2, 2024 11:26
Show Gist options
  • Save neolaw84/9334007e67752a957394ac2408d543e8 to your computer and use it in GitHub Desktop.
Save neolaw84/9334007e67752a957394ac2408d543e8 to your computer and use it in GitHub Desktop.

Revisions

  1. neolaw84 revised this gist May 30, 2019. 5 changed files with 179 additions and 0 deletions.
    179 changes: 179 additions & 0 deletions 01_spring_boot_web_ssl_x509.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,179 @@
    # Creating a Spring Boot Web (REST) service with SSL

    We will refer to: https://github.com/jonashackt/spring-boot-rest-clientcertificate

    Full project is available at: https://github.com/neolaw84/spring_boot_web_with_ssl

    ## Situation/Problem

    To create an SSL secured web (REST) service with cliet authentication (X509) using Spring Boot.

    ## Action/Solution

    ### Enabling SSL in Server-Side

    1. We will create a private key, certificate signing request and a self-signed certificate.

    ```bash
    #!/bin/bash

    echo "generating key 1"
    openssl genrsa -des3 -out node1.key 1024

    echo "generating csr 1"
    openssl req -new -key node1.key -out node1.csr

    echo "generating certificate 1 signed by key 1"
    openssl x509 -req -days 3650 -in node1.csr -signkey node1.key -out node11.crt
    ```

    It will ask several questions including password for keystore. We will make the password 'abcd1234' for this example.

    It is very important to match First Name <concat> Last Name is the same as the host-name of your server. If you are playing in localhost, enter "localhost" as your name. (i.e. CN=localhost in verification step, where you enter 'yes').

    2. We will create a pkcs12 key-store that houses self-signed certificate node11.crt.

    ```bash
    echo "generating key-store 1 containing certificate 1 signed by key 1"
    openssl pkcs12 -export -in node11.crt -inkey node1.key -name "node1" -out node1.p12

    ```

    3. Use the following application.properties

    ```
    # The format used for the keystore. It could be set to JKS in case it is a JKS file
    server.ssl.key-store-type=PKCS12
    # The path to the keystore containing the certificate
    server.ssl.key-store=classpath:path/to/node1.p12
    # The password used to generate the certificate
    server.ssl.key-store-password=<password>
    ```

    ### Accessing the Server via RestTemplate

    1. Import the self-signed certificate to node22.jks to be used as trust-store.

    ```bash
    echo "generating trust-store 2 containing certificate 1 signed by key 2"
    keytool -import -file node11.crt -alias node1 -keystore node22.jks
    ```

    2. Use the following code-fragment:

    ```java
    @Autowired RestTemplateBuilder restTemplateBuilder;

    /**
    * This test case requires the followings to be put as VM Arguments:
    * -Djavax.net.ssl.trustStore="full/path/to/cacerts" -Djavax.net.ssl.trustStorePassword="password"
    * the one in git repo (src/main/resources/certs3/node22.jks has certificate for 'localhost' with password 'abcd1234'
    */
    @Test
    public void addTwoAndFive() {
    UriComponentsBuilder uriComponentBuilder = UriComponentsBuilder.fromHttpUrl(
    "https://localhost:8080/integer/add_two/"
    )
    .queryParam("a", new Integer(2))
    .queryParam("b", new Integer(5));
    RestTemplate restTemplate = restTemplateBuilder.build();
    String uriString = uriComponentBuilder.toUriString();
    System.out.println(uriString);
    SwoIntegerObject result = restTemplate.getForObject(
    uriString, SwoIntegerObject.class
    );
    assert(result.getInteger() == 7);
    }
    ```

    ### Enabling SSL with Client Authentication

    We will do the following steps (alternatively, just run https://github.com/neolaw84/spring_boot_web_with_ssl/blob/master/src/main/resources/certs3/gen_certs_pairs.sh)

    1. generate two private keys (node1.key and node2.key)

    2. generate two certificate signing requests (node1.csr and node2.csr)

    3. generate cross-signed certificates (node1.crt and node2.crt)

    4. generate self-signed certificates (node11.crt and node22.crt)

    5. put the cross-signed certificates into trust-stores (node1.crt to node2.jks and vice-versa)

    6. put the self-signed certificates into key-stores (node11.crt to node1.p12 and vice-versa)

    7. Use node1.p12 as keystore and node1.jks as trust-store in server. Let the client use node22.crt self-signed certificate and cross-signed certificate node1.crt (node2.p12 and node22.jks)

    ```properties
    # Define a custom port (instead of the default 8080)
    server.port=8443
    # The format used for the keystore
    server.ssl.key-store-type=PKCS12
    # The path to the keystore containing the certificate
    server.ssl.key-store=classpath:certs3/node1.p12
    # The password used to generate the certificate
    server.ssl.key-store-password=abcd1234

    # Trust store that holds SSL certificates.
    server.ssl.trust-store=classpath:/certs3/node11.jks
    # Password used to access the trust store.
    server.ssl.trust-store-password=abcd1234
    # Type of the trust store.
    server.ssl.trust-store-type=JKS
    # Whether client authentication is wanted ("want") or needed ("need").
    server.ssl.client-auth=need
    ```

    8. Run the application.

    ### Accessing the Server (that need client-authentication) via RestTemplate

    1. Use the following code-fragment (better to make the RestTemplate a bean):

    ```java
    @Autowired RestTemplateBuilder restTemplateBuilder;

    @Value(value="${server.ssl.key-store}") Resource keyStore = null;
    @Value(value="${server.ssl.trust-store}") Resource trustStore = null;

    public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {

    SSLContext sslContext = SSLContextBuilder
    .create()
    .loadKeyMaterial(keyStore.getFile(), "abcd1234".toCharArray(), "abcd1234".toCharArray())
    .loadTrustMaterial(trustStore.getFile(), "abcd1234".toCharArray())
    .build();

    HttpClient client = HttpClients.custom()
    .setSSLContext(sslContext)
    .build();

    return builder
    .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(client))
    .build();
    }

    /**
    * This test case requires the followings to be put as VM Arguments:
    * -Djavax.net.ssl.trustStore="full/path/to/cacerts" -Djavax.net.ssl.trustStorePassword="password"
    * the "node2.jks" in git repo has certificate for 'localhost' with password 'changeit'
    * @throws Exception
    * @throws RestClientException
    */
    @Test
    public void addTwoAndFive() throws RestClientException, Exception {
    UriComponentsBuilder uriComponentBuilder = UriComponentsBuilder.fromHttpUrl(
    "https://localhost:8443/integer/add_two/"
    )
    .queryParam("a", new Integer(2))
    .queryParam("b", new Integer(5));
    //RestTemplate restTemplate = restTemplateBuilder.build();
    String uriString = uriComponentBuilder.toUriString();
    System.out.println(uriString);
    SwoIntegerObject result = restTemplate(restTemplateBuilder)
    .getForObject(
    uriString, SwoIntegerObject.class
    );
    assert(result.getInteger() == 7);
    }
    ```
    File renamed without changes.
  2. neolaw84 revised this gist May 25, 2019. 2 changed files with 67 additions and 0 deletions.
    47 changes: 47 additions & 0 deletions 03_spring_boot_web_with_ssl_and_client_auth.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    # Creating a Spring Boot Web (REST) service with SSL and Client Authentication

    We will refer to: https://dzone.com/articles/securing-rest-apis-with-client-certificates

    ## Situation/Problem

    We need to set up a Spring Boot Web (REST) service with both SSL and Client Authentication (two-way authentication or X509 authentication).

    ## Action/Solution

    1. We create necessary keys, certificates and keystores.

    ```bash
    ./04_gen_certs.sh
    ```

    Note: the commands in the source (dzone) link has typos. Refer to the 04_gen_certs.sh for typo-clear version.

    In this exercise, we make sure both common names are 'localhost' and passwords are 'abcd1234'

    2. Add the following properties to application.properties

    ```properties
    # Define a custom port (instead of the default 8080)
    server.port=8443
    # The format used for the keystore
    server.ssl.key-store-type=PKCS12
    # The path to the keystore containing the certificate
    server.ssl.key-store=file:/path/to/ssl/server/keyStore.p12
    # The password used to generate the certificate
    server.ssl.key-store-password=abcd1234

    # Trust store that holds SSL certificates.
    server.ssl.trust-store=file:/path/to/ssl/server/trustStore.jks
    # Password used to access the trust store.
    server.ssl.trust-store-password=abcd1234
    # Type of the trust store.
    server.ssl.trust-store-type=JKS
    # Whether client authentication is wanted ("want") or needed ("need").
    server.ssl.client-auth=need
    ```

    3. Run the service.

    4. Install the /path/to/ssl/client/client_pavel.p12 (in windows, double-clicking will do).

    5. Try the service from browser. The browser will ask which certificate to use (you will see 'localhost' there).
    20 changes: 20 additions & 0 deletions 04_gen_certs.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    #Create folders to generate all files (separated for client and server)
    mkdir ssl && cd ssl && mkdir client && mkdir server
    ## Server
    # Generate server private key and self-signed certificate in one step
    openssl req -x509 -newkey rsa:4096 -keyout server/serverPrivateKey.pem -out server/server.crt -days 3650 -nodes
    # Create PKCS12 keystore containing private key and related self-sign certificate
    openssl pkcs12 -export -out server/keyStore.p12 -inkey server/serverPrivateKey.pem -in server/server.crt
    # Generate server trust store from server certificate
    keytool -import -trustcacerts -alias root -file server/server.crt -keystore server/trustStore.jks
    ## Client
    # Generate client's private key and a certificate signing request (CSR)
    openssl req -new -newkey rsa:4096 -out client/request.csr -keyout client/myPrivateKey.pem -nodes
    ## Server
    # Sign client's CSR with server private key and a related certificate
    openssl x509 -req -days 360 -in client/request.csr -CA server/server.crt -CAkey server/serverPrivateKey.pem -CAcreateserial -out client/pavel.crt -sha256
    ## Client
    # Verify client's certificate
    openssl x509 -text -noout -in client/pavel.crt
    # Create PKCS12 keystore containing client's private key and related self-sign certificate
    openssl pkcs12 -export -out client/client_pavel.p12 -inkey client/myPrivateKey.pem -in client/pavel.crt -certfile server/server.crt
  3. neolaw84 revised this gist May 25, 2019. 2 changed files with 0 additions and 0 deletions.
    File renamed without changes.
  4. neolaw84 revised this gist May 25, 2019. 1 changed file with 13 additions and 1 deletion.
    14 changes: 13 additions & 1 deletion client_configuration.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,13 @@
    # Configuration of Clients for the Spring Boot Web (REST) with SSL

    ## Situation/Problem

    We need a java program that can hit REST API behind SSL.

    ## Action/Solution

    We need to run java program using a trust-store (not a key-store). Here is how:

    1. Get the certificate from the web-serviec (using browser like Chrome)

    2. Create a trust-store
    @@ -39,4 +47,8 @@ public class SWOControllerViaRestTests {
    assert(result.getInteger() == 7);
    }
    }
    ```
    ```

    ## Result

    Resulting java program can hit REST API (behind SSL).
  5. neolaw84 revised this gist May 25, 2019. No changes.
  6. neolaw84 revised this gist May 25, 2019. 2 changed files with 44 additions and 0 deletions.
    42 changes: 42 additions & 0 deletions client_configuration.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    # Configuration of Clients for the Spring Boot Web (REST) with SSL

    1. Get the certificate from the web-serviec (using browser like Chrome)

    2. Create a trust-store

    ```bash
    keytool -import -alias ca -file somecert.cer -keystore cacerts -storepass changeit
    ```

    3. Start using the trust-store (for example, run the following JUnit test).

    ```java
    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class SWOControllerViaRestTests {

    @Autowired RestTemplateBuilder restTemplateBuilder;

    /**
    * This test case requires the followings to be put as VM Arguments:
    *
    * -Djavax.net.ssl.trustStore="full/path/to/cacerts" -Djavax.net.ssl.trustStorePassword="password"
    * the one in git repo has certificate for 'localhost' with password 'changeit'
    */
    @Test
    public void addTwoAndFive() {
    UriComponentsBuilder uriComponentBuilder = UriComponentsBuilder.fromHttpUrl(
    "https://localhost:8080/integer/add_two/"
    )
    .queryParam("a", new Integer(2))
    .queryParam("b", new Integer(5));
    RestTemplate restTemplate = restTemplateBuilder.build();
    String uriString = uriComponentBuilder.toUriString();
    System.out.println(uriString);
    SWOIntegerObject result = restTemplate.getForObject(
    uriString, SWOIntegerObject.class
    );
    assert(result.getInteger() == 7);
    }
    }
    ```
    2 changes: 2 additions & 0 deletions spring_boot_web_with_ssl.md
    Original file line number Diff line number Diff line change
    @@ -16,6 +16,8 @@ keytool -genkeypair -alias qbpo -keyalg RSA -keysize 2048 -storetype PKCS12 -key

    It will ask several questions including password for keystore. We will make the password 'abcd1234' for this example.

    It is very important to match First Name <concat> Last Name is the same as the host-name of your server. If you are playing in localhost, enter "localhost" as your name. (i.e. CN=localhost in verification step, where you enter 'yes').

    2. We will put the following properties in the application.properties to so that generated keystore will be used by the app.

    ```properties
  7. neolaw84 created this gist May 25, 2019.
    36 changes: 36 additions & 0 deletions spring_boot_web_with_ssl.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    # Creating a Spring Boot Web (REST) service with SSL

    We will refer to: https://www.baeldung.com/spring-boot-https-self-signed-certificate

    ## Situation/Problem

    To create an SSL secured web (REST) service using Spring Boot.

    ## Action/Solution

    1. We will create a pkcs12 keystore containing key qbpo.

    ```bash
    keytool -genkeypair -alias qbpo -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore qbpo_java.p12 -validity 3650
    ```

    It will ask several questions including password for keystore. We will make the password 'abcd1234' for this example.

    2. We will put the following properties in the application.properties to so that generated keystore will be used by the app.

    ```properties
    # The format used for the keystore. It could be set to JKS in case it is a JKS file
    server.ssl.key-store-type=PKCS12
    # The path to the keystore containing the certificate
    server.ssl.key-store=classpath:qbpo_java.p12
    # The password used to generate the certificate
    server.ssl.key-store-password=abcd1234
    # The alias mapped to the certificate
    server.ssl.key-alias=qbpo
    ```

    3. Run the application.

    ## Results

    The resulting application is using the keystore and SSL secured (https).