Consuming web service & storing cookies - java

This method is used to consume a web service which I also control. The web service sets cookies to keep the user logged in.
This all works fine through a browser. i.e. I can call the login url, it will cookie my browser, and subsequent access to the web service recognizes my cookies.
In android, I can get a successful return on my login, but the cookies do not seem to be setting.
You can see where this code prints the cookie data to the output. It prints the cookie when it hits the login script, but for subsequent calls to this function, it does not recognize the cookie anymore.
Here's the code I'm using, I started from an example someone else posted:
private JSONObject getResponse(String func, List<NameValuePair> args) throws Exception {
HttpClient httpclient = new DefaultHttpClient();
try {
// Create a local instance of cookie store
CookieStore cookieStore = new BasicCookieStore();
// Create local HTTP context
HttpContext localContext = new BasicHttpContext();
// Bind custom cookie store to the local context
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpPost put= new HttpPost("http://example.com/api/" + func);
if (args != null) {
put.setEntity(new UrlEncodedFormEntity(args));
}
System.out.println("executing request " + put.getURI());
// Pass local context as a parameter
HttpResponse response = httpclient.execute(put, localContext);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
}
List<Cookie> cookies = cookieStore.getCookies();
for (int i = 0; i < cookies.size(); i++) {
System.out.println("Local cookie: " + cookies.get(i));
}
// Consume response content
//EntityUtils.consume(entity);
System.out.println("----------------------------------------");
InputStream instream = entity.getContent();
String result = convertStreamToString(instream);
instream.close();
entity.consumeContent();
System.out.println("JSON Output: " + result);
return new JSONObject(result);
} finally {
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}

That might be because your HttpClient and CookieStore are local to getResponse. Try making them global so they persist onto subsequent calls.

When you are trying to access locked content on a url call you need to manually set a cookie for the next coming call, which can be done using:
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setInstanceFollowRedirects(false);
httpURLConnection.setRequestProperty("Host", domainOfYourCookie);
httpURLConnection.setRequestProperty("Cookie", valueOfYourCookie);
I have written another answer regarding this topic, which you can find here.

Related

Logging into Content Navigator from external application

