Should an optional, statically-defined resource that is unimplemented be defined as 403 or 501 (or something else)? - api

I have a device for which I am implementing an HTTP API and defining it via OpenAPI 3.0.
The following paths are defined:
/scan/inventory/start
/scan/location/start
/scan/direction/start
This API is designed to run on various devices, but not all of them implement the location or direction feature, but all do implement the inventory feature. The available features can be queried by GETing the /scan path.
For a device that does not support location my team has been waffling on the error code to return if someone attempts to use it. We want to provide useful feedback when this happens, so 404 seems ruled out, especially since the path is documented in our API. After reading and re-reading RFC-7231 and various summaries of it, 501 or 403 seemed like good choices.
At first, "501 Not Implemented" seemed like a good choice, but the 5XX class of errors seems to suggest a more serious server error.
Since we want to provide feedback, "403 Forbidden" seems good and puts the onus on the client for accessing a bad path.
I'm sure part of the problem is that we're attempting to use a specification (HTTP) that was not necessarily designed for arbitrary APIs.
What would you suggest we do?

This is a pretty straightforward 404.
The 404 (Not Found) status code indicates that the origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
403 isn't right, since that indicates that the user isn't "authorized" to access that resource. It implies that the issue lies on the client side. But in this case there simply is no resource.
501 isn't right, since that "indicates that the server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource." In this case the server has no problem supporting the request, it's just that the resource doesn't exist.
Note that "server" refers to the web server. The issue isn't whether or not your application as a whole supports some bit of functionality, it's whether the web server is capable of handling the HTTP request it was sent. It's not appropriate to use HTTP status codes to indicate that kind of high-level application state.
Also note that the status code isn't just a private contract between your application and its users. All actors in the web stack—loggers, intermediate caches, browsers, etc.—might change their behavior depending on the status code. That's why it's important to reserve things like 5xx for actual server errors.
To summarize, since the resource at that URI doesn't exist, the best way to provide useful feedback is to return a 404. If you want to distinguish between features that are never supported and those that are simply unsupported for that device you should use a mechanism other than the status code. Fortunately you're off to a good start by listing the available features at /scan.

Related

Getting 411 Response for http GET request on cloudflare URL

Our website uses cloudflare as it's CDN to handle loads.
One of our apps requests the URL http://www.codenameone.com/files/cn1libs/CN1JSON.cn1lib with a get request. This works fine for every machine/location we tested but we have user complaints that they are getting an HTTP 411: "Length Required" response.
Since this is a GET request content-length doesn't seem like a header we would need to send...
Our server logs don't show any 411 response so my only conclusion is that this is a failure on the cloudflare side. However, since we can't reproduce this and the cloudflare aspect is a black box I don't have much to go on in terms of debugging.
I tried contacting cloudflare support but effectively got the usual "run around" asking me to send traces from a users machine on the other side of the world which is not something I can realistically do.
After a long session with cloudflare support it seems that unless you are an enterprise subscriber log files for access just don't exist. So effectively their support sees cloudflare as a black box just like we do.
Since the problem clearly isn't in our servers my educated guess is that this is a bug in cloudflare related to some odd edge case.
If someone has a better answer than this I'll gladly accept it.

ending a passbook program - HTTP response to incoming passbook requests?

We attempted a passbook program but it never made it out of beta, but there are a few passes out there that keep phoning home (and throwing errors because the passes are out of sync with existing data). My plan is to 404 any incoming requests, but I'm not sure if that is the best way to handle existing passes. Any other ideas or is 404 the right solution?
There are a few of options:
Return an updated pass without that has a blank web service url
Return an appropriate error
Remove the DNS entry of the subdomain
Update the web service url
Any of the fields in the pass can be updated including the web service url. Removing the url will prevent further requests for updates. This s potentially the most effective, but would require a bit of development to return the updated pass and would need to be maintained until all passes have been "disabled."
Return an appropriate error code
It may be easier to simply return an error code. This could be done through the web server configuration preventing the requests from being processed by your application (and presumably stop the errors in the application). This would allow you to remove the code altogether from your application.
The Passbook Web Service Reference indicates that Passbook will eventually give up when receiving persistent errors.
If a request fails—for example, due to a network connectivity issue—Passbook tries again several times after waiting a period of time. Each time it tries again, it waits longer. If the request continues to fail, it eventually gives up.
The documentation also indicates that standard HTTP status codes should be used in the response from the call to Getting the Latest Version of a Pass (and others).
Response
If request is authorized, return HTTP status 200 with a payload of the pass data.
If the request is not authorized, return HTTP status 401.
Otherwise, return the appropriate standard HTTP status.
Discussion
Support standard HTTP caching on this endpoint: check for the If-Modified-Since header and return HTTP status code 304 if the pass has not changed.
It sounds like the ending of the passbook program is permanent in which case 410 Gone would be an appropriate error code. (From RFC 2616).
410 Gone
The requested resource is no longer available at the server and no forwarding address is known. This condition is expected to be considered permanent. Clients with link editing capabilities SHOULD delete references to the Request-URI after user approval. If the server does not know, or has no facility to determine, whether or not the condition is permanent, the status code 404 (Not Found) SHOULD be used instead. This response is cacheable unless indicated otherwise.
The 410 response is primarily intended to assist the task of web maintenance by notifying the recipient that the resource is intentionally unavailable and that the server owners desire that remote links to that resource be removed. Such an event is common for limited-time, promotional services and for resources belonging to individuals no longer working at the server's site. It is not necessary to mark all permanently unavailable resources as "gone" or to keep the mark for any length of time -- that is left to the discretion of the server owner.
Remove subdomain DNS
If your web service url was set up on a separate subdomain (e.g. passbook.example.com) you can simply remove the DNS entry for the subdomain. The requests will never reach the server and Passbook will eventually give up.

