Android: not getting xml out of http get request with basic authentication - java

My goal is to get the xml from an API. The API uri I use, including parameters is http://webservices.ns.nl/ns-api-treinplanner?fromStation=Roosendaal&toStation=Eindhoven. I am given a username and password, for what I think probably is basic authorization.
I tried various things like something with an Authenticator, the format http://username:password#webservices.ns.nl/ns-api-treinplanner, but at the end of a lot of SO searching I ended up with something with a setRequestProperty with the basic authorization.
I put the code into an AsyncTask which seems to work correctly so I will just put the code from inside doInBackground in here.
As the java FileNotFoundException I first got didn't give me much information, I found out how to use the getErrorStream to find out more.
InputStream in;
int resCode;
try {
URL url = new URL("http://webservices.ns.nl/ns-api-treinplanner?fromStation=Roosendaal&toStation=Eindhoven");
String userCredentials = "username:password";
String encoding = new String(android.util.Base64.encode(userCredentials.getBytes(), Base64.DEFAULT));
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic " + encoding);
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
try {
resCode = urlConnection.getResponseCode();
if (resCode == HttpURLConnection.HTTP_OK) {
Log.i("rescode","ok");
in = urlConnection.getInputStream();
} else {
Log.i("rescode","not ok");
in = urlConnection.getErrorStream();
}
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(in));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
finally{
urlConnection.disconnect();
}
}
catch(Exception e) {
Log.e("ERROR", e.getMessage(), e);
return null;
}
Then, in onPostExecute I print the response, but the response I get is
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<soap:Header></soap:Header>
<soap:Body><soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>006:No customer found for the specified username and password</faultstring></soap:Fault>
</soap:Body></soap:Envelope>
This is of course not right, it should give a full xml of in this case a train voyage recommendation.
I tested with my browsers, and also using a HTTP request tool called Postman which returned the correct xml so all the uri's, parameters, username and password are correct.

The encoding used is wrong. The base64 encoding used randomly returns whitespaces in the middle, adding encoding = encoding.replaceAll("\\s+",""); actually fixed it.

Related

Reflected XSS on BufferedReader readLine() method

