How to do in Resttemplate Spring - java

curl -u "uname:password" -H "X-Requested-With: Curl" -X "POST" "https://qualysapi.qg2.apps.qualys.eu/qps/rest/3.0/search/was/wasscan/" > was_finding.txt
How to do the same thing in Spring rest template,
curl -u "uname:password" -H "X-Requested-With: Curl" -X "POST" "https://qualysapi.qg2.apps.qualys.eu/qps/rest/3.0/search/was/wasscan/" > was_finding.txt

Well, I'm not sure why you have the same request two times. Anyhow, you need to initiate a rest client, that you can reuse, and then use it is as a simple http client for any calls:
// Do once
HttpClient client = HttpClients.createDefault();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client);
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(factory));
// Do anytime
byte[] plainCredsBytes = "uname:password".getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
ResponseEntity<String> response = restTemplate.postForEntity(
"https://qualysapi.qg2.apps.qualys.eu/qps/rest/3.0/search/was/wasscan/",
new HttpEntity(headers), String.class);
if (response.getStatusCode() == HttpStatus.OK) {
Files.writeString(Paths.get("was_finding.txt"), response.getBody());
} else {
// Handle status code, etc.
}
If you need to set up SSL then you need to create a SSLContextBuilder before you build your client, thats it.

Related

Java - 422 Unprocessable Entity using RestTemplate

I have two services, Am trying to send a GET request from Service A, To make Service B send a Post request to Redmine Server.
Am getting 422 Unprocessable Entity: "{"errors":["Name cannot be blank","Identifier cannot be blank"]}"
And here is what I have already tried :
String url = "http://localhost:3001/projects.json"; //Redmine local server
RestTemplate restTemplate = new RestTemplate();
JSONObject object = new JSONObject(); //Json object that will need to be sent to redmine
object.put("name", "dummyName"); // Should look like this
object.put("identifier", "dummyId"); // {"project":{"identifier":"dummyId","name":"dummyName"}}
JSONObject body = new JSONObject();
body.put("project", object);
String plainCreds = "user:bitnami1"; // default basic auth encoding
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
headers.add("Content-Type", "application/json");
RequestEntity<JSONObject> requestEntity = RequestEntity
.post(new URI(url))
.accept(MediaType.APPLICATION_JSON)
.headers(headers)
.body(body);
ResponseEntity<String> r = restTemplate.exchange(requestEntity, String.class);
This way am getting the same error, 422 Unprocessable Entity: "{"errors":["Name cannot be blank", "Identifier cannot be blank"]}"
And when I try to log.info the Request Entity to check it look ok
<POST http://localhost:3001/projects.json,{"project":{"identifier":"dummyId","name":"dummyName"}},[Accept:"application/json", Authorization:"Basic dXNlcjpiaXRuYW1pMQ==", Content-Type:"application/json"]>
Then I've Tried with entity , As the following
String url = "http://localhost:3001/projects.json"; //Redmine local server
RestTemplate restTemplate = new RestTemplate();
JSONObject object = new JSONObject(); //Json object that will need to be sent to redmine
object.put("name", "dummyName"); // Should look like this
object.put("identifier", "dummyId"); // {"project":{"identifier":"dummyId","name":"dummyName"}}
JSONObject body = new JSONObject();
body.put("project", object);
String plainCreds = "user:bitnami1"; // default basic auth encoding
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
headers.add("Content-Type", "application/json");
HttpEntity<Object> entity = new HttpEntity<Object>(body, headers);
ResponseEntity<String> result = restTemplate.exchange("http://localhost:3001/projects.json",
HttpMethod.POST,
entity,
String.class);
The same result as earlier, When I log.info for entity-body I get the following
<{"project":{"identifier":"dummyId","name":"dummyName"}},[Authorization:"Basic dXNlcjpiaXRuYW1pMQ==", Content-Type:"application/json"]>
Tried To use NetCat to capture what is being sent, In both ways am not getting any body with restTemplate.exchange.
While debugging, It seems that the error came from RestTemplate.doExecute And I cant get why.
----Edit----
Am trying to connect to Redmine API to create new Project, More info can be found here And this is the curl command that successfully create new project
curl --location --request POST 'localhost:3001/projects.json' \
--header 'Authorization: Basic dXNlcjpiaXRuYW1pMQ==' \
--header 'Content-Type: application/json' \
--data-raw '{"project":{"identifier":"dummyId","name":"dummyName"}}'
What I am trying to do, Is to send a request From service A to my Service B so this request will be forwarded to redmine server.
For simplicity, I hard-coded the information in the code above (service B) just to make sure I can map this curl request, But it's not working.
Is there any suggested solution for this situation? Maybe an alternative approach ? Any suggestion would help.
Since your method would accept an object node as an input so you can do something like this:
String url = "http://localhost:3001/projects.json";
RestTemplate restTemplate = new RestTemplate();
Then you can set an HttpEntity like this:
HttpEntity<ObjectNode> entity = new HttpEntity<>(node, headers);
Then call exchange:
ResponseEntity<String> result = restTemplate.exchange("http://localhost:3001/projects.json",
HttpMethod.POST,
entity,
String.class);
I guess this will make your life easier.

