Android HttpURLConnection always unauthorized 401 response (Spring Boot REST API) - java

I am attempting to consume a REST API with an Android app I am developing in Android Studio. I have developed the API using Spring Boot. The issue:
Whenever I make a call to my API I am always returned a 401 Unauthorized response. "Pre-authenticated entry point called. Rejecting access."
I have configured my CORS as follows:
cors:
allowed-origins: "*"
allowed-methods: GET, PUT, POST, DELETE, OPTIONS
allowed-headers: "*"
exposed-headers:
allow-credentials: true
max-age: 1800
My api is running on localhost:8080, and I am making the requests from my device with my WLAN IPv4 address.
Such as: curl -v -X GET http://192.168.1.xx:8080/api/users
This returns a 200 OK response.
I am also able to call this in postman/DHC etc.. and receive a 200 OK response.
However, when I call this same address with HttpURLConnection through my android device, I receive a 401 response.
Noob developer here - any ideas as to what might be causing this would be greatly appreciated!
Edit to include my GET Request:
#Override
protected String doInBackground(String... params){
String stringUrl = params[0];
String result;
String inputLine;
try {
//Create a URL object holding our url
URL myUrl = new URL(stringUrl);
//Create a connection
HttpURLConnection connect =(HttpURLConnection)
myUrl.openConnection();
connect.setRequestMethod(REQUEST_METHOD); // GET
connect.setRequestProperty("Host", HOST);
connect.setRequestProperty("Connection", "keep-alive");
connect.setRequestProperty("Origin", ORIGIN);
connect.setRequestProperty("User-Agent", System.getProperty("http.agent"));
connect.setRequestProperty("Content-Type", CONTENT_TYPE);
connect.setRequestProperty("Accept", "*/*");
connect.setRequestProperty("Accept-Encoding", ACCEPT_ENCODING);
connect.setRequestProperty("Accept-Language", ACCEPT_LANGUAGE);
connect.setDoOutput(true);
connect.setDoInput(true);
//Connect to our url
connect.connect();
String responseMessage = connect.getResponseMessage(); // Unathorized
int responseCode = connect.getResponseCode(); //401
//Create a new InputStreamReader
InputStreamReader streamReader = new
InputStreamReader(connect.getInputStream());
//Create a new buffered reader and String Builder
BufferedReader reader = new BufferedReader(streamReader);
StringBuilder stringBuilder = new StringBuilder();
//Check if the line we are reading is not null
while((inputLine = reader.readLine()) != null){
stringBuilder.append(inputLine);
}
//Close our InputStream and Buffered reader
reader.close();
streamReader.close();
//Set our result equal to our stringBuilder
result = stringBuilder.toString();
}
catch(IOException e){
e.printStackTrace();
result = null;
}
return result;
}

Replace:-
InputStreamReader streamReader = new
InputStreamReader(connect.getInputStream());
With:-
InputStreamReader streamReader = new
InputStreamReader(connect.getErrorStram());
This will help you track why 401 then you can proceed solving that issue.
401-- is server side problem, Server is unable to process you request, check if you have to pass data in header or url as you are using get request

Related

Java - Reading POST from HttpURLConnection throwing response code 400

I am opening an HttpURLConnection and with POST method, I am sending a JSON request that I build form another class. The JSON is structured correctly since I have validated it on debugging. The exception is thrown when trying to read the output response given from the server. This is the Error given
java.io.IOException: Server returned HTTP response code: 400 for URL:
However when I manually try to enter the Url from a web browser with a POST method chrome extension. I can view the response and everything works. So I am sure it has something to do with the following code where I make the connection and read/write.
URL obj = new URL(url);
HttpURLConnection connection = (HttpURLConnection) obj.openConnection();
//add request header
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
//mapping objects to json
BatchRequest requestParameters = new BatchRequest(o,d);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(requestParameters);
connection.setDoOutput(true);
DataOutputStream os = new DataOutputStream(connection.getOutputStream());
os.writeBytes(json);
os.flush();
os.close();
// this is where the program throws the exception
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
Both the URL and the JSON request are correct since They work when I try a manual conenction over a browser.
A DataOutputStream is not needed. Just:
OutputStream os = con.getOutputStream();

Java Http request PUT : 401 unauthorized

I'm trying to send a PUT request from a Java app to a server. I successfully send GET, POST and DELETE requests but the PUT one won't succeed (I'm getting a 401 Error with the code below, 405 Error with an other code using the HttpPut of the apache package).
I'm using java.net.HttpURLConnection, here is a small region of my code :
URL obj = new URL(urlPost);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
//add request header
con.setRequestMethod(typeRequest); //typeRequest = PUT
String credentials = adminOC + ":" + pwdOC;
String encoding = Base64.encode(credentials.getBytes("UTF-8"));
con.setRequestProperty("Authorization", String.format("Basic %s", encoding));
if (!typeRequest.equals("GET")){
con.setDoOutput(true);
try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {
wr.writeBytes(postParam);
wr.flush();
}
}
if (con.getResponseCode() == 200){
try (BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()))) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
response += inputLine;
}
}
}
I tried sending my PUT parameters the "POST" way and also directly in the URL.
It seems to be an error from my Java code and not from the server because I tried to do the PUT request with cURL and it worked.
Thanks for reading, I hope you will be able to give me some hints to debug the problem.
What is missing in your code is con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")

