Spring Boot TestRestTemplate: Pass along session id - java

I've got a Spring Boot application with some tests. The application's 'happy-path' requires that the user send a request to start a session, then it can make other requests to other services.
I'm trying to test these other services, but I need a session started first. My mindset was as follows:
Hit the session start endpoint
Get the session cookie from that request
Slap that cookie onto future requests made during testing.
To achieve that, I've got this mess:
String s = t.postForEntity(loginUrl, remoteSessionPacket, String.class)
.getHeaders()
.get("Set-Cookie").get(0);
String[] split = s.split(";");
String sessionId = "";
for (String s1 : split) {
if(s1.contains("SESSION"))
{
sessionId = s1;
}
}
HttpHeaders headers = new HttpHeaders();
headers.add("SESSION", sessionId);
HttpEntity<?> httpEntity = new HttpEntity<>(headers);
RemoteDTOPacket= new RemoteDTOPacket();
packet.Token = UUID.randomUUID().toString();
String url = "http://localhost:" + port + "/domain/SomeFunction";
ResponseEntity<ResponsePacket> response = t.postForEntity(url, packet, ResponsePacket.class, httpEntity);
Assert.assertEquals(0, (long) response.getBody().count);
Obviously, this doesn't work and errors are thrown with abandon.
Does anyone know how to accomplish what I'm trying to do?
Any help is greatly appreciated.

Session id is stored in cookie that is stored in "Cookie" header - not in separate request header. Something like this should work:
List<String> coockies = t.postForEntity(loginUrl, remoteSessionPacket, String.class)
.getHeaders()
.get("Set-Cookie");
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.put(HttpHeaders.COOKIE, coockies);
HttpEntity<Void> requestEntity = new HttpEntity<>(requestHeaders);
Or you can get exact session id cookie that will be most probably stored under "JSESSIONID" key.

Related

How to set OAuth realm in RestAssured

I am using RestAssured library for automating NetSuite Restlets. This Restlets are using OAuth 1.0 for authentication. Apart from consumer key, consumer secret, access token and token secret, I need to set advanced fields like REALM. But I couldn't find any way to set that in RestAssured.
RequestSpecification request = new RequestSpecBuilder()
.addHeader("Content-Type", ContentType.JSON.toString())
.setBaseUri(url).build()
.auth().oauth(
netsuiteConfig.getNetsuiteConsumerKey(),
netsuiteConfig.getNetsuiteConsumerSecret(),
netsuiteConfig.getNetsuiteTokenId(),
netsuiteConfig.getNetsuiteTokenSecret()
);
Here is the api call using Postman
RestAssured does not support this. Create OAuth 1.0 string using some library (I have used com.github.seratch:signedrequest4j) and set Authorization header in RestAssured RequestSpecification.
OAuthConsumer consumer = new OAuthConsumer(consumerKey, consumerSecret);
OAuthAccessToken accessToken = new OAuthAccessToken(tokenId, tokenSecret);
OAuthRealm realm = new OAuthRealm(myRealm);
SignedRequest request =
SignedRequestFactory.create(realm, consumer, accessToken);
request.readQueryStringAndAddToSignatureBaseString(url);
request.setHeader("Content-Type", "application/json");
String oAuthNonce = String.valueOf((new SecureRandom()).nextLong());
Long oAuthTimestamp = System.currentTimeMillis() / 1000L;
String signature = request.getSignature(url,
HttpMethod.POST, oAuthNonce, oAuthTimestamp);
String authorizationHeader = request
.getAuthorizationHeader(signature, oAuthNonce, oAuthTimestamp);
I was using the library mentioned in the previous answer but then I realised I needed to use PATCH requests which wasn't supported.
I started using the google oauth client instead and after days of trying, finally got this example working:
val signer = OAuthHmacSigner()
signer.clientSharedSecret = CONSUMER_SECRET
signer.tokenSharedSecret = TOKEN_SECRET
val oauthParameters = OAuthParameters()
oauthParameters.consumerKey = CONSUMER_KEY
oauthParameters.token = ACCESS_TOKEN
oauthParameters.signer = signer
val genericUrl = GenericUrl("https://{ACC_ID}.suitetalk.api.netsuite.com/path/to/endpoint")
oauthParameters.version = "1.0"
oauthParameters.computeNonce()
oauthParameters.computeTimestamp()
oauthParameters.computeSignature("GET", genericUrl)
oauthParameters.realm = REALM
val authHeader = oauthParameters.authorizationHeader
RestAssured.with()
.log().all()
.header("Authorization", authHeader)
.urlEncodingEnabled(false)
.request(Method.GET, genericUrl.toString())
.then()
.statusCode(200)
urlEncoding is set to false for urls with query params that are already encoded. For example:
{url}/invoice?q=internalid%20IS%2012
I hope it helps someone in the future!

