I am writing an application that will autocomplete a form on a website;(in Java)
The user must be logged in to do this, and this is where the issue appears:
this is a chunk of the response to the login request:
Set-Cookie: PHPSESSID=3fvr31tb3c1iplpi3vqpvloar3; path=/; domain=.bursatransport.com
Set-Cookie: PHPSESSID=eanaj1d9egd73uiome0jtsed43; path=/; domain=.bursatransport.com
As far as I have tested it, the last one is the correct one(I tested it by changing the PHPSESSID cookie in the browser)
My application retains the first cookie. As a result, when submitting a form, it behaves as if the user would not be logged in.
Sometines it retained the last cookie, but it did not succesfully submit the form(the same as before).
Here is my login code:
String query = String
.format("returnTo=/&Login[username]=%s&Login[password]=%s&Login[rememberMe]=0&yt4=",
URLEncoder.encode(name, charset),
URLEncoder.encode(password, charset));
CookieManager manager = new CookieManager();
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);
URLConnection mycon = new URL(url).openConnection();
mycon.setDoOutput(true);
mycon.setRequestProperty("Accept-Language", "ro-RO,ro;q=0.8,en-US;q=0.6,en;q=0.4");
mycon.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
mycon.setRequestProperty("Accept-Charset", charset);
mycon.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=" + charset);
OutputStream output = null;
output = mycon.getOutputStream();
output.write(query.getBytes(charset));
mycon.getContent();
This is for sure not a server issue, since it responds correctly to browser requests(I am listening to them with fiddler)
I solved the problem(even if i still don't know the roots of it).
The response contained 2 "Set-Cookie" headers because(this is not your most consistent reason) my request did not contain a PHPSESSID cookie;
So I changed the code, so that it would first get the login page(with no login data).
The response to this request set's a PHPSESSID cookie(but I am not logged in)
Then I send my login request (which now contains a PHPSESSID cookie) and, boom, it works.
here is the code:
CookieManager manager = new CookieManager();
CookieHandler.setDefault(manager);
URLConnection mycon = new URL(url).openConnection();
mycon.getContent();
String query = String
.format("Login[username]=%s&Login[password]=%s&Login[rememberMe]=0&yt4=",
URLEncoder.encode(name, charset),
URLEncoder.encode(password, charset));
mycon = new URL(url).openConnection();
mycon.setDoOutput(true);
mycon.setRequestProperty("Accept-Language", "ro-RO,ro;q=0.8,en-US;q=0.6,en;q=0.4");
mycon.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
mycon.setRequestProperty("Accept-Charset", charset);
mycon.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=" + charset);
OutputStream output = null;
output = mycon.getOutputStream();
output.write(query.getBytes(charset));
output.close();
mycon.getContent();
mycon.getInputStream().close();
This the post that "opened my eyes":
Java: Handling cookies when logging in with POST
Related
NOTICE UPDATE!!
The problem got solved and i added my own answer in the thread
In short, I have attempted to add the parameter "scan_id" value but since it is a POST i can't add the value directly in the url path.
using the code i already have, how would i go about modifying or adding so that the url is correct, that is, so that it accepts my POST?.
somehow i have been unable to find any examples that have helped me in figuring out how i would go about doing this..
I know how to do a POST with a payload, a GET with params. but a post with Params is very confusing to me.
Appreciate any help. (i'd like to continue using HttpUrlConnection unless an other example is provided that also tells me how to send the request and not only configuring the path.
I've tried adding it to the payload.
I've tried UriBuilder but found it confusing and in contrast with the rest of my code, so wanted to ask for help with HttpUrlConnection.
URL url = new URL("http://localhost/scans/{scan_id}/launch");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("tmp_value_dont_mind_this", "432432");
con.setRequestProperty("X-Cookie", "token=" + "43432");
con.setRequestProperty("X-ApiKeys", "accessKey="+"43234;" + " secretKey="+"43234;");
con.setDoInput(true);
con.setDoOutput(true); //NOT NEEDED FOR GETS
con.setRequestMethod("POST");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
//First example of writing (works when writing a payload)
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
writer.write(payload);
writer.close();
//second attemp at writing, doens't work (wanted to replace {scan_id} in the url)
DataOutputStream writer = new DataOutputStream(con.getOutputStream());
writer.writeChars("scan_id=42324"); //tried writing directly
//writer.write(payload);
writer.close();
Exception:
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 400 for URL: http://localhost/scans/launch
I'd like one of the three response codes because then i know the Url is correct:
200 Returned if the scan was successfully launched.
403 Returned if the scan is disabled.
404 Returned if the scan does not exist.
I've tried several urls
localhost/scans/launch,
localhost/scans//launch,
localhost/scans/?/launch,
localhost/scans/{scan_id}/launch,
So with the help of a friend and everyone here i solved my problem.
The below code is all the code in an entire class explained bit by bit. at the bottom you have the full class with all its syntax etc, that takes parameters and returns a string.
in a HTTP request there are certain sections.
Such sections include in my case, Request headers, parameters in the Url and a Payload.
depending on the API certain variables required by the API need to go into their respective category.
My ORIGINAL URL looked like this: "http://host:port/scans/{scan_id}/export?{history_id}"
I CHANGED to: "https://host:port/scans/" + scan_Id + "/export?history_id=" + ID;
and the API i am calling required an argument in the payload called "format" with a value.
String payload = "{\"format\" : \"csv\"}";
So with my new URL i opened a connection and set the request headers i needed to set.
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
The setDoOutput should be commented out when making a GET request.
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.setRequestProperty("X-Cookie", "token=" + token);
con.setRequestProperty("X-ApiKeys", "accessKey="+"23243;" +"secretKey="+"45543;");
Here i write to the payload.
//WRITING THE PAYLOAD to the http call
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
writer.write(payload);
writer.close();
After i've written the payload i read whatever response i get back (this depends on the call, when i do a file download (GET Request) i don't have a response to read as i've already read the response through another piece of code).
I hope this helps anyone who might encounter this thread.
public String requestScan(int scan_Id, String token, String ID) throws MalformedInputException, ProtocolException, IOException {
try {
String endpoint = "https://host:port/scans/" + scan_Id + "/export?history_id=" ID;
URL url = new URL(endpoint);
String payload= "{\"format\" : \"csv\"}";
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.setRequestProperty("X-Cookie", "token=" + token);
con.setRequestProperty("X-ApiKeys", "accessKey="+"324324;" +
"secretKey="+"43242;");
//WRITING THE PAYLOAD to the http call
OutputStreamWriter writer = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
writer.write(payload);
writer.close();
//READING RESPONSE
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuffer jsonString = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
jsonString.append(line);
}
br.close();
con.disconnect();
return jsonString.toString();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
As discussed here the solution would be to change the content type to application/x-www-form-urlencoded, but since you are already using application/json; charset=UTF-8 (which I am assuming is a requirement of your project) you have no choise to redesign the whole thing. I suggest you one of the following:
Add another GET service;
Add another POST service with content type application/x-www-form-urlencoded;
Replace this service with one of the above.
Do not specify the content type at all so the client will accept anything. (Don't know if possible in java)
If there are another solutions I'm not aware of, I don't know how much they would be compliant to HTTP protocol.
(More info)
Hope I helped!
Why you are not using like this. Since you need to do a POST with HttpURLConnection, you need to write the parameters to the connection after you have opened the connection.
String urlParameters = "scan_id=42324";
byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);
DataOutputStream dataOutputStream = new DataOutputStream(conn.getOutputStream());
dataOutputStream.write(postData);
Or if you have launch in the end, just change the above code to the following,
String urlParameters = "42324/launch";
byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8);
DataOutputStream dataOutputStream = new DataOutputStream(conn.getOutputStream());
dataOutputStream.write(postData);
URL url = new URL("http://localhost/scans/{scan_id}/launch");
That line looks odd to me; it seems you are trying to use a URL where you are intending the behavior of a URI Template.
The exact syntax will depend on which template implementation you choose; an implementation using the Spring libraries might look like:
import org.springframework.web.util.UriTemplate;
import java.net.url;
// Warning - UNTESTED code ahead
UriTemplate template = new UriTemplate("http://localhost/scans/{scan_id}/launch");
Map<String,String> uriVariables = Collections.singletonMap("scan_id", "42324");
URI uri = template.expand(uriVariables);
URL url = uri.toURL();
I have a problem on HttpURLConnection in post method. Everything is working fine on get method however, when I try to use Post method. I'm getting this error message.
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 403 for URL
Here's my code snippet. I hope you could help me about this.
URL url = new URL(my url/userInfo);
String encoding = Base64.getEncoder().encodeToString(("username:password").getBytes("UTF-8"));
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "text/plain");
connection.setRequestProperty("Authorization", "Basic " + encoding);
connection.setRequestProperty("x-csrf-token", "fetch");
String csrfToken = connection.getHeaderField("x-csrf-token");
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
String output = in.readLine();
in.close();
String content = data // expected data to retrieve
URL url2 = new URL(my URL);//another url to push the data retrieve
HttpURLConnection connection2 = (HttpsURLConnection) url2.openConnection();
connection2.setDoInput(true);
connection2.setDoOutput(true);
connection2.setRequestMethod("POST");
connection2.setRequestProperty("Authorization", "Basic " + encoding);
connection2.setRequestProperty("Accept", "application/json");
connection2.setRequestProperty("x-CSRFToken", csrfToken);
connection2.setRequestProperty("cache-control", "no-cache");
OutputStream os = connection2.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
osw.write(data);//this is where the data will be pushed
osw.flush();
osw.close();
os.close();
the idea is, we need first to get the x-csrf-token and data from the first link, which is okay. After GET Method execution, the POST method will occur. unfortunately, the post method is not working. I'm getting the error message shown above. By the way, we tried to do a post method in POSTMAN and it' working fine.
Hoping you could help me about this.
In the code below I am running a post request on a website. What I dont understand is why the cookie shows up via the cookiemanager, but it does not show up in the POST header. See my comments in the code.
Can someone kindly explain what I am missing?
CookieManager cm = new CookieManager(null, CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cm);
...
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
OutputStream outputStream = connection.getOutputStream();
outputStream.write(urlParams.getBytes(charset));
// Clear cookies to prove they are not from an old request.
cm.getCookieStore().removeAll();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
throw new Exception("Invalid response code.");
// No cookie prints here:
Log.d("Aero", connection.getHeaderFields().toString());
List<HttpCookie> cookies = cm.getCookieStore().getCookies();
for (HttpCookie cookie : cookies) {
if (cookie.getName().equals("ASP.NET_SessionId")) {
// But we do get a cookie here
Log.d("Aero", cookie.toString());
}
}
Ok with a clear head this morning I have managed to solve this one myself. The problem was that the response was a 302 redirect and the redirected page had no cookie in the response header.
I needed to use:
connection.setInstanceFollowRedirects(false);
To ensure I was reading the response from the original header not the redirected one.
I'm trying to login web site using Java and I succeeded. Below is the code I used.
String query = "myquery";
URL url = new URL(loginUrl);
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-length", String.valueOf(query.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(query);
output.close();
DataInputStream input = new DataInputStream( con.getInputStream() );
for( int c = input.read(); c != -1; c = input.read() ) {
System.out.print( (char)c );
// this page returns JavaScript code
}
After this, I want to access another web page in same domain, so I tried below code.
URL url = new URL(anotherUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
... similar to above code ...
But this page asks me to login again. I think connection has been disconnected in the process of changing URL. (Onlt login page uses HTTPS protocol and other pages use HTTP protocol)
How can I fix this?
Someone please help
Keep in mind that HTTP is completely stateless. The idea of "logging in" to a site translates to (usually) setting cookies from an HTTP perspective. Those cookies are simply HTTP headers and they are sent with each subsequent request by your browser. So for you to maintain the logged in state its up to you get the cookies from the response headers and send them along with future requests.
Here is how:
Retrieving cookies from a response:
Open a java.net.URLConnection to the server:
URL myUrl = new URL("http://www.hccp.org/cookieTest.jsp");
URLConnection urlConn = myUrl.openConnection();
urlConn.connect();
Loop through response headers looking for cookies:
Since a server may set multiple cookies in a single request, we will need to loop through the response headers, looking for all headers named "Set-Cookie".
String headerName=null;
for (int i=1; (headerName = uc.getHeaderFieldKey(i))!=null; i++) {
if (headerName.equals("Set-Cookie")) {
String cookie = urlConn.getHeaderField(i);
...
Extract cookie name and value from cookie string:
The string returned by the getHeaderField(int index) method is a series of name=value separated by semi-colons (;). The first name/value pairing is actual data string we are interested in (i.e. "sessionId=0949eeee22222rtg" or "userId=igbrown"), the subsequent name/value pairings are meta-information that we would use to manage the storage of the cookie (when it expires, etc.).
cookie = cookie.substring(0, cookie.indexOf(";"));
String cookieName = cookie.substring(0, cookie.indexOf("="));
String cookieValue = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
This is basically it. We now have the cookie name (cookieName) and the cookie value (cookieValue).
Setting a cookie value in a request:
Values must be set prior to calling the connect method:
URL myUrl = new URL("http://www.hccp.org/cookieTest.jsp");
URLConnection urlConn = myUrl.openConnection();
Create a cookie string:
String myCookie = "userId=igbrown";
Add the cookie to a request:
Using the
setRequestProperty(String name, String value);
method, we will add a property named "Cookie", passing the cookie string created in the previous step as the property value.
urlConn.setRequestProperty("Cookie", myCookie);
Send the cookie to the server:
To send the cookie, simply call connect() on the URLConnection for which we have added the cookie property:
urlConn.connect()
I am trying use the HTTPURLConnection class to open connection to a JSP and receive a response from a servlet. A response header is set in the JSP that need to be read in the servlet.
The code sample is as below
String strURL = "http://<host>:<port>/<context>/mypage.jsp";
String sCookies = getCookie();//method to get the authentication cookie(**SSOAUTH**) and its value for the current logged in user
URL url = new URL(strURL);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty("Cookie", URLEncoder.encode(sCookies, "UTF-8"));
urlConnection.setRequestMethod("POST");
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
out.writeBytes("lang=en");
out.flush();
out.close();
//reading the response received from JSP and retrieve header value
response.write(urlConnection.getHeaderField("commAuth") + "<br />");
The issue is the passed SSOAUTH cookie is not sent to the JSP. If I send the UID/PWD instead of cookie as below the authentication succeeds and response is sent correctly.
urlConnection.setRequestProperty("username", "testuser");
urlConnection.setRequestProperty("password", "testpwd");
Is this the right way of sending cookie over HTTPURLConnection? or are there other parameters that need to be set?
You may want to try removing the URLEncoder.encode from the entire sCookies String. The cookie format should be in the form of NAME=VALUE, but by URLEncoding the whole string you will escape the =.