RESTful API Versioning

I'm a new to RESTful API's and sort of developing my first one at the moment for a mobile application to be followed. I have a question regarding API versions and how to manage/tackle them.
At this moment, my API 'version' is a directory named v<version_name> in which my API class resides. In that directory, I have resources that the API and REST client needs in another directory named include. So the structure is as follows: example.com/api/v0.2/method_name/ and on .htaccess, I'm making sure that everything that follows the API version (hardcoded in the .htaccess file, is saved in a query string parameter).
I'm not sure if it is the right approach for a live application as it requires manually changing the URL endpoints at clients' ends, too. So my questions are:
Is this the right approach to API versioning?
If it is and I keep it, how do I deal with outdated URL's. Say for instance the app is live and I update the API to v0.3 but the client who have the app installed would be accessing v0.2 and getting a 404 response code back?
Is there more elegant solution out there? It must be.
Edit: there are some resources that reside outside of the api folder itself, in the root include folder so to speak.
Edit 2: My API is targeted to be consumed by mobile applications and is not publicly consumable.
While I think these questions are primarily opinion-based, I will have a go...
I think it is a valid approach, and I've seen others use it,
including Microsoft.
When it is necessary to outdate an API, you could give a 404
back with an explanation that the new API is at the new address.
HOWEVER it is usually a bad idea to just retire an API version; you
would at least have to give client developers enough time to switch
to the new API before retiring the old, if at all.
A more elegant solution would be to just keep the API at one
address, and update that as necessary, and add to it rather than
replace whenever possible. Keep supporting outdated functions for as
long as possible and have open communication to client developers
about when a certain method will no longer work.
Just my opinion, do with it what you will...

How to obtain HttpServletRequest in AppservPasswordLoginModule (SSL)

In a customized Login Module I've developed for my application server (GlassFish 3.1.2.2), I'm using the following syntax to obtain the HttpServletRequest:
PolicyContext.getContext(HttpServletRequest.class.getName())
And it works fine.
But now I'm configuring the server to use only HTTPS and the same instruction returns null.
I guess this is a security restriction, but I'm not sure what needs to be changed in order to solve this issue (server.policy?).
To put this under context, I need to record the IP address of all login attempts, valid and invalid, and getting the request in the module seemed the most obvious solution.
Can someone help me to figure out a solution?
I can't help you directly with your question, but you may want to note that PolicyContext is a JACC class. It's spec'ed to work inside JACC policy providers. You may want to look at an article I wrote that explains this more in depth.
There is thus no specific guarantee that obtaining the HttpServletRequest works from inside a GlassFish proprietary login module, although I indeed have seen people using this more often and it typically works. The fact that it does not work when you switch to https sounds more like a bug or oversight to me than any specific security restriction.
A workaround for you could be to rewrite your login module as a Java EE standard auth module using JASPIC. I've also written an article about that subject which you could use for reference. In JASPIC you explicitly have access to the HttpServletRequest.

404 vs 403 when directory index is missing

This is mostly a philosophical question about the best way to interpret the HTTP spec. Should a directory with no directory index (e.g. index.html) return 404 or 403? (403 is the default in Apache.)
For example, suppose the following URLs exist and are accessible:
http://example.com/files/file_1/
http://example.com/files/file_2/
But there's nothing at:
http://example.com/files/
(Assume we're using 301s to force trailing slashes for all URLs.)
I think several things should be taken into account:
By default, Apache returns 403 in this scenario. That's significant to me. They've thought about this stuff, and they made the decision to use 403.
According to W3C, 403 means "The server understood the request, but is refusing to fulfill it." I take that to mean you should return 403 if the URL is meaningful but nonetheless forbidden.
403 might result in information disclosure if the client correctly guesses that the URL maps to a real directory on disk.
http://example.com/files/ isn't a resource, and the fact that it internally maps to a directory shouldn't be relevant to the status code.
If you interpret the URL scheme as defining a directory structure from the client's perspective, the internal implementation is still irrelevant, but perhaps the outward appearance should indeed have some bearing on the status codes. Maybe, even if you created the same URL structure without using directories internally, you should still use 403s, because it's about the client's perception of a directory structure.
In the balance, what do you think is the best approach? Should we just say "a resource is a resource, and if it doesn't exist, it's a 404?" Or should we say, "if it has slashes, it looks like a directory to the client, and therefore it's a 403 if there's no index?"
If you're in the 403 camp, do you think you should go out of your way to return 403s even if the internal implementation doesn't use directories? Suppose, for example, that you have a dynamic web app with this URL: http://example.com/users/joe, which maps to some code that generates the profile page for Joe. Assuming you don't write something that lists all users, should http://example.com/users/ return 403? (Many if not all web frameworks return 404 in this case.)
The first step to answering this is to refer to RFC 2616: HTTP/1.1. Specifically the sections talking about 403 Forbidden and 404 Not Found.
10.4.4 403 Forbidden
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.
My interpretation of this is that 404 is the more general error code that just says "there's nothing there". 403 says "there's nothing there, don't try again!".
One reason why Apache might return 403 on directories without explicit index files is that auto-indexing (i.e. listing all files in it) is disabled (a.k.a "forbidden"). In that case saying "listing all files in this directory is forbidden" makes more sense than saying "there is no directory".
Another argument why 404 is preferable: google webmaster tools.
Indeed, for a 404, Google Webmaster Tool displays the referer (allowing you to clean up the bad link to the directory), whereas for a 403, it doesn't display it.