HTTPUrlConnection maintain session

I am using Restful Services on server and trying to maintain the same session after performing login:
URL endpoint = new URL(getString(R.string.url_login));
// Create connection
HttpURLConnection myConnection = (HttpURLConnection) endpoint.openConnection();
myConnection.setRequestMethod("POST");
myConnection.setRequestProperty("User-Agent", "my-rest-app-v0.1");
// Create the data
String myData = "username=" + username + "&password=" + pwd;
// Enable data writing
myConnection.setDoOutput(true);
// Write the data
myConnection.getOutputStream().write(myData.getBytes());
rc = myConnection.getResponseCode();
if (rc == 200) {
String Cookie= myConnection.getHeaderField("Set-Cookie");
URL endpoint2 = new URL(getString(R.string.url_checkUserType));
HttpURLConnection myConnection2 =
(HttpURLConnection)endpoint2.openConnection();
myConnection2.setRequestMethod("GET");
myConnection2.setRequestProperty("User-Agent", "my-rest-app-v0.1");
myConnection2.setRequestProperty("Cookie", Cookie);
rc2 = myConnection2.getResponseCode();
....
}....
The problem is that rc2 is every time 401 as WebService doesn't recognize that requiest is part of the same session. What am I doing wrong?
You may do as follows
on the server side, it checks if the incoming request has a "sessionId" in cookie: if not, create one and return it in response; if yes, it knows the request belongs to a known session
on the client side, after a successful login, retrieve the "sessionId" from the response, and set it in the following requests
==
connection.setRequestProperty("Cookie", "JSESSIONID=" + URLEncoder.encode(jSessionId, "UTF-8"));
The solution was to use Spring RESTful services for Android that worked great for me.

Is there a limit in number of concurrent connections from google app engine to external services?

We have java7 based a google app engine application. For some report generation process, we are already using an external service in AWS. This external service is based on spring and it is deployed on tomcat7 instance.
We are consuming this external service's REST API's from gae app and getting output from it. Recently we needed to parallelize this report generation task using URLFetch.
I am initiating my 12 POST requests at the same time then trying to collect results using URLFetch. (I am using same external service url for all requests)
But tomcat only receives 2 request at the same time and this is creating a bottleneck for us.
What may be limiting tomcat so it can only process 2 request at the same time?
Is there anything configure on spring on external service?
Is there anything to configure on tomcat?
Is there anything to configure on google app engine?
Here you can find the request and collect part of code, for your reference.
URLFetchService fetcher = URLFetchServiceFactory.getURLFetchService();
FetchOptions fetchOptions = FetchOptions.Builder.withDefaults();
fetchOptions.doNotValidateCertificate();
fetchOptions.setDeadline(60d);
/* Initiate requests */
ArrayList<Future<HTTPResponse>> asyncResponses = new ArrayList<Future<HTTPResponse>>();
for(int i=startPage;i<(endPage+1);i++){
/* Create list of parameters to pass wkhtmltoPDF */
Map<String, Object> map = new HashMap<String, Object>();
map.put("parameters", parameters);
targetUrl = referer + "?viewMode=export&subjectId="+ subjectId +"&page=" + i;
map.put("targetUrl", targetUrl);
Gson gson = new Gson();
String data = gson.toJson(map);
URL serviceUrl = new URL(EXS_SERVER_URL+"/wkhtmltopdf");
HTTPRequest request = new HTTPRequest(serviceUrl, HTTPMethod.POST, fetchOptions);
HTTPHeader header = new HTTPHeader("Content-Type", "application/json; charset=UTF-8");
request.setHeader(header);
request.setPayload(data.getBytes("UTF-8"));
Future<HTTPResponse> responseFuture = fetcher.fetchAsync(request);
asyncResponses.add(responseFuture);
}
/* collect responses */
ArrayList<Integer> responseCodes = new ArrayList<Integer>();
for(int i=0;i<asyncResponses.size();i++){
Future<HTTPResponse> serviceResponse = null;
try {
serviceResponse = asyncResponses.get(i);
int responseCode = serviceResponse.get(59, TimeUnit.SECONDS).getResponseCode();
responseCodes.add(responseCode);
byte[] pdfBuffer = serviceResponse.get(59, TimeUnit.SECONDS).getContent();
if (pdfBuffer != null){
PdfReader page = new PdfReader(pdfBuffer);
copy.addDocument(page);
}
} catch (Exception e) {
e.printStackTrace();
}
}

