21

How can I make a GET call using Rest-Assured in java to a endpoint which requires certificate. I have certificate as .pem format. In PEM file there is certificate and private key.

rohitkadam19
  • 1,734
  • 5
  • 21
  • 39
  • I tried to convert it to jks and used in RestAssured.keystore(jks, "passwrd") but it's giving error - PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target – rohitkadam19 Apr 01 '16 at 09:49
  • Are you using the latest version of 2.9.0? – Johan Apr 14 '16 at 19:58
  • @Johan Yes, using latest version 2.9.0 – rohitkadam19 Apr 15 '16 at 11:56
  • Have you followed the instructions here: http://static.javadoc.io/com.jayway.restassured/rest-assured/2.9.0/com/jayway/restassured/config/SSLConfig.html – Johan Apr 15 '16 at 12:35
  • Hi @Johan, Yes. I exactly followed same steps, but no success. My PEM file has certificate and private key. If you could give sample script with PEM file details. It will be helpful. Thanks! – rohitkadam19 Apr 19 '16 at 09:49
  • Did any find resolution to this? – ARK Sep 20 '17 at 01:48
  • @AkshayrajKore If you follow my answer below you may get it working. – rohitkadam19 Sep 26 '17 at 09:54
  • @rohitkadam19 What is difference between the different keystores.. PKCS12, JKS etc. How do I get the PKCS12 keystore? – ARK Sep 29 '17 at 02:41

11 Answers11

30

In my case using "relaxed HTTPs validation" fixed my problem:

given().relaxedHTTPSValidation().when().post("https://my_server.com")
Saeed Zarinfam
  • 9,818
  • 7
  • 59
  • 72
  • 7
    From what I can see, this simply disables the SSL checking, so it neither sends a client cert nor checks the remote server's cert. – DaveyDaveDave Jul 17 '19 at 09:55
  • Only use this if you want to completely disable the check. – Nicholas DiPiazza Apr 16 '21 at 20:00
  • @DaveyDaveDave - What are the disadvantages of using this approach, especially in accessing a company's apis via a vpn ? – MasterJoe May 20 '21 at 22:59
  • @NicholasDiPiazza - What are the disadvantages of using this approach, especially in accessing a company's apis via a vpn ? – MasterJoe May 20 '21 at 22:59
  • 1
    @MasterJoe the disadvantage is that it's not using HTTPS, so you requests are vulnerable to MITM attacks. Whether this is a concern for you on your VPN is for you and your team to answer. – DaveyDaveDave May 21 '21 at 12:50
13

Got it working with following code -

KeyStore keyStore = null;
SSLConfig config = null;

