Should a HTTP 404 precede a HTTP 403 status code? - java

I have created a web service (RESTful) with Spring MVC 3.1 and I have added Spring security. One of the endpoints is /users/{id} which should only be available to administrators. However /users/{id} is also available to a user if and only if the username of the retrieved resource matches that of the logged in user. This is solved by using a #PostAuthorize annotation.
Now, if a user access /users/999 (which is not the logged in user), should I return HTTP status 404 or HTTP status 403? Currently I am doing a 404 (not found), but should it have been a 403 since the user shouldn't be able to access it?
If so, how would you do that when you rely on a #PostAutorize annotation?
#PostAuthorize("returnObject.username == principal.username and hasRole('ROLE_USER')")

I would use 404, because whether the resource exists or not is not information a non-administrative user should have. This is even covered in the HTTP specification with regard to code 403:
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.
(My emphasis.)
If you used 403 instead, you'd have to use 403 when replying to non-admin requests for resources that didn't exist, otherwise your implementation would be leaking information (which users exist and don't) to non-admin users who shouldn't have that information.
There's an argument for using 403 (even if the user doesn't exist), but I think 404 edges it out. However, whichever you use, use it consistently when replying to requests from non-admin users for user pages other than their own, to avoid the information leak.

You should use 403 as the resource is available but user is not allowed. HTTP 403 specification clearly mentions that:
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.
A web server may return a 403 Forbidden HTTP status code in response
to a request from a client for a web page or resource to indicate that
the server refuses to allow the requested action. In other words, the
server can be reached, but the server declined to allow the requested
access.

Related

Http 503 for some Rest api call

I am running an SpringBoot application and I have a controller which defines Rest Api and accepts a request by a list of ids. Normally it works fine but if number of ids gets bigger, then I receive http 503. Interesting thing is that I cannot see any logs that my request was received by controller as well. Therefore I am not able to understand what is happening. Do you have any idea what can be worth to check ?
503 is a error code, which means service or url or controller, that you are requested is not running/available, make sure your jar file is running and also make sure the url you requested is valid. since service is not available you cant see any logs or error messages. because your controller dint receive any request yet.
The 503 error indicate that the server is not ready to handle the request.
There are some limitations for transferring data through URL , basically the length of the URL
In general the limit was 2047 chars and it is different for different browsers
503 means Service Unavailable.
I think something is wrong with your request.
You can try to add a custom OncePerRequestFilter and log your HTTP Request.

What is appropriate response a 404 or a 401 for this REST endpoint

I have an endpoint to get a User for example. If the user is not found it would be a 404.
If I ask for some data for that user and that doesn't exist it is a 204.
If I ask for some data for a user, but the user doesn't exist. In this case is it a 404 or a 401?
It seems to me that it is a 404. But consider the following scenario...
There is a REST client who is making the request to the REST server. The REST server (which uses spring security) tries to load the user first but fails to load because the user doesn't exist in the system. Because the spring security sees UserNameNotFound exception it throws a 401. This seems correct too.
Use 404 when the client requests a resource that do not exist:
6.5.4. 404 Not Found
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. A 404 status code does
not indicate whether this lack of representation is temporary or
permanent; the 410 (Gone) status code is preferred over 404 if the
origin server knows, presumably through some configurable means, that
the condition is likely to be permanent. [...]
If you are using HTTP authentication, use 401 when the client requests a resource and the credentials are not valid (authentication problem):
3.1. 401 Unauthorized
The 401 (Unauthorized) status code indicates that the request has
not been applied because it lacks valid authentication credentials
for the target resource. The server generating a 401 response MUST
send a WWW-Authenticate header field containing at
least one challenge applicable to the target resource. [...]
For more details, check the RFC 7231, the current reference for semantics and content of the HTTP/1.1 protocol. Also have a look at the following decision chart from Racksburg:
The status codes are grouped into three rough categories:
Start here:
Choosing 2xx and 3xx status codes:
Choosing 4xx status codes:
Choosing 5xx status codes:
In my opinion you should never intentionally send 404. 404 would be used when we are calling an API that doesn't exist.
So if you throw 404, the client would assume they are calling the wrong API or the API is not available.
If there is no data, 204 is apt, 204 tells that you are calling correct API and server acknowledges it but there is no response to provide from server side.
Hence either there is no user or user has no data, it should be 204 as status.
2XX - success
3XX - request moved
4XX - bad request
5XX - server error

Cross Domain Error with self built API