POST Requests from a Servlet

I am writing a servlet using eclipse that receives POST request from a client that should do some splitting on the received text, access google geolocation api to get some data and display to the user.
On a localhost, this works perfectly fine. On an actual server (tried with Openshift and CloudBees), this doesn't work. I can see the splitting reply but not the reply from google geolocation service. There is always an error logged into the console from google service. However, the same code works perfectly fine on localhost.
After I receive the POST request in the doPost method of the servlet, I am doing the following to access the Google GeoLocation service:
//Attempting to send data to Google Geolocation Service
URL url;
HttpURLConnection connection = null;
try {
//Create connection
url = new URL("https://www.googleapis.com/geolocation/v1/geolocate?key=MyAPI");
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setUseCaches (false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request with data (output variable has the JSON data)
DataOutputStream wr = new DataOutputStream (
connection.getOutputStream ());
wr.writeBytes (output);
wr.flush ();
wr.close ();
//Get Response
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response2 = new StringBuffer();
while((line = rd.readLine()) != null) {
response2.append(line);
response2.append('\r');
}
rd.close();
//Write to Screen using out=response.getWriter();
out.println("Access Point's Location = " + response2.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if(connection != null) {
connection.disconnect();
}
Could you tell me why this is happening and how can I make this work? Should I resort to something like AJAX or is there someother work around? I am relatively new to coding and hence, trying to refrain from learning AJAX at this stage. Please let me if there's any other way of getting this to work
Your localhost has your localhost IP as a sending IP. Openshift et al has the Openshift et al IP as a sending IP. So the Google API says "I have only seen that localhost IP twice before, that's fine!", whereas it says "I have seen this Openshift IP millions of times before! NO REPLY FOR YOU!"

How to get the Response Back from the Remote Server using an HttpURLConnection Object?

I am trying to send an HTTP POST Request to a remote server using an instance of the HttpURLConnection class. Although, I am able to get a response code and a response message, when I try to write the input stream into a StringBuffer, I am not able to actually read any lines.
When I analyzed the packets sent from WireShark, I noticed that a full response was being sent from the remote server. My only guess as to why I am not able to see it in the Java program is because the time in which I try to read from the InputStream is too late.
So, how do I read the immediate, full response from the remote server using my HttpURLConnection object? Below is the code that I am using:
HttpURLConnection conn = null;
String urlStr = "...";
URL url = null;
try
{
url = new URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
...
BufferedReader rd = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = rd.readLine()) != null)
{
sb.append(line);
}
rd.close();
...
}...
Okay, never mind. It turns out that what I was looking for was in the HTTP Respone's header. So, I got what I needed by looking through its headers. ::Face Palm::

FileNotFoundException while getting the InputStream object from HttpURLConnection

I am trying to send a post request to a url using HttpURLConnection (for using cUrl in java).
The content of the request is xml and at the end point, the application processes the xml and stores a record to the database and then sends back a response in form of xml string. The app is hosted on apache-tomcat locally.
When I execute this code from the terminal, a row gets added to the db as expected. But an exception is thrown as follows while getting the InputStream from the connection
java.io.FileNotFoundException: http://localhost:8080/myapp/service/generate
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1401)
at org.kodeplay.helloworld.HttpCurl.main(HttpCurl.java:30)
Here is the code
public class HttpCurl {
public static void main(String [] args) {
HttpURLConnection con;
try {
con = (HttpURLConnection) new URL("http://localhost:8080/myapp/service/generate").openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
File xmlFile = new File("test.xml");
String xml = ReadWriteTextFile.getContents(xmlFile);
con.getOutputStream().write(xml.getBytes("UTF-8"));
InputStream response = con.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(response));
for (String line ; (line = reader.readLine()) != null;) {
System.out.println(line);
}
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Its confusing because the exception is traced to the line InputStream response = con.getInputStream(); and there doesn't seem to be any file involved for a FileNotFoundException.
When I try to open a connection to an xml file directly, it doesn't throw this exception.
The service app uses spring framework and Jaxb2Marshaller to create the response xml.
The class ReadWriteTextFile is taken from here
Thanks.
Edit:
Well it saves the data in the DB and sends back a 404 response status code at the same time.
I also tried doing a curl using php and print out the CURLINFO_HTTP_CODE which turns out to be 200.
Any ideas on how do I go about debugging this ? Both service and client are on the local server.
Resolved:
I could solve the problem after referring to an answer on SO itself.
It seems HttpURLConnection always returns 404 response when connecting to a url with a non standard port.
Adding these lines solved it
con.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
con.setRequestProperty("Accept","*/*");
I don't know about your Spring/JAXB combination, but the average REST webservice won't return a response body on POST/PUT, just a response status. You'd like to determine it instead of the body.
Replace
InputStream response = con.getInputStream();
by
int status = con.getResponseCode();
All available status codes and their meaning are available in the HTTP spec, as linked before. The webservice itself should also come along with some documentation which overviews all status codes supported by the webservice and their special meaning, if any.
If the status starts with 4nn or 5nn, you'd like to use getErrorStream() instead to read the response body which may contain the error details.
InputStream error = con.getErrorStream();
FileNotFound is just an unfortunate exception used to indicate that the web server returned a 404.
To anyone with this problem in the future, the reason is because the status code was a 404 (or in my case was a 500). It appears the InpuStream function will throw an error when the status code is not 200.
In my case I control my own server and was returning a 500 status code to indicate an error occurred. Despite me also sending a body with a string message detailing the error, the inputstream threw an error regardless of the body being completely readable.
If you control your server I suppose this can be handled by sending yourself a 200 status code and then handling whatever the string error response was.
For anybody else stumbling over this, the same happened to me while trying to send a SOAP request header to a SOAP service. The issue was a wrong order in the code, I requested the input stream first before sending the XML body. In the code snipped below, the line InputStream in = conn.getInputStream(); came immediately after ByteArrayOutputStream out = new ByteArrayOutputStream(); which is the incorrect order of things.
ByteArrayOutputStream out = new ByteArrayOutputStream();
// send SOAP request as part of HTTP body
byte[] data = request.getHttpBody().getBytes("UTF-8");
conn.getOutputStream().write(data);
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.d(TAG, "http response code is " + conn.getResponseCode());
return null;
}
InputStream in = conn.getInputStream();
FileNotFound in this case was an unfortunate way to encode HTTP response code 400.
FileNotFound in this case means you got a 404 from your server - could it be that the server does not like "POST" requests?
FileNotFound in this case means you got a 404 from your server
You Have to Set the Request Content-Type Header Parameter
Set “content-type” request header to “application/json” to send the request content in JSON form.
This parameter has to be set to send the request body in JSON format.
Failing to do so, the server returns HTTP status code “400-bad request”.
con.setRequestProperty("Content-Type", "application/json; utf-8");
Full Script ->
public class SendDeviceDetails extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String data = "";
String url = "";
HttpURLConnection con = null;
try {
// From the above URL object,
// we can invoke the openConnection method to get the HttpURLConnection object.
// We can't instantiate HttpURLConnection directly, as it's an abstract class:
con = (HttpURLConnection)new URL(url).openConnection();
//To send a POST request, we'll have to set the request method property to POST:
con.setRequestMethod("POST");
// Set the Request Content-Type Header Parameter
// Set “content-type” request header to “application/json” to send the request content in JSON form.
// This parameter has to be set to send the request body in JSON format.
//Failing to do so, the server returns HTTP status code “400-bad request”.
con.setRequestProperty("Content-Type", "application/json; utf-8");
//Set Response Format Type
//Set the “Accept” request header to “application/json” to read the response in the desired format:
con.setRequestProperty("Accept", "application/json");
//To send request content, let's enable the URLConnection object's doOutput property to true.
//Otherwise, we'll not be able to write content to the connection output stream:
con.setDoOutput(true);
//JSON String need to be constructed for the specific resource.
//We may construct complex JSON using any third-party JSON libraries such as jackson or org.json
String jsonInputString = params[0];
try(OutputStream os = con.getOutputStream()){
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
}
int code = con.getResponseCode();
System.out.println(code);
//Get the input stream to read the response content.
// Remember to use try-with-resources to close the response stream automatically.
try(BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"))){
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
}
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.e("TAG", result); // this is expecting a response code to be sent from your server upon receiving the POST data
}
and call it
new SendDeviceDetails().execute("");
you can find more details in this tutorial
https://www.baeldung.com/httpurlconnection-post
The solution:
just change localhost for the IP of your PC
if you want to know this: Windows+r > cmd > ipconfig
example: http://192.168.0.107/directory/service/program.php?action=sendSomething
just replace 192.168.0.107 for your own IP (don't try 127.0.0.1 because it's same as localhost)
Please change
con = (HttpURLConnection) new URL("http://localhost:8080/myapp/service/generate").openConnection();
To
con = (HttpURLConnection) new URL("http://YOUR_IP:8080/myapp/service/generate").openConnection();

Categories

Resources