try {
        keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(
                new FileInputStream("certs/client_cert_and_private.p12"),
                password.toCharArray());

    } catch (Exception ex) {
        System.out.println("Error while loading keystore >>>>>>>>>");
        ex.printStackTrace();
    }

    if (keyStore != null) {

        org.apache.http.conn.ssl.SSLSocketFactory clientAuthFactory = new org.apache.http.conn.ssl.SSLSocketFactory(keyStore, password);

        // set the config in rest assured
        config = new SSLConfig().with().sslSocketFactory(clientAuthFactory).and().allowAllHostnames();

RestAssured.config = RestAssured.config().sslConfig(config);
RestAssured.given().when().get("/path").then();
rohitkadam19
  • 1,734
  • 5
  • 21
  • 39
  • 1
    I am trying the same thing... Can you tell me how did you get the certificate for the endpoint? – Harish Talanki Sep 10 '16 at 20:36
  • @HarishTalanki I got certificates from developer – rohitkadam19 Feb 07 '17 at 07:48
  • I had a workaround for this. But, I really appreciate your response. Thanks. – Harish Talanki Feb 08 '17 at 01:50
  • Does this really place an https request, in my tests I need to explicitly set the protocol as when().get("https:...")... otherwise http is used. – ITomas Mar 25 '18 at 21:21
  • @rohitkadam19 why is .p12 file loaded into keystore? Shouldn't it be truststore? isn't .p12 file normally contains certificate(public key)? – user1559625 May 02 '19 at 11:36
  • This didn't work for me, I'm not sure of the cause, but I needed to create a truststore too, with the remote certificate chain, and include that in creating the `SSLSocketFactory`, otherwise I found the RestAssured was testing for the presence of a truststore and, when it didn't find one, assuming that I didn't want the client certs either, so never sending them with the request. Once I'd added the truststore, then everything else in this answer worked fine. – DaveyDaveDave Jul 17 '19 at 09:28
  • SSLSocketFactory is deprecated, we need to use SSLConnectionSocketFactory – Peter S. Sep 29 '20 at 11:27
  • @rohitkadam19 - why did you not use the top voted answer ? https://stackoverflow.com/a/37436519/6648326 – MasterJoe May 20 '21 at 23:00
  • @PeterS. but the SSLConnectionSocketFactory is not supported by RestAssured SSLConfig, or am I wrong? – MrNobody Jun 10 '22 at 09:36
4

I am new to rest-assured but I know this kind of problems using digital certificates for client authentication

In rest-assured doc is only an option to configure certificate: JKS

RestAssured.config = RestAssured.newConfig().sslConfig(new SSLConfig("/truststore_javanet.jks", "test1234");

Convert your PEM to JKS. Open it with portecle and ensure that the password is right and you have the certificate loaded and all the certification chain to CA root. Portecle simplify the command-line using a GUI and also allows you to create the JKS

http://portecle.sourceforge.net/

This error occurs ALWAYS when your java client do not trust in server certificate

 PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

The easiest way to fix this is include the server certificate chain in your jdk keystore.

First, download the server certificates opening an https connection with your browser, for example with chrome. It does not matter it fails. Click on the green lock in the toolbar>Detail>See server certicate and download as PEM. It is best to download it yourself to make sure you are using the correct. Download all certificates of certification chain enter image description here

Then, open jdk cacerts at JDK_HOME/jre/lib/security with portecle. Password will be 'changeit'. Add the server certificates as 'trusted'

Now, PKIX path building failed will dissapear. If not, check the certificates and the JDK you are using

pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • I tried this, but it's saying "No required SSL certificate was sent". I am creating keystore and adding it to RestAssured. – rohitkadam19 May 25 '16 at 09:42
  • In an SSL handshake, the certificate authentication request OCCURS after the verification of the server certificatepor, Therefore, the first step is passed. Are you sure your JKS certificate is accepted by the server? Is there errors of incorrect password or JKS not found? – pedrofb May 25 '16 at 10:00
2

The code mentioned below just works,

public static void getArtifactsHttps(String args) {
    String username = "username";
    String password1 = "password";
    StringBuilder authorization = new StringBuilder();
    authorization.append(username).append(":").append(password);
    String authHeader = "Basic " + Base64.getEncoder().encodeToString(authorization.toString().getBytes());


    String response = RestAssured
            .given()
            .trustStore("D:\\workspace\\DemoTrust.jks", "DemoTrustKeyStorePassPhrase")
            .when()
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON)
            .header("Authorization", authHeader)
            .baseUri("https://server.us.oracle.com:55898")
            .queryParam("name", args)
            .get("/validendpoint").prettyPrint();

    System.out.println("RESPONSE" + response);
}
forkdbloke
  • 1,505
  • 2
  • 12
  • 29
2

The method using org.apache.http.conn.ssl.SSLSocketFactory is now deprecated. If you are using the latest version of RestAssured from io then the best method is to set your authentication using:

    RestAssured.authentication =
        RestAssured.certificate(
            "/path/to/truststore",
            "trust store password",
            "/path/to/p12",
            "p12 password",
            CertificateAuthSettings.certAuthSettings());

Note, CertificateAuthSettings.certAuthSettings() uses default KeyStore settings, so be aware of this.

JCollerton
  • 3,227
  • 2
  • 20
  • 25
1

Using RestAssured 3.0 I took @rohitkadam19's code and got it working so:

@Before
public void setUp() throws Exception {
    try {
        RestAssured.port = port;
        RestAssured.useRelaxedHTTPSValidation();
        RestAssured.config().getSSLConfig().with().keyStore("classpath:keystore.p12", "password");
    } catch (Exception ex) {
        System.out.println("Error while loading keystore >>>>>>>>>");
        ex.printStackTrace();
    }
}
Jacques Koorts
  • 1,819
  • 1
  • 17
  • 10
  • 1
    It seems RestAssured creates the socket factory straight away with a null keystore when you call `useRelaxedHTTPSValidation()`, so will ignore whatever keystore you try to set before/after that. When I tried configuring using: `.with().keystore(...).and().truststore(...)` it worked though. – Tim Jul 27 '18 at 05:19
1

You need to allow self-signed certificate for RestAssured client. To do so, you need to place your certificate (public key) to the truststore (not keystore).

RestAssured
  .config()
  .sslConfig(
    sslConfig().with().trustStoreType("PKCS12").and()
      .trustStore(ResourceUtils.getFile("classpath:keystore/keystore.p12"), "password"));
StasKolodyuk
  • 4,256
  • 2
  • 32
  • 41
0

//headerMap is map of header Get

Response response = given().headers(headerMap)
.config(RestAssuredConfig.config().decoderConfig(DecoderConfig.decoderConfig().defaultContentCharset("UTF-8")).and().sslConfig(new SSLConfig().relaxedHTTPSValidation())) .contentType(ContentType.JSON).when().get(url).then().extract().response();

Post

response =   given().headers(headerMap) .config(RestAssuredConfig.config().decoderConfig(DecoderConfig.decoderConfig().defaultContentCharset("UTF-8")).and().sslConfig(new SSLConfig().relaxedHTTPSValidation()))
.contentType(ContentType.JSON).body(body).when().post(url).then().extract().response();
Tested
  • 11
  • 2
0

This worked for me, thank you everyone. I am using RestAssured v 3.0, this is for Post but we can just change that to .get() and removed .body(...)

    ResponseSpecification responseSpec = null;
    Response response123 = null;
    
    RestAssured.config = RestAssured.config().sslConfig(
            new SSLConfig().keystore("app trust.jks", password)
                    .keystore("key trust.jks", password));
    
    responseSpec = given()
            .urlEncodingEnabled(Encode url = true or false)
            .body(BodyToPOST)
            .config(RestAssured.config())
            .contentType("application/json")
            .headers(appropriate headers)
            .expect()
            .statusCode(200);
    
    response123 = responseSpec.when()
            .post(url)
            .then()
            .extract()
            .response();
shoes_on
  • 1
  • 1
0

I had no luck with pretty much any of these answers on 4.3.3 version of RestAssured.

I finally discovered this: RestAssured.trustStore(truststoreFilePath, password)

Usage:

String truststore = Props.getStringProperty("truststore", ""); // truststore in jks format
if (StringUtils.isNotBlank(truststore)) {
    File truststoreFile = new File(truststore);
    if (!truststoreFile .exists()) {
        throw new RuntimeException("Could not initialize the truststore 
 because file specified does not exist: " + truststore);
    }
    String password = Props.getStringProperty("truststorePassword", "changeit");
    RestAssured.trustStore(truststoreFile.getAbsolutePath(), password);
}

Now

RestAssured.given()
    .auth().basic(Props.getStringProperty("user"), Props.getStringProperty("authToken"))
    .with().config(RestAssured.config().connectionConfig(new ConnectionConfig())).when().get("/my-service")

Has no more SSL handshake issues.

Nicholas DiPiazza
  • 10,029
  • 11
  • 83
  • 152
0

To understand the scenario, you must be looking into this answer if the server, which you are making a request to, is configured with a self-signed SSL certificate. Trust SSL certificates are automatically validated by the browser with the help of CA(Certificate Authorities), but if it is a self-signed SSL we must configure truststore to the rest client(rest assured in this case).

What is the truststore?

Truststore is kind of vault in which you place certificates which you believe are valid, to explain further, the process involved in https validation is similar to the following steps,

  1. You make request to the server
  2. Server sends a certificate
  3. Now it is clients responsibility to validate the certificate, if it was trust SSL, then browser/ http client approaches CA to validate certificate's authenticity, but since it is self signed SSL, we have to configure the http client that whom it should approach for validating certificate and that configuration is truststore's configuration

Now to complete the configuration and make the http call, follow these steps

  1. Create a truststore file with extension "jks" in your project, have to configure the password while creating the jks file.
  2. Download the certificate from the browser or use the created certificate(both are same), certificate extension is usually "pem" or "crt"
  3. Now we need to import the certificate into the truststore(*.jks file), run the below command in the terminal

keytool -importcert -alias "[[alias for certificate]]" -file [[Certificate name]].pem -keystore [[truststore name]].jks -storepass [[truststore password]]

  1. Now we need to configure Rest assured that it should use this truststore for https validation

given().config(newConfig().sslConfig(new SSLConfig("/truststore.jks", "truststorepassword")))

We could use the above instance to perform http get request, given().config(newConfig().sslConfig(new SSLConfig("/truststore.jks", "truststorepassword"))).get("URL")