OAuth 2.0 Access Tokens and Client Certificate

So I'm currently developing a Spring boot MS that needs to connect to an external API which has OAuth 2.0 implemented.
The API Store uses a custom version of a grant type called a Client Certificate.
This grant type uses a combination of Mutual SSL and Application level credentials.
It requires two identity factors:
Identity Factor 1 – Mutual SSL: Certificate created by me signed by the API store owner
Identity Factor 2 – Application Level Credentials: {consumerKey:consumerSecret}
The curl command for obtaining this token is:
curl -k -d "grant_type=client_cert" --basic -u "{consumer key}:{consumer secret}" -H "Content-Type: application/x-www-form-urlencoded" --cert {Certificate Pem} https://api.examplestore.com/token
How can I translate this to my Spring boot application?
I've currently written this piece of code, but I think I'm far off.
public void TokenRequest() {
ResponseEntity<String> response = null;
RestTemplate restTemplate = new RestTemplate();
String credentials = String.format("%s:%s", consumerKey, consumerSecret);
String encodedCredentials = new String(Base64.getEncoder().encodeToString(credentials.getBytes()));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
//headers.setCertificate??
headers.add("Authorization", "Basic " + encodedCredentials);
HttpEntity<String> request = new HttpEntity<String>(headers);
response = restTemplate.exchange(tokenUrl, HttpMethod.POST, request, String.class);
}
Any help is welcome. Thank you :)
I think you are not that far off.
You defenitely need to include the body:
HttpEntity<String> request = new HttpEntity<String>("grant_type=client_cert", headers);
Also you need to include the certificate, maybe like this:
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(new URL("/path/to/your/cert"), "certpassword".toCharArray())
.setProtocol("yourProtocol")
.build();
final HttpClient httpClient = HttpClientBuilder.create()
.setSSLContext(sslContext)
.build();
final ClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
...

Why is my Session gone when using RestTemplate to access Spring MVC?

