XML-RPC authentication (http vs. XmlRpcNotAuthorizedException) - java

I could not find an exact answer to my question (either google or here), so my apologies if this is a repeat that I missed:
I am writing a XML-RPC server using Apache's XML-RPC libraries (which I'm regretting a bit) in Java that needs to conform to a given specification. With authentication, the server generates an org.apache.xmlrpc.common.XmlRpcNotAuthorizedException. This is not the behaviour that is required. I would like to return an HTTP error 401 (not authenticated) and 403 (forbidden) instead. However, Apache keeps on throwing these exceptions and I cannot find a way around it.
For example response received after sending correct username/password:
HTTP/1.1 200 OK
Content-Length:362
Content-Type:text/xml
Server:Jetty(7.x.y-SNAPSHOT)
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
...correct response information here
</methodResponse>
...and wrong username and password:
HTTP/1.1 200 OK
Content-Length:252
Content-Type:text/xml
Server:Jetty(7.x.y-SNAPSHOT)
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
...xmlrpc exception here
<methodResponse>
I don't want "HTTP/1.1 200 OK", I want "HTTP/1.1 401 Unauthorized"
I was considering inheriting Apache's ReflectiveXmlRpcHandler (or something similar) and trying to intercept the exception, but I was wondering if someone else have found a better idea to this problem.
Any ideas?

That seems to be difficult. As stated in the XML-RPC Specification
Response format
Unless there's a lower-level error, always return 200 OK.
Bad Authentication Credentials is not a low-level error, it's just a particular use case.
But you can enable Exceptions on the client side (be aware of security issues) to handle this particular case

I would post code but it touches a few too many places and by the time I had it here, it was an essay...
What I did:
Created PropagatedHttpException extending RuntimeException. It just has one field, code, which is the HTTP error code.
Extend XmlRpcServletServer:
Override writeError to check if the error is a PropagatedHttpException and if it is,
throw it back out immediately.
Override execute(HttpServletRequest, HttpServletResponse) to catch
PropagatedHttpException and pass it on as a proper HTTP error.
Extend XmlRpcServlet:
Set a custom AuthenticationHandler which throws PropagatedHttpException for
specific HTTP error codes.
Override newXmlRpcServer to return the custom XmlRpcServletServer.
We already had a custom authentication handler when we started to figure out how this would work but in your case maybe it isn't needed and the writeError code could be adjusted to check for XmlRpcNotAuthorizedException. Actually I had no idea this exception existed until today...
The problem you'll have now is that from the client side, Apache XML-RPC doesn't check the error code it gets back and then tries to parse the XML response irrespective of the result.
Grooveek's answer is extremely disheartening to us as we want authentication to be hooked into the JRE's built-in authentication so that things like NTLM can work, but if it's going to return an HTTP 200 then it is impossible for this to ever work without breaking the spec.

Related

Best practise to write a boolean API in Java Sturts 2 server?

I need to write an API to check if a user name already exists in a database.
I want my server (Struts Action class instance in tomcat server) to return true/false.
Its something like this
checkUserName?userName=john
I want to know what is the standard way to do this?
Shall I return a JSON response with just one boolean value ... seems like a overkill.
Shall I do something like manually setting the HTTP header to 200 or 404 (for true/false), but that seems to violate the actual purpose of using the headers which I believe must only be used to indicate network failures etc.
(Too long for a comment.)
I don't see any reason not to return a standard JSON response with something indicating whether or not the user name exists. That's what APIs do: there's nothing "overkill" about providing a response useful across clients.
To your second point: headers do a lot more than "indicate network problems". A 404 isn't a network problem, it means the requested resource doesn't exist. It is not appropriate in your case, because you're not requesting a resource: the resource is checkUserName, which does exist. If instead your request was /userByName/john a 404 would be appropriate if the user didn't exist. That's not an appropriate request in this case, because you don't want to return the user.
A 401 isn't a network problem, it's an authentication issue. A 302 isn't a network problem, it's a redirect. Etc. Using HTTP response codes is entirely appropriate, if they match your requests.

REST endpoint returns different results in AWS vs. localhost