I have scanned a java web project with the Checkmarx tool, and the analysis marks an XSS vulnerability in a method where a web service is executed that responds a JSON, the vulnerability is in the line while((output = Encode.forJava(br.readLine())) != null) {, specifically in br.readLine().
Checkmarx says:
The attacker would be able to alter the returned web page by simply
providing modified data in the user input readLine, which is read by
the NetClientPost method. This input then flows through the code
straight to the output web page, without sanitization.
This can enable a Reflected Cross-Site Scripting (XSS) attack.
I tried with OWASP for Java, implementing the method Encode.forJava(), but the vulnerability continues to appear in the analysis. This is the implementation of the method:
public String NetClientPost (String urlSer, String param){
String result ="";
try {
InetAddress ip = InetAddress.getLocalHost();
String host = ip.getHostAddress();
doTrustToCertificates();
URL url = new URL(urlSer);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setConnectTimeout(2000);
String input = param;
String output = "";
try(OutputStream os = conn.getOutputStream()) {
os.write(input.getBytes());
os.flush();
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP code : " + conn.getResponseCode());
}
try (BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())))) {
while ((output = Encode.forJava(br.readLine())) != null) {//LINE OF CHECKMARX XSS
result += output;
}
}
}
conn.disconnect();
return result;
} catch (MalformedURLException e) {
return result;
} catch (IOException e) {
return result;
} catch (Exception e) {
return result;
}
}
Any have an idea of how to solve this?
Try parsing the incoming data as JSON and then serializing it back to a string before sending it on.
That way you can be sure that your method only returns JSON to the client. If for some reason, your incoming data isn't JSON, then your method would encounter an error parsing the JSON, which you can then handle appropriately.
Encode.forJava isn't a helpful method to use here: it is used to encode a string to be inserted into a Java string literal.
output = Encode.forHtmlAttribute(br.readLine() works for me

How i can get connected with qc 12 with rest api

Can u please help me to understand with simple piece of java code to get connect wth qc 12 using rest api.
I gone thorough the rest api documentation but am not clear with how to start with.but it will be helpful if people can show me a simple java code for authentication(login,logout or getting defect details) using rest api. Also want to know do i need to include any jars in my build path.
Thanks a lot friends.
I don't quite get what you're asking, but if you want to connect to a REST API, there are several ways... I usually use HttpURLConnection, here's an example of a get:
public String getProfile(String URL) throws IOException {
URL getURL = new URL(url);
//Establish a https connection with that URL.
HttpURLConnection con = (HttpURLConnection) getURL.openConnection();
//Select the request method, in this case GET.
con.setRequestMethod("GET");
//Add the request headers.
con.setRequestProperty("header", headerValue);
System.out.println("\nSending 'GET' request to URL : " + url);
int responseCode;
try {
responseCode = con.getResponseCode();
System.out.println("Response Code : " + responseCode);
} catch (Exception e) {
System.out.println("Error: Connection problem.");
}
InputStreamReader isr = new InputStreamReader(con.getInputStream());
BufferedReader br = new BufferedReader(isr);
StringBuffer response = new StringBuffer();
String inputLine;
while ((inputLine = br.readLine()) != null) {
//Save the response.
response.append(inputLine + '\n');
}
br.close();
return response.toString();
}

Java HTTP post assistance

I've been working with the Slack API in java and have been trying to get an HTTP method that can be used like my below example block of code. That code block works, but the issue is I need to also include a 200 response code, and can't figure out how to get it to work.
Basically, how can I, In Java, send an HTTP post and also tag on the 200 status code using the URL and the content?
Current code:
public void httpRequest(URL url, String content) {
try {
byte[] contentBytes = content.getBytes("UTF-8");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Content-Length", Integer.toString(contentBytes.length));
connection.setRequestProperty("Status", Integer.toString(200));
OutputStream requestStream = connection.getOutputStream();
requestStream.write(contentBytes, 0, contentBytes.length);
requestStream.close();
String response = "";
BufferedReader responseStream;
response = "" + ((HttpURLConnection) connection).getResponseCode();
try {
if (((HttpURLConnection) connection).getResponseCode() == 200) {
responseStream = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
} else {
responseStream = new BufferedReader(new InputStreamReader(((HttpURLConnection) connection).getErrorStream(), "UTF-8"));
}
response = responseStream.readLine();
responseStream.close();
} catch (NullPointerException ignored) {
}
} catch (IOException e) {
e.printStackTrace();
}
}
The call to setDoOutput(true) triggers a post, i.e. you do not need to add
connection.setRequestMethod("POST");
Adding a status header to the request is possible, as you have done, but typically one associates status codes with http responses, not requests. - And off course, adding such custom header would only make sense if the server was designed to use this information to anything.
See this big, and highly up-voted answer on java.net.HttpURLConnection.
Also, you have some problems relating to your response variable as well as the BufferedReader. You accidentally override the value you initially assigned to the response field, instead of concatening. Also, your readLine() should probably be in a loop:
String tmp;
while ((tmp = responseStream.readLine()) !=null){
response += tmp;
}

Weird behavior when downloading html using HttpURLConnection

In my Wikipedia reader app for Android, I'm downloading an article's html by using HttpURLConnection, some users report that they are unable to see articles, instead they see some css, so it seems like their carrier is somehow preprocessing the html before it's downloaded, while other wikipedia readers seem to work fine.
Example url: http://en.m.wikipedia.org/wiki/Black_Moon_(album)
My method:
public static String downloadString(String url) throws Exception
{
StringBuilder downloadedHtml = new StringBuilder();
HttpURLConnection urlConnection = null;
String line = null;
BufferedReader rd = null;
try
{
URL targetUrl = new URL(url);
urlConnection = (HttpURLConnection) targetUrl.openConnection();
if (url.toLowerCase().contains("/special"))
urlConnection.setInstanceFollowRedirects(true);
else
urlConnection.setInstanceFollowRedirects(false);
//read the result from the server
rd = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
while ((line = rd.readLine()) != null)
downloadedHtml.append(line + '\n');
}
catch (Exception e)
{
AppLog.e("An exception occurred while downloading data.\r\n: " + e);
e.printStackTrace();
}
finally
{
if (urlConnection != null)
{
AppLog.i("Disconnecting the http connection");
urlConnection.disconnect();
}
if (rd != null)
rd.close();
}
return downloadedHtml.toString();
}
I'm unable to reproduce this problem, but there must be a way to get around that? I even disabled redirects by setting setInstanceFollowRedirects to 'false' but it didn't help.
Am I missing something?
Example of what the users are reporting:
http://pastebin.com/1E3Hn2yX
carrier is somehow preprocessing the html before it's downloaded
a way to get around that?
Use HTTPS to prevent carriers from rewriting pages. (no citation)
Am I missing something?
not that I can see

Preemptive Basic Auth with HttpUrlConnection?

What is the best way to use preemptive basic http authentication using HttpUrlConnection. (Assume for now I can't use HttpClient).
EDIT for clarification: I'm setting the un/pw correctly in the request header using Base64 encoding. Are there any additional flags or properties that need to be set, or is the fact that I'm setting the basic auth headers for the request all that is needed for preemptive basic auth?
If you are using Java 8 or later, java.util.Base64 is usable:
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
String encoded = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8)); //Java 8
connection.setRequestProperty("Authorization", "Basic "+encoded);
Then use the connection as normal.
If you're using Java 7 or lower, you'll need a method to encode a String to Base64, such as:
byte[] message = (username+":"+password).getBytes("UTF-8");
String encoded = javax.xml.bind.DatatypeConverter.printBase64Binary(message);
Yes, that's all you have to do in order to use Basic Auth. The code above to set the Request Property should be done immediately after opening the connection and before getting the Input or Output streams.
Incidentally, in case someone else runs into the same, the android problem, is also present if you use org.apache.commons.codec.binary.Base64 and do Base64.encodeBase64String(). You need to do Base64.encodeBase64() and get a byte[] then construct the string.
It caught me offguard entirely that the results would be different for the line ending between those two methods.
You can use java.net.Authenticator to configure basic auth. globally for every request send by your application, see :
http://docs.oracle.com/javase/7/docs/technotes/guides/net/http-auth.html
http://developer.android.com/reference/java/net/Authenticator.html#getPasswordAuthentication()
you need to do this just copy paste it be happy
HttpURLConnection urlConnection;
String url;
// String data = json;
String result = null;
try {
String username ="danish.hussain#gmail.com";
String password = "12345678";
String auth =new String(username + ":" + password);
byte[] data1 = auth.getBytes(UTF_8);
String base64 = Base64.encodeToString(data1, Base64.NO_WRAP);
//Connect
urlConnection = (HttpURLConnection) ((new URL(urlBasePath).openConnection()));
urlConnection.setDoOutput(true);
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Authorization", "Basic "+base64);
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(10000);
urlConnection.connect();
JSONObject obj = new JSONObject();
obj.put("MobileNumber", "+97333746934");
obj.put("EmailAddress", "danish.hussain#dhl.com");
obj.put("FirstName", "Danish");
obj.put("LastName", "Hussain");
obj.put("Country", "BH");
obj.put("Language", "EN");
String data = obj.toString();
//Write
OutputStream outputStream = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
writer.write(data);
writer.close();
outputStream.close();
int responseCode=urlConnection.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
//Read
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
bufferedReader.close();
result = sb.toString();
}else {
// return new String("false : "+responseCode);
new String("false : "+responseCode);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
I was having this problem too.
And Now I have solved this problem.
My code is :
URL url = new URL(stringUrl);
String authStr = "MyAPIKey"+":"+"Password";
System.out.println("Original String is " + authStr);
// encode data on your side using BASE64
byte[] bytesEncoded = Base64.encodeBase64(authStr .getBytes());
String authEncoded = new String(bytesEncoded);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic "+authEncoded);
It may help many others.
Best of luck.
Regarding the Base64 encoding problem, I found this library: http://sourceforge.net/projects/migbase64/
I have not fully vetted it but I am using it for the Basic Authentication solution shown above (as well as for image encoding/decoding), and it works well. It provides a parameter for whether or not to include the newline.

Categories