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.
11 Answers
In my case using "relaxed HTTPs validation" fixed my problem:
given().relaxedHTTPSValidation().when().post("") 5 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(); 9 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
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 targetThe 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
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
2The 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("") .queryParam("name", args) .get("/validendpoint").prettyPrint(); System.out.println("RESPONSE" + response);
} 1 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.
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(); }
} 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")); //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(); 1 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(); 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.
2To 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,
- You make request to the server
- Server sends a certificate
- 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
- Create a truststore file with extension "jks" in your project, have to configure the password while creating the jks file.
- Download the certificate from the browser or use the created certificate(both are same), certificate extension is usually "pem" or "crt"
- 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]]
- 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")