I have a RESTful service controller that requests another RESTful service
#ResponseBody
#RequestMapping(value = "/headerparameters/{instanceId}", method = RequestMethod.DELETE)
public RestContainerFormBean passivizeHeaderParameter(#PathVariable String instanceId) throws GenericException, IOException {
String url = proactiveURL + "/customerheaders/" + instanceId;
if(isSecurityCheckOK(url)){
ResponseEntity<CustomerHeaderParameterBean> response = restTemplate.exchange(url, HttpMethod.DELETE, new HttpEntity<>(new HttpHeaders()), CustomerHeaderParameterBean.class);
CustomerHeaderParameterBean result = response.getBody();
setButtonActivity(result);
l10nOfValue(result);
return new RestContainerFormBean(result);
} else{
throw new IOException();
}
}
This code can not pass SonarQube policy.
Refactor this code to not construct the URL from tainted,
User provided data, such as URL parameters, POST data payloads, or
cookies, should always be considered untrusted and tainted. A remote
server making requests to URLs based on tainted data could enable
attackers to make arbitrary requests to the internal network or to the
local file system.
The problem could be mitigated in any of the following ways:
Validate the user provided data based on a whitelist and reject input
not matching. Redesign the application to not send requests based on
user provided data.
How can I pass the policy by sticking on REST conventions ?
Use UriComponentsBuilder to encode the URL instead of using raw URL.
Related
I'm new to the java rest CXF client. I will make various requests to a remote server, but first I need to create a Ticket Granting Ticket (TGT). I looked through various sources but I could not find a solution. The server requests that I will create a TGT are as follows:
Content-Type: text as parameter, application / x-www-form-urlencoded as value
username
password
I create TGT when I make this request with the example URL like below using Postman. (URL is example). But in the code below, I'm sending the request, but the response is null. Could you help me with the solution?
The example URL that I make a request with POST method using Postman: https://test.service.com/v1/tickets?format=text&username=user&password=pass
List<Object> providers = new ArrayList<Object>();
providers.add(new JacksonJsonProvider());
WebClient client = WebClient.create("https://test.service.com/v1/tickets?format=text&username=user&password=pass", providers);
Response response = client.getResponse();
You need to do a POST, yet you did not specify what your payload looks like?
Your RequestDTO and ResponseDTO have to have getters/setters.
An example of using JAX-RS 2.0 Client.
Client client = ClientBuilder.newBuilder().register(new JacksonJsonProvider()).build();
WebTarget target = client.target("https://test.service.com/v1/tickets");
target.queryParam("format", "text");
target.queryParam("username", "username");
target.queryParam("password", "password");
Response response = target.request().accept(MediaType.APPLICATION_FORM_URLENCODED).post(Entity.entity(yourPostDTO,
MediaType.APPLICATION_JSON));
YourResponseDTO responseDTO = response.readEntity(YourResponseDTO.class);
int status = response.getStatus();
Also something else that can help is if you copy the POST request from POSTMAN as cURL request. It might help to see the differences between your request and POSTMAN. Perhaps extra/different headers are added by postman?
Documentation: https://cxf.apache.org/docs/jax-rs-client-api.html#JAX-RSClientAPI-JAX-RS2.0andCXFspecificAPI
Similar Stackoverflow: Is there a way to configure the ClientBuilder POST request that would enable it to receive both a return code AND a JSON object?
When using the java.net.http.HttpClient classes in Java 11 and later, how does one tell the client to follow through an HTTP 303 to get to the redirected page?
Here is an example. Wikipedia provides a REST URL for getting the summary of a random page of their content. That URL redirects to the URL of the randomly-chosen page. When running this code, I see the 303 when calling HttpResponse#toString. But I do not know how to tell the client class to follow along to the new URL.
HttpClient client = HttpClient.newHttpClient();
HttpRequest request =
HttpRequest
.newBuilder()
.uri( URI.create( "https://en.wikipedia.org/api/rest_v1/page/random/summary" ) )
.build();
try
{
HttpResponse < String > response = client.send( request , HttpResponse.BodyHandlers.ofString() );
System.out.println( "response = " + response ); // ⬅️ We can see the `303` status code.
String body = response.body();
System.out.println( "body = " + body );
}
catch ( IOException e )
{
e.printStackTrace();
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
When run:
response = (GET https://en.wikipedia.org/api/rest_v1/page/random/summary) 303
body =
Problem
You're using HttpClient#newHttpClient(). The documentation of that method states:
Returns a new HttpClient with default settings.
Equivalent to newBuilder().build().
The default settings include: the "GET" request method, a preference of HTTP/2, a redirection policy of NEVER [emphasis added], the default proxy selector, and the default SSL context.
As emphasized, you are creating an HttpClient with a redirection policy of NEVER.
Solution
There are at least two solutions to your problem.
Automatically Follow Redirects
If you want to automatically follow redirects then you need to use HttpClient#newBuilder() (instead of #newHttpClient()) which allows you to configure the to-be-built client. Specifically, you need to call HttpClient.Builder#followRedirects(HttpClient.Redirect) with an appropriate redirect policy before building the client. For example:
HttpClient client =
HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL) // follow redirects
.build();
The different redirect policies are specified by the HttpClient.Redirect enum:
Defines the automatic redirection policy.
The automatic redirection policy is checked whenever a 3XX response code is received. If redirection does not happen automatically, then the response, containing the 3XX response code, is returned, where it can be handled manually.
There are three constants: ALWAYS, NEVER, and NORMAL. The meaning of the first two is obvious from their names. The last one, NORMAL, behaves just like ALWAYS except it won't redirect from https URLs to http URLs.
Manually Follow Redirects
As noted in the documentation of HttpClient.Redirect you could instead manually follow a redirect. I'm not well versed in HTTP and how to properly handle all responses so I won't give an example here. But I believe, at a minimum, this requires you:
Check the status code of the response.
If the code indicates a redirect, grab the new URI from the response headers.
If the new URI is relative then resolve it against the request URI.
Send a new request.
Repeat 1-4 as needed.
Obviously configuring the HttpClient to automatically follow redirects is much easier (and less error-prone), but this approach would give you more control.
Please find below code where i was calling another api from my REST APi in java.
To note I am using java version 17. This will solve error code 303.
#GetMapping(value = "url/api/url")
private String methodName() throws IOException, InterruptedException {
var url = "api/url/"; // remote api url which you want to call
System.out.println(url);
var request = HttpRequest.newBuilder().GET().uri(URI.create(url)).setHeader("access-token-key", "accessTokenValue").build();
System.out.println(request);
var client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL).build();
System.out.println(client);
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response);
System.out.println(response.body());
return response.body();
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
HTTP GET with request body
I've read few discussions here which do not advocate sending content via HTTP GET. There are restrictions on the size of data that can be sent via clients (web browsers). And handling GET data also depends on servers. Please refer section Resources below.
However, I've been asked to test the possibility to send content via HTTP GET using RestTemplate. I refered few discussions on spring forum but they were not answered. (Please note sending data via http Post works fine). The discussion here suggests using POST instead.
dev env - JBoss AS 5.1, Spring 3.1.3
Client
#Test
public void testGetWithBody()
{
// acceptable media type
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.TEXT_PLAIN);
// header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
// body
String body = "hello world";
HttpEntity<String> entity = new HttpEntity<String>(body, headers);
Map<String, Object> uriVariables = new HashMap<String, Object>();
uriVariables.put("id", "testFile");
// Send the request as GET
ResponseEntity<String> result = restTemplate.exchange(
"http://localhost:8080/WebApp/test/{id}/body",
HttpMethod.GET, entity, String.class, uriVariables);
Assert.assertNotNull(result.getBody());
}
Server #Controller
#RequestMapping(value = "/{id}/body", method = RequestMethod.GET)
public #ResponseBody
String testGetWithBody(#PathVariable String id,
#RequestBody String bodyContent)
{
return id + bodyContent;
}
The problem -
executing this test case returns 500 Internal Server Error. On debugging, I found that the controller is not hit.
Is it correct to understand that the RestTemplate provides the way to send data as request body, but the error occurs because the server could not handle the request body ?
If the request body sent via HTTP Get is not conventional why does RestTemplate provide the APIs to allow sending it ? Does this mean there are few servers capable of handling the Request body via GET ?
Resources - discussions on sending body via HTTP GET using RestTemplate at spring forum
http://forum.springsource.org/showthread.php?129510-Message-body-with-HTTP-GET&highlight=resttemplate+http+get
http://forum.springsource.org/showthread.php?94201-GET-method-on-RestTemplate-exchange-with-a-Body&highlight=resttemplate+http+get
Resources - General discussions on sending body via HTTP GET
get-with-request-body
is-this-statement-correct-http-get-method-always-has-no-message-body
get-or-post-when-reading-request-body
http-uri-get-limit
Is it correct to understand that the RestTemplate provides the way to send data as request body, but the error occurs because the server could not handle the request body ?
You can tell by looking at network traffic (does the request get sent with a request body and a GET method?) and at server logs (the 500 result you receive must have a server-side effect that gets logged, and if not, configure the server to do so).
If the request body sent via HTTP Get is not conventional why does RestTemplate provide the APIs to allow sending it ? Does this mean there are few servers capable of handling the Request body via GET ?
Because it is a generic class that also allows you to craft requests that can include a message body.
As stated in HTTP GET with request body:
In other words, any HTTP request message is allowed to contain a message body, and thus [a server] must parse messages with that in mind. Server semantics for GET, however, are restricted such that a body, if any, has no semantic meaning to the request. The requirements on parsing are separate from the requirements on method semantics.
A body on a GET cannot do anything semantically, because you are requesting a resource. It's like you tell the server: "Give me resource X, oh, and have some apples!". The server won't care about your apples and happily serve resource X - or throw an error because it doesn't like any offers in a request.
However, I've been asked to test the possibility to send content via HTTP GET
Please tell the one who requested this that this is a case that should not have to be tested, because no sensible implementation supports it.
We are using OAuth authorization and our internal JWT tokens with spring boot(stateless backend) + React. After several redicrections for getting user info we create jwt-token. And we need somehow to send it to client with html page. We can use
Request params (is not big enought for our token)
Cookie (is big enought for our token)
Put token into html page
So, 1 and 2 aren't our choice. We decided to put token into html page before sending to client. On client side just read it with js.
My question is: how to dynamically change html content before sending it to customer with spring boot?
Are there other methods solving this problem for stateless backend?
So i solved my issue in next way
#RequestMapping(value = "/login")
public String processLogin(HttpServletResponse response,
#RequestParam(value = "code") String code)throws IOException {
response.reset();
response.setContentType("text/html");
Resource file = new ClassPathResource("/META-INF/resources/index.html");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(file.getInputStream(), UTF_8));
htmlSourceContent = bufferedReader.lines().collect(Collectors.joining());
//do changes with htmlSourceContent
response.getOutputStream().write(htmlSourceContent);
log.debug("Authentication successfully passed");
}
I want a java way to extract the parameters of a URL regardless the way these parameters are written in it, in the regular way like( https://www.facebook.com/Doly.mohamed.Smile9?ref=stream&hc_location=stream ) it's so easy because all i have to do is :
URL url = new URL("www.blabla....etc");
String query = url.getQuery();
try{
String [] params = query.split("&");
for(int i= 0 ; i < params.length; i++){
String [] split = params[i].split("=");
parameters.put(split[0], split[1]);
}
}catch(NullPointerException ex){}
so the parameters values would be :
key = ref value = stream , key = hc_location value = stream
but what shall i do if the URL has parameters written in another way or if the URL does't has it's parameters written in it like in the case of the doPost() way.
and is there is a way to get the extraPathInfo from a URL without using servlets?
You could do that easily with Apache's HTTP utils.
URIBuilder uriBuilder = new URIBuilder(uriString);
List<NameValuePair> urlParameters = uriBuilder.getQueryParams();
String uriWithoutParameters = uriBuilder.clearParameters().toString();
Now you could, for example, easily convert the GET request to a POST request, using other classes from the http utils API.
There is a difference between GET and POST urls
In GET url, parameters are part of URL and in POST they are part of Request-body.
So in POST, the URL may or may not contain the request params, and unless you don't have them in the URL its not possible to extract.
The POST request method is designed to request that a web server
accept the data enclosed in the request message's body for storage.1
It is often used when uploading a file or submitting a completed web
form.
So unless you have the POST request's body. Its difficult to extract the Parameter.
Typically you need HTTP request parameters on HTTP server side. Java HTTP server will parse the request and pass it as ServletRequest object to Servlet.service method. ServletRequest has methods to access the request parameters.