Jersey ClientResponse getCookies failing to parse correctly

I have some Java code which is calling a restful service, and needs to first authenticate and store cookies for a future call. I am using Jersey 1.8. The problem is that after making the call to authenticate, I try to retrieve the cookies using ClientResponse.getCookies() and iterate through the list of NewCookie objects. However, when calling NewCookie.getName(), the path of the cookie is returned.
The cookies returned in the response header look like this:
Set-Cookie: xsIdEEDB0766347B60DAEAA0AF57226EDD2C=385DF57B79FE0A4D84E04ED43000A81B; path=/; HttpOnly
My code looks something like this. I am just dumping the info to System.out for now because I wanted to look at the values in the debugger.
My question is why ClientResponse.getCookies() does not seem to work. Parsing the headers manually will work, but that just does not seem right. Is there a way to configure the Client or the ClientResponse to correctly get the cookies?
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
Builder builder = client.resource(MY_PATH).accept("text/plain");
builder = builder.header(AUTHORIZATION, auth);
ClientResponse response = builder.head();
if (response.getClientResponseStatus() == Status.OK) {
// Look at cookies in the response
List<NewCookie> cs = response.getCookies();
for (NewCookie c : cs) {
System.out.println(c.getName());
System.out.println(c.getValue());
}
// Look at the cookies in the header
List<String> cookies = headers.get("Set-Cookie");
for (String cookie : cookies) {
// example: xsIdEEDB0766347B60DAEAA0AF57226EDD2C=385DF57B79FE0A4D84E04ED43000A81B; path=/; HttpOnly
int x = cookie.indexOf(';');
String cookieNameValue = cookie.substring(0, x);
String[] nameValue = cookieNameValue.split("=");
NewCookie nc = new NewCookie(nameValue[0], nameValue[1]);
}
}

Google API Java GET request with body content

My Goal is to request GoogleTaskAPI for TASKLIST with specified no.of result.
It works fine, If I m passing no requestBody. But I need to pass request parameter to specific number of results to be returned. When I do that, it creates new Tasklist, Instead of listing. So how to do this?
My Code:
GoogleAccessProtectedResource access = new GoogleAccessProtectedResource(accessToken, httpTransport, jsonFactory, clientId, clientSecret, refreshToken);
HttpRequestFactory rf = httpTransport.createRequestFactory(access);
String endPointUrl = "https://www.googleapis.com/tasks/v1/users/#me/lists";
String requestBody = "{\"maxResults\":3}";
GenericUrl endPoint = new GenericUrl(endPointUrl);
ByteArrayContent content = new ByteArrayContent("application/json", requestBody.getBytes());
//Try 0: Works, But Retrieving all of my Tasklist, I need only 3
//HttpRequest request = rf.buildGetRequest(endPoint);
//-------
//Try 1: Fails to retrieve
//HttpRequest request = rf.buildGetRequest(endPoint);
//request.setContent(content);
//request.getContent().writeTo(System.out);
//-------
//Try 2: Fails to retrieve
HttpRequest request = rf.buildRequest(HttpMethod.GET, endPoint, content);
request.getContent().writeTo(System.out);
//-------
HttpResponse response = request.execute();
String str = response.parseAsString();
utils.log(str);
maxResults is a query parameter, not a request parameter, so you can just put it in the url:
String endPointUrl = "https://www.googleapis.com/tasks/v1/users/#me/lists?maxResults=3";
You should also consider using the Java client's Tasks interface for making requests; it may be a little easier since it handles the details of the url for you:
http://code.google.com/p/google-api-java-client/wiki/APIs#Tasks_API

Categories

Resources