The server sending JSON to the API is a Tomcat server in the Gradle packages (it is built in Java).
I am having trouble's making an API call with Angular. I know my API is working because I can view it on "Postman."
var app = angular.module("todo", []);
app.controller("AppCtrl", function($http){
$http.get("192.168.5.100:8080/aggregators/datafile")
.success(function(data){
console.log(data)
})
})
When I run it I get the following error:
XMLHttpRequest cannot load %3192.168.5.100:8080/aggregators/datafile. Cross origin requests are only supported for HTTP.
The problem you're running into is that you can't make cross origin requests from the browser without CORS or using JSONP.
Postman operates outside of the context of the browser (as if you had issued a cURL request, if you're familiar with cURL).
This is for security reasons.
So, how do you implement JSONP? It really depends on the server, but in general, your resource would look for a GET request that had a pre-determined querystring parameter (normally callback for simplicity):
http://192.168.5.100:8080/aggregators/datafile?callback=mycallback
How do you make a JSONP call?
The server wraps the JSON in that callback, causing it to look something like the following:
mycallback({json:object});
This Stack Overflow answer goes into more detail.
The callback is the function the browser should hit when the request is executed, and that's what allows for cross-domain requests.
Now, on to CORS.
CORS is a system for allowing the browser to communicate with the server to determine whether or not it should accept a cross domain request. It's a bit complicated, but in general it involves settings up certain Headers on your API Server; and then executing an Ajax request in a particular fashion (for JQuery, use the withCredentials property for $.ajax). The server checks where the request is from, and if it's a valid source, it let's the browser know and the browser allows the request (I'm being simplistic).
MDN has a thorough explanation of CORS that is worth reading.

HTTP Authorization header consistency in requests

HTTP specification says;
HTTP access authentication is described in "HTTP Authentication:
Basic and Digest Access Authentication" [43]. If a request is
authenticated and a realm specified, the same credentials SHOULD
be valid for all other requests within this realm (assuming that
the authentication scheme itself does not require otherwise, such
as credentials that vary according to a challenge value or using
synchronized clocks).
I don't really understand what this means, but here is my scenario is there anything against HTTP specs here? I use Java Rest service
Client sends username:password using HTTP Authorization header using HTTP Basic
Server sends back a token
Now client sends a custom authorization token instead of password for further requests still in the HTTP authorization header still using HTTP Basic username:token
Now this does not feel right since what I am really doing with the auth token is NOT an actual HTTP Basic authorization. Also usage of the very same header is inconsistent between requests.
But on the other hand I do not want create yet another custom header for the token exchange. Because its hard to base64 encode them with test tools when you use a custom header. And still inconsistent headers between requests.
Note: these requests refers to different endpoints
What do you advice?
If you do that, since you are using the same headers, aren't you going to need server side logic to differentiate when the login is the actual login, as opposed to your token? At the end of the day, HTTP Authorization is already a token (only a simple encoded version of the username/password string), so in all cases you are receiving a token, now you have to decode it, decide if it's one of your session tokens, or if it's a username/password, and therefore check against two sources of "good tokens".
I would advice against this, but not because you're breaking standards, it just feels convoluted.
Why do you need to change username/password to a token on the first place? Are you redirecting to an endpoint where you no longer require HTTP Basic Auth?

How to test Webservice in JDeveloper that uses Basic Authentication?

I have created a web-service that uses basic authentication in JDeveloper 11.1.1.4.
When i test my application using a client application is runs correctly so i know that the authentication mechanism has no problems.
How can i pass authentication info into the HTTP Analyzer by right clicking on Webservices and selecting Test Web Service?
I have tried to pass credentials through SOAP Headers > :WS-Security:Header like below but is not working
I have also tried to pass authentication through Credentials option like shown below
In both cases i get this error 500 HTTP Analyzer Server Error The server sent HTTP status code 401: Unauthorized: .....
How can i get through this?
Thanks
UPDATE
I also tried to pass Authentication option to Request HTTP Headers but get the error message :
Error 403--Forbidden
From RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1:
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. 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.
If you're using Basic authentication, all you need is set request header Authorization. Value of this header: prefix Basic, one space, Base64 encoded string with usrname:password, so your header for Aladin:sesam open should be like this: Basic QWxhZGluOnNlc2FtIG9wZW4=.
On screenshot i see section Request HTTP headers, add Authorization header to it.
I am aware that this is an old post , but this may benefit those who run into this issue.
I am using Jdeveloper 11.1.2. I have secured the JAX-RPC web service (created by exposing PL/SQL poackage) using basic authentication. I attached the security policy: "Auth.xml" using the wizard.
I was able to test this using HTTP Analyzer. I just passed the user credentials in the SOAP Headers as shown below and it worked fine for me.(I also passed invalid creds and no creds to see if the security works as expected.)
Hope this helps !!!

Categories

Resources