EDIT: It looks like my observation that both localhost and AWS were returning 409 was incorrect. AWS is returning 500 (which I would still expect to return null, as the #ExceptionHandler method for Exception.class clearly sets the status to 500 and returns null). Looking closer at the exception message, "could not inspect JDBC autocommit mode; nested exception is org.hibernate.exception.GenericJDBCException: could not inspect JDBC autocommit mode", this is looking more like a database-issue.
ORIGINAL:
I have a RESTful service written in Java/Spring. In this service, I have 3 #ExceptionHandler methods, all of which return null. Only one exception sets the status to 409 Conflict, which is the one I'm expecting in my current scenario.
While testing the service with Postman on localhost, under a particular circumstance, I get an expected 409 Conflict with no data body. However, when I hit the service after being deployed on amazonaws.com, I get the 409 Conflict with a result body consisting of timestamp, status, error, exception, and message values. The version returned by /manage/info looks correct and the git commit data is reported exactly the same.
The localhost version returns 4 headers (plus a custom one):
Content-Length = 0
Date = (today)
Server = Apache-Coyote/1.1
X-Application-Context = application
The Amazon AWS version returns 5 headers (plus the same custom one):
Content-Type = application/json;charset=UTF-8
Date = (today)
Server = Apache-Coyote/1.1
Transfer-Encoding = chunked
X-Application-Content = application, application
What could be causing this? My application calling the service ~could~ handle either situation, but it seems wrong to bandage a fix there when obviously something weird is going on in the service, itself. It was coded to expect null, not a body consisting of values that would not be part of a non-409 result.
What could be causing this?
It is most likely the web-app framework that you are using to run the service. It might be an inherent difference in framework software (on your local machine and AWS), or there could be configuration differences.
(I note that you haven't mentioned how you are running the service locally.)
My application calling the service ~could~ handle either situation, but it seems wrong to bandage a fix there when obviously something weird is going on in the service, itself. It was coded to expect null, not a body consisting of values that would not be part of a non-409 result.
I disagree that there is "obviously something weird" going on. This is the sort of thing that >>I<< would expect if I tried to run a web service on a range of different web platforms. Especially if I was taking a "light touch" approach to configuration / deployment.
You could probably make your local host platform handle error responses more like AWS, and possibly the other way around.
But I think the simple solution is to change the client to work with both kinds of error response.
I think my answer still applies to your updated question. Modify your client code to handle error responses with and without bodies. It is also worth logging the response body for unexpected responses.

HTTP 405 - Method Not Allowed error on a 200 OK response

I have a small REST-ful Java back-end that some clients written in C connect to. There is a certain POST method they call where they send some information, I save that to a database and respond with 200 OK, if all goes well. Basic structure shown below.
#POST
#Path("/mypath")
#Produces("text/html")
public Response processMessage(final String message, #Context final HttpServletRequest request) throws IOException {
.....
return Response.ok().build();
}
My issue is that on this response, I get the following error in the log:
javax.ws.rs.NotAllowedException: No resource method found for , return 405 with Allow header
I understand what this error means in circumstances when let's say you try to execute a GET on an endpoint that is supposed to be a POST, for example. I can't understand though why I would get this after my response goes out, and it clearly shows that the request type is empty.... so odd.
Some additional info - the code on the client side has been buggy with incorrect HTTP code... but what would have to be wrong on the client side to cause this kind of response? (I do not have access to the client side code).
Also, there is no client side code in my app, if you are wondering if there is some other code making a call out of my webapp.
Thanks for any ideas!
The issue is most likely on the client side, so without seeing that code it is difficult to offer more detailed information -- but my expectation would be that this is a result of your client attempting to do something like POST or PUT credentials, or something along that line.
Your only recourse is to enable verbose request logging, log the requests that are generating 405 errors, and report it to the client developers.
Worth noting, however, that any publicly-exposed APIs will generate piles of 405s and 404s because "hackers" will try to execute things like WordPress hacks and so on against any known URL.

How to parse a custom XML-style error code response from a website

I'm developing a program that queries and prints out open data from the local transit authority, which is returned in the form of an XML response.
Normally, when there are buses scheduled to run in the next few hours (and in other typical situations), the XML response generated by the page is handled correctly by the java.net.URLConnection.getInputStream() function, and I am able to print the individual results afterwards.
The problem is when the buses are NOT running, or when some other problem with my queries develops after it is sent to the transit authority's web server. When the authority developed their service, they came up with their own unique error response codes, which are also sent as XMLs. For example, one of these error messages might look like this:
<Error xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Code>3005</Code>
<Message>Sorry, no stop estimates found for given values.</Message>
</Error>
(This code and similar is all that I receive from the transit authority in such situations.)
However, it appears that URLConnection.getInputStream() and some of its siblings are unable to interpret this custom code as a "valid" response that I can handle and print out as an error message. Instead, they give me a more generic HTTP/1.1 404 Not Found error. This problem cascades into my program which then prints out a java.io.FileNotFoundException error pointing to the offending input stream.
My question is therefore two-fold:
1. Is there a way to retrieve, parse, and print a custom XML-formatted error code sent by a web service using the plugins that are available in Java?
2. If the above is not possible, what other tools should I use or develop to handle such custom codes as described?
URLConnection isn't up to the job of REST, in my opinion, and if you're using getInputStream, I'm almost certain you're not handling character encoding correctly.
Check out Spring's RestTemplate - it's really easy to use (just as easy as URLConnection), powerful and flexible. You will need to change the ResponseErrorHandler, because the default one will throw an exception on 404, but it looks like you want it to carry on and parse the XML in the response.

What Java exception class to use for HTTP errors?

I am using Apache HttpClient and would like to communicate HTTP errors (400 Bad Request, 404 Not Found, 500 Server Error, etc.) via the Java exception mechanism to the calling code. Is there an exception in the Java standard library or in a widely used library that would be appropriate to use or to subclass for this purpose?
The alternative is to check status return codes. This appears to be the HttpClient design philosophy, but since these errors are truly exceptional in my app, I would like to have the stack trace and other nice exception things set up for me when they happen.
If it's not an Exception in HttpClient design philosophy, but an Exception in your code, then create your own Exception classes. ( As a subclass of org.apache.commons.httpclient.HttpException )
Quick answer
In Spring you have exactly what you want:
HttpClientErrorException - Exception thrown when an HTTP 4xx is received.
HttpServerErrorException - Exception thrown when an HTTP 5xx is received.
And a recommended practice
Minimally, you should differentiate exceptions related to business logic (e.g., insufficient balance, email address is not valid) from other exceptions (e.g., server not available, unsupported media type, SQLException).
In our REST API, we have a library for Java clients that parses responses and throws only three different exceptions:
400, 401, 403, 404, 409, 422: throw MyBusinessException, which contains a message that can be shown to the end user. The message comes in the response body (exception handling on the service side), but if not present we have a default message specific to each status code.
405, 412, 415: throw HttpClientErrorException with a message that is specific to each status code.
other 4xx codes: throw HttpClientErrorException with a generic message.
5xx codes: throw HttpServerErrorException with a generic message.
All these exceptions are unchecked.
Check out the page on Exception Handling for HttpClient
To answer your question though there appears to be an org.apache.commons.httpclient.HttpException class that is probably a good fit.
If you do need a custom exception class for this I would think java.io.IOException would be the correct super class to use.
I'd say this depends on what you are using the HTTPClient for. For example, the PayPal SDK uses HttpClient to transmit API calls to the PayPal server, but fails to check the HTTP response code when it's done. I patched my copy so that if the response code isn't 200 it throws a PayPal FatalException, with an appropriate message. That's because the caller isn't interested in the HTML or any of the details of this HTTP post, and isn't even interested in the fact that we're using HTTP as a transport. If the call is successful then the body of the response contains transaction details, which are extracted and placed into a response object; otherwise it contains HTML which is useless. HTTP is just the transport in this case, so certain response codes indicate errors which can be reported using exceptions. Because this is part of the PayPal SDK, I used a PayPal Exception class. In some other system or library, I'd use a subtype of whatever exceptions that library already uses. For example, if I were writing a GMail library, which accesses GMail accounts, I'd probably create a GMailException class, and subclass that for the different kinds of exceptions the library runs into. Alternatively, you can use something like IOException.
The reason HttpClient makes you check response codes is because the response may be useful even if the response code is not 200. Some websites put useful text on a 404 page, either providing something useful for the user to do, or a search form, or just a helpful error message. Depending on your use case you may want to just show the response content rather than throw an exception.
I found this exception on Apache HTTP Client 4.5.7:
...
import org.apache.http.client.HttpResponseException;
...
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() != 200) {
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
...
The sample of result is:
Exception in thread "main" org.apache.http.client.HttpResponseException: status code: 400, reason phrase: Bad Request
There is org.apache.commons.httpclient.HttpException if you want a library exception. We have also sometimes created our own for specific purposes, both creating an exception for specific HTTP status codes and a generic one for and unexpected status code.

Categories

Resources