I'm trying to access a PluginService on Content Navigator from my Java Application (Event Action Handler in FileNet P8). The application uses the JAXRS logon service to receive the security_token from the Content Navigator server. However, if I try to call the PluginService I get a response that my login has expired.
I'm able to get the security token, as described in this code block:
URL logonUrl = new URL("http://icn-host:9081/jaxrs/logon"
+ "?userid=user"
+ "&password=password"
+ "&desktop=admin"
+ "&contextPath=%2Fnavigator");
HttpURLConnection logonConnection = (HttpURLConnection)logonUrl.openConnection();
logonConnection.setRequestMethod("POST");
logonConnection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
logonConnection.setDoOutput(true);
InputStream logonResponse = logonConnection.getInputStream();
String responseText = IOUtils.toString(logonResponse, "UTF-8")
.replaceFirst("^\\{}&&", "");
JSONObject responseJson = JSONObject.parse(responseText);
return (String)responseJson.get("security_token");
But when I try to make another request, I get an error response:
URL requestUrl = new URL("http://icn-host:9081/plugin.do"
+ "?plugin=myPlugin&action=myPluginService&myRequestProps=foobar");
HttpURLConnection requestConnection =
(HttpURLConnection)requestUrl.openConnection();
requestConnection.setRequestMethod("GET");
String securityToken = getSecurityToken(); // calls above code
requestConnection.setRequestProperty("security_token", securityToken);
equestConnection.setDoOutput(true);
InputStream responseStream = requestConnection.getInputStream();
String responseText = IOUtils.toString(responseStream, "UTF-8")
.replaceFirst("^\\{}&&", "");
log.info("response was: " + responseText);
I always get the following response:
{
"messagesEncoded":true,
"errors": [
{
"adminResponse":null,
"moreInformation":null,
"explanation":"Your session expired because of inactivity.",
"number":"1003",
"userResponse":"Log in again.",
"text":"Your session expired."
}
]
}
I've also tried to set the cookies, but no success.
java.net.CookieManager cookieManager = new java.net.CookieManager();
Map<String, List<String>> headerFields = logonConnection.getHeaderFields();
List<String> cookiesHeader = headerFields.get("Set-Cookie");
if (cookiesHeader != null) {
for (String cookie : cookiesHeader) {
cookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
}
}
// ...
StringBuilder cookieHeader = new StringBuilder();
List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
for (int i = 0; i < cookies.size(); i++) {
if (i > 0) {
cookieHeader.append(";");
}
HttpCookie cookie = cookies.get(i);
log.info("Cookie " + i + ": " + cookie.toString());
cookieHeader.append(cookie.toString());
}
requestConnection.setRequestProperty("Cookie", cookieHeader.toString());
I tried to replicate the request using XMLHttpRequest in a Content Navigator window and it works as expected:
var xhr = new XMLHttpRequest();
xhr.open("GET", "plugin.do" +
"?plugin=myPlugin" +
"&action=myPluginService" +
"&myRequestProps=foobar");
xhr.setRequestHeader("security_token", ecm.model.Request._security_token);
xhr.send();
I had a similar challenge for a client a few months ago where i had to automate the process of installing plugins and applying configuration for CI purposes.
I discovered it is key to obtain the desktop as the first api call after login for the session to become 'valid'.
So first jaxrs/logon, then jaxrs/getDesktop, then your service invoke.
A little sidenote: If you plan on having container managed authentication later on, the process will be different. The jaxrs/logon won't work, and instead the jaxrs/getDesktop will deliver the security_token.
A little remark though: wouldn't it be a better solution to have a shared library that you'd be able to use both from your Event Action as the ICN service?
Using shared libraries (see Ivo's answer) is definitely the best approach, calling jaxrs/getDesktop didn't work for me. Instead I just used the Maven Assembly Plugin to include a newer version of the org.apache.httpcomponents dependency and call the requests with an HttpClient.
My final code looks something like this:
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultCookieStore(cookieStore)
.setDefaultRequestConfig(requestConfig)
.build();
HttpUriRequest logonRequest = RequestBuilder.post()
.setUri("http://icn-host:9081/navigator/jarxrs/logon")
.addParameter("desktop", "admin")
.addParameter("contextPath", "/navigator")
.addParameter("userid", "icnadmin")
.addParameter("password", "password")
.build();
CloseableHttpResponse logonResponse = httpClient.execute(logonRequest);
HttpEntity responseEntity = logonResponse.getEntity();
String responseText = EntityUtils.toString(responseEntity)
.replaceFirst("^\\{}&&", "");
JSONObject responseJson = JSONObject.parse(responseText);
String securityToken = (String) responseJson.get("security_token");
HttpUriRequest request = RequestBuilder.get()
.setUri("http://icn-host:9081/navigator/plugin.do")
.addParameter("plugin", "myPlugin")
.addParameter("action", "myPluginService")
.addParameter("myRequestProps", "foobar")
.addHeader("security_token", securityToken)
.build();
HttpClientContext context = HttpClientContext.create();
CookieStore cookieStore = new BasicCookieStore();
context.setCookieStore(cookieStore);
CloseableHttpResponse response = httpClient.execute(request, context);

Sending the session id from an Android App to a Jersey web service

I got an Android application which is supposed to communicate with a web service which was implemented using Jersey and Jetty.
I can read the incoming session Id using this code:
private static void getCookie(HttpResponse httpResponse)
{
Header[] headers = httpResponse.getAllHeaders();
for (int i=0; i < headers.length; i++)
{
Header h = headers[i];
String s1 = h.getName();
if(s1.equals("Set-Cookie"))
{
sessionCookieValue = h.getValue().split(";",2)[0];
return;
}
}
}
This seems to work and I get a value like this in the cookie value: JSESSIONID=8pdfuwgduykls5cvj971ylrc
The problem is that I don't seem to send it properly. The web service is injected with a HttpServletRequest parameter which is supposed to hold the session id but it doesn't.
The way I'm trying to pass it is like this:
DefaultHttpClient client = new DefaultHttpClient();
CookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", sessionCookieValue);
cookie.setPath("/");
cookie.setDomain(MyApplication.WEB_SERVICE_BASE_ADDRESS); //"192.168.200.158/"
cookieStore.addCookie(cookie);
client.setCookieStore(cookieStore);
HttpResponse httpResponse;
try
{
httpResponse = client.execute(request);
...
}
Why isn't the session id injected to the request in the web service?
I have finally figured out the problem.
The initial comments were correct - the cookie's key in the BasicClientCookie should be "JESSIONID". The path and domain should be set like I did there.
The main issue was simply removing the "JSESSIONID=" prefix from the `sessionCookieValue. After I removed it, everything worked.

Accessing a login api using http get method in android

I am developing an android app which uses a login api, which will allow its web users to login with their same credentials on the android device.....
the url for the api is
https://api.ecoachsolutions.com/main.php?ecoachsignin=1&server=remote&user=ecoachguest&pass=ecoachguest
which retuns a response in json
JSON object: {
status: <success or error>,
msg: <response message>,
profile: <user profile object>
}
I tried this code which I found searching on the internet but it isn't working,
private void doLogin(View view) {
//ALERT MESSAGE
_spinner.setVisibility(View.VISIBLE);
Toast.makeText(mContext, "connecting to server.... ",
Toast.LENGTH_SHORT).show();
// URLEncode user defined data
String usernameValue = username.getText().toString();
String passValue = password.getText().toString();
// Create http cliient object to send request to server
HttpClient Client = new DefaultHttpClient();
// Create URL string
String URL = "https://api.ecoachsolutions.com/main.php?ecoachsignin=1&server=remote&user="+usernameValue+"&pass="+passValue;
Log.i("httpget", URL);
try
{
String SetServerString ;
// Create Request to server and get response
HttpGet httpget = new HttpGet(URL);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
SetServerString = Client.execute(httpget, responseHandler);
System.out.println(usernameValue);
System.out.println(passValue);
// Show response on activity
Toast.makeText(getBaseContext(),SetServerString,Toast.LENGTH_LONG).show();
}
catch(Exception ex)
{
Toast.makeText(getBaseContext(),"Fail",Toast.LENGTH_LONG).show();
_spinner.setVisibility(View.INVISIBLE);
}
}
will appreciate the help or the positive direction thanks :)
Change your code to get the HttpResponse like below,
String responseBody = "";
HttpResponse response = client.execute(post);
int responseCode = response.getStatusLine().getStatusCode();
Log.i("GET Response Code ",responseCode + "");
switch(responseCode) {
// Means server is responding
case 200:
HttpEntity entity = response.getEntity();
if(entity != null) {
responseBody = EntityUtils.toString(entity);
// Now you can try printing your returned string here, before you go for JSON parsing
}
break;
// Add more case statements to handle other scenarios
}
The code is simple, but if still unable to understand, don't hesitate to ask.

Log-in Webpage has hidden token that gets sent in a POST when submitting form. How to use the token in a Java HttpPost?

So there is this website that has a login form. I want to log in and then download a file. When submitting the form, not only do username and password get transmitted in the http POST but also a token that is in a hidden <input> tag.
Now, my Problem is that whenever I open the URL in java and get the token to make a POST the token is invalid when I use a HttpClient.
I somehow need to use the same client for calling the website to get the token and making the post. Unfortunately I get a 403 FORBIDDEN return code when trying to access the file.
This is what I have so far:
public static void main(String[] args){
try {
String token = getTokenFromPage("http://my.url");
HttpContext context = new BasicHttpContext();
DefaultHttpClient client = new DefaultHttpClient();
List <NameValuePair> parameters = new ArrayList <NameValuePair>();
HttpPost post = new HttpPost("http://my.url");
parameters.add(new BasicNameValuePair("username", "MYNAME"));
parameters.add(new BasicNameValuePair("password", "MYPW"));
parameters.add(new BasicNameValuePair("token", token));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters, HTTP.UTF_8);
post.setEntity(entity);
System.out.println("URL: " + post.getURI());
HttpResponse postResponse = client.execute(post, context);
System.out.println(postResponse.getStatusLine());
EntityUtils.consume(postResponse.getEntity());
//Now download the file
HttpGet httpget = new HttpGet("http://url.to.file");
HttpResponse getResponse = client.execute(httpget, context);
System.out.println(getResponse.toString());
System.out.print((postResponse.getEntity().getContent()));
client.getConnectionManager().shutdown();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
You are going to have to make an HTTP request for the login page, parse the resulting HTML in the HTTP response stream, and get the token value to use from there. Using a library like jsoup to parse the HTML would be advisable.

cURL app using Java

Does anyone have a good tutorial on how to write a java or javafx cURL application? I have seen tons of tutorials on how to initiate an external call to say like an XML file, but the XML feed I am trying to retrieve calls for you to submit the username and password before being able to retrieve the XML feed.
What are you trying to accomplish? Are you trying to retrieve a XML feed over HTTP?
In that case I suggest you to take a look at Apache HttpClient. It offers similair functionality as cURL but in a pure Java way (cURL is a native C application). HttpClient supports multiple authentication mechanisms. For example you can submit a username/password using Basic Authentication like this:
public static void main(String[] args) throws Exception {
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(
new AuthScope("localhost", 443),
new UsernamePasswordCredentials("username", "password"));
HttpGet httpget = new HttpGet("https://localhost/protected");
System.out.println("executing request" + httpget.getRequestLine());
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
}
if (entity != null) {
entity.consumeContent();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
Check the website for more examples.

Categories