I am trying to access a Spring MVC app. That uses a CSRF Token. I do an initial GET to receive the Token. Then add it to my POST with my JSESSIONID. However, during debug the Server app doesn't find my JSESSIONID. And therefore, doesn't authenticate my token, and gives me 403.
I can't tell but it looks like my GET JSESSIONID doesn't get saved in the server HTTP Session repository.
Is there a way, to validate:
The session is in the server context?
Am I sending the correct header data?
Here's my code:
public String testLogin() {
ResponseEntity<String> response =
restTemplate.getForEntity(LOGIN_RESOURCE_URL, String.class);
List<String> cookies = new ArrayList<String>();
cookies = response.getHeaders().get("Set-Cookie");
String[] firstString = cookies.get(0).split("=|;");
String jsessionPart = firstString[1];
String[] secondString = cookies.get(1).split("=|;");
String tokenPart = secondString[1];
BasicCookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie("JSESSIONID",
jsessionPart);
cookie.setDomain(".mydomain.com");
cookie.setPath("/");
cookieStore.addCookie(cookie);
BasicClientCookie cookie2 = new BasicClientCookie("X-XSRF-TOKEN",
tokenPart);
cookie2.setDomain(".mydomain.com");
cookie2.setPath("/");
cookieStore.addCookie(cookie2);
HttpClient client = HttpClientBuilder
.create()
.setDefaultCookieStore(cookieStore)
.disableRedirectHandling()
.build();
HttpComponentsClientHttpRequestFactory factory = new
HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(client);
RestTemplate postTemplate = new RestTemplate(factory);
HttpEntity<?> requestEntity = new HttpEntity<Object>(body, headers);
ResponseEntity<String> response = postTemplate.exchange(loginUserUrl,
HttpMethod.POST, requestEntity,String.class);
To your code sample I added user name and password plus changed the content type. The 403 still happens whether i sent content type or not:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// if you need to pass form parameters in request with headers.
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
try {
map.add( URLEncoder.encode("username", "UTF-8"),
URLEncoder.encode("userdev", "UTF-8") );
map.add(URLEncoder.encode("password", "UTF-8"),
URLEncoder.encode("devpwd","UTF-8") );
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>
(map, headers);
ResponseEntity<String> response =
this.restTemplate(builder).exchange(RESOURCE_URL, HttpMethod.POST,
requestEntity, String.class);
Instead of messing around with cookies yourself let the framework, Apache HttpClient, handle this for you. Configure the RestTemplate to work with a properly configured HttpClient.
Something like this should do the trick
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.requestFactory(this::requestFactory)
.build();
}
#Bean
public HttpComponentsClientHttpRequestFactory requestFactory() {
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.setExpectContinueEnabled(true)
.build();
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setDefaultCookieStore(new BasicCookieStore())
.setDefaultRequestConfig(defaultRequestConfig).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return requestFactory;
}
This will configure the RestTemplate to use a HttpClient that stores cookies in a CookieStore in between requests. Reuse the configured RestTemplate and don't create a new one because you might need it.

Invalid HTTP method: PATCH

After trying other solutions from HttpURLConnection Invalid HTTP method: PATCH
I am getting Invalid HTTP Method: PATCH Exception with JAVA 7.
Updating JAVA is not in option so i have to stick to the workarounds.
I am using Invocation to invoke the request like this
Invocation invoke = reqBuilder.build(getHTTPVerb(), Entity.entity(requestJSON, MediaType.APPLICATION_JSON));
getWebTarget().request(MediaType.APPLICATION_JSON).header("Authorization", getAuthorization()).accept(MediaType.APPLICATION_JSON);
getHTTPVerb() returns String "POST" or "PATCH".
With PATCH method I am having problem.
In the mentioned question, i have not tried one solution with:
conn.setRequestProperty("X-HTTP-Method-Override", "PATCH");
conn.setRequestMethod("POST");
conn is HttpURLConnection instance.
But I am not sure how I can get HttpURLConnection from Invocation class or any property.
Any pointers or help would be highly appreciated.
An example of PATCH method with apache http client:
try {
//This is just to avoid ssl hostname verification and to trust all, you can use simple Http client also
CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
HttpPatch request = new HttpPatch(REST_SERVICE_URL);
StringEntity params = new StringEntity(JSON.toJSONString(payload), ContentType.APPLICATION_JSON);
request.setEntity(params);
request.addHeader(org.apache.http.HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
request.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
request.addHeader(HttpHeaders.AUTHORIZATION, OAuth2AccessToken.BEARER_TYPE + " " + accessToken);
HttpResponse response = httpClient.execute(request);
String statusCode = response.getStatusLine().getStatusCode();
} catch (Exception ex) {
// handle exception here
}
Equivalent example with RestTemplate:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", OAuth2AccessToken.BEARER_TYPE + " " + accessToken);
final HttpEntity<String> entity = new HttpEntity<String>(JSON.toJSONString(payload), headers);
RestTemplate restTemplate = new RestTemplate();
try {
ResponseEntity<String> response = restTemplate.exchange(REST_SERVICE_URL, HttpMethod.PATCH, entity, String.class);
String statusCode = response.getStatusCode();
} catch (HttpClientErrorException e) {
// handle exception here
}

Translate authorized curl -u post request with JSON data to RestTemplate equivalent

I am using github api to create repositories using curl command as shown below and it works fine.
curl -i -u "username:password" -d '{ "name": "TestSystem", "auto_init": true, "private": true, "gitignore_template": "nanoc" }' https://github.host.com/api/v3/orgs/Tester/repos
Now I need to execute the same above url through HttpClient and I am using RestTemplate in my project.
I have worked with RestTemplate before and I know how to execute simple url but not sure how to post the above JSON data to my url using RestTemplate -
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Create a multimap to hold the named parameters
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
parameters.add("username", username);
parameters.add("password", password);
// Create the http entity for the request
HttpEntity<MultiValueMap<String, String>> entity =
new HttpEntity<MultiValueMap<String, String>>(parameters, headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
Can anyone provide an example how would I execute the above URL by posting JSON to it?
I have not had the time to test the code, but I believe this should do the trick. When we are using curl -u, to pass the credentials, it has to be encoded and passed along with the Authorization header, as noted here http://curl.haxx.se/docs/manpage.html#--basic. The json data, is simply passed as a HttpEntity.
String encoding = Base64Encoder.encode("username:password");
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Basic " + encoding);
headers.setContentType(MediaType.APPLICATION_JSON); // optional
String data = "{ \"name\": \"TestSystem\", \"auto_init\": true, \"private\": true, \"gitignore_template\": \"nanoc\" }";
String url = "https://github.host.com/api/v3/orgs/Tester/repos";
HttpEntity<String> entity = new HttpEntity<String>(data, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity , String.class);

Categories