HTTP response and headers for AJAX/oData authentication? - ajax

How oData or AJAX services should respond when the authentication cookie is expired and it's time to renew?
What should the server send to the client when
An oData or AJAX service access is forbidden (access denied)
When the session credentials are stale, and need to be renewed, perhaps by redirecting to an ADFS, OpenID, or Azure ACS IDP
Just looking in Wikipedia lets me guess that I should send some version of 403.x for the first scenario, and a 401 for the second scenario.
Please confirm if the above is correct, and what I should include in the response header and body as well.
Some examples I assume to be incorrect do the following:
Silently error out the AJAX service and return no data
Attempt to redirect the AJAX call to the IDP
Send error text to the client that is not in JSON format

its always safe to play with the HTTP Status codes instead of cooking up your own tokens or anything of that sort.
Since the fundamentals of OData is to make it possible for any client which knows how to communicate HTTP, it makes sense to play around the HTTP status code. The clients will decide what to do on a particular status code.

HTTP Status Codes are the way to go. OData specifically doesn't define anything that is already implemented at a lower level (such as security and authentication.)
401 is for Unauthenticated, 403 is for Unauthorized. For secnario 1 you only say "Access denied" but not why you're denying access. Is the user not authenticated? Then return 401. Is the user authenticated but lacking privileges? Then return 403.
For scenario 2, I would agree, return a detailed 401 status (i.e. with a valid "WWW-Authenticate" header for your authentication provider.)
The Wikipedia article I recommend starting at (you may have already found this) is: https://secure.wikimedia.org/wikipedia/en/wiki/List_of_HTTP_status_codes
Hope this helps someone. :-)

Related

JMeter view results tree requests showing error

Why is this second request happening (Request2-1) here and how to solve it.
Your request is redirected and there is not permission to access the resource.
The HTTP 403 Forbidden client error status response code indicates that the server understands the request but refuses to authorize it.
Please check the request details in the view result tree by clicking Request->Request Body and Request->Request Headers
You need to ensure that the request is permitted.
Most probably the resources, you're trying to access require authentication and you're not supplying valid authentication context.
If you do HTTP Status Code 403 means that the user is not allowed to access the endpoint.
See How to use JMeter for Login Authentication article for more information on example bypassing login challenge in JMeter tests.
If "Follow Redirects" is selected in HTTP Request, it will follow the redirects and groups each redirect under the original request as in the image you posted.
Some APIs can redirect, this is normal. Response failure is caused by the request content sent. Check the parameters and body values you sent.

How to secure web api with Identity Server 3

I'm building an MVC web app that uses the openID Connect hybrid flow to authenticate with Identity Server 3. The MVC web app contains jQuery scripts to get async JSON data from een ApiController. That ApiController is part of the same MVC web app.
I don't want that everyone is able to access the data from the API, so I want to secure the API as well. I added an [authorize] attribute to the ApiController. When requesting the API with a JQuery ajax request I get the following error message:
XMLHttpRequest cannot load
https://localhost:44371/identity/connect/authorize?....etc.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:13079' is therefore not allowed
access. The response had HTTP status code 405.
But, when I do a request to the API method directly in browser, I will be correct redirected to the Login page of Identity Server..
So, what's exactly the problem here? I read something about that requesting the /authorize endpoint is not allowed via 'back-channel', but I don't understand what's the difference between 'front-channel' and 'back-channel'. Is it possible that I mixed up the wrong OAuth flows? Is the Hybrid flow not the correct one maybe?
I also find out that the API is often a seperate app, but is it always neccessary / best-practice to build a seperate API app that for example requires a bearer token?
Please point me in the right direction about this.
The authorize method on your identity server does not allow ajax calls. Even specifying CORS headers is not going to help you in this particular case. Perhaps you could return a forbidden response instead of a redirect and manually redirect the client to the desired location via window.location
You need to allow your IdentityServer to be accessed from other domains, this is done by allowing "Cross Origin Resource Sharing" or CORS for short. In IdentityServer the simplest way to allow this is in your Client configuration for your Javascript Client, see this from the IdentityServer docs on CORS:
One approach to configuing CORS is to use the AllowedCorsOrigins collection on the client configuration. Simply add the origin of the client to the collection and the default configuration in IdentityServer will consult these values to allow cross-origin calls from the origins.
The error you're seeing is the browser telling you that when it asked IdentityServer if it allows requests from your Javscript client, it returned a response basically saying no, because the origin (http://localhost:13079) was not specified in the "Access-Control-Allow-Origin" response header. In fact that header wasn't in the response at all meaning CORS is not enabled.
If you follow the quickstart for adding a JavaScript client from the docs here all the necessary code is detailed there that you need for the Client config and to setup IdentityServer to allow CORS.

What's the appropriate HTTP status code to return if a user tries logging in with an incorrect username / password, but correct format?

A similar question is posted here: What's an appropriate HTTP status code to return by a REST API service for a validation failure?
The answer in the thread above states that "For instance if the URI is supposed to have an ISO-8601 date and you find that it's in the wrong format or refers to February 31st, then you would return an HTTP 400. Ditto if you expect well-formed XML in an entity body and it fails to parse."
However, what happens if the user submitted correctly formatted data? By this I mean, the user submitted a plain alphabetical string / text for the username and password (which is perfectly valid for my application). The only issue is that the password did not match with the username. In this case, 400 will be incorrect because it is perfectly valid syntax and well-formed.
A 401 would be incorrect (as suggested here: Which HTTP status code to say username or password were incorrect?) because the user is not trying to access any page, he is simply trying to login and entered data which does not match.
If you look back at the first post I linked to, the second answer states that 422 is the correct response (and it looks correct to me), however, I am using Django Rest Framework and 422 is not part of the status codes (a list of the status codes which are part of DRF can be found here: http://www.django-rest-framework.org/api-guide/status-codes/#client-error-4xx)
404 also doesn't look right because the data is successfully accepted and not refused.
With that said, what is the real correct response which should be used?
If you are strictly using the HTTP authentication framework provided by RFC 7235 for your REST API, the correct HTTP code would actually be 401. From the RFC:
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 (Section 4.1) containing at least one challenge applicable to the target resource.
If the request included authentication credentials, then the 401 response indicates that authorization has been refused for those credentials. The user agent MAY repeat the request with a new or replaced Authorization header field (Section 4.2).
Your REST API should employ an authentication scheme of some sort in order to return a valid 401 response to your client.
Another pertinent section from RFC 7235, page 4:
Upon receipt of a request for a protected resource that omits
credentials, contains invalid credentials (e.g., a bad password) or
partial credentials (e.g., when the authentication scheme requires
more than one round trip), an origin server SHOULD send a 401
(Unauthorized) response that contains a WWW-Authenticate header field
with at least one (possibly new) challenge applicable to the
requested resource.
A higher-level response, such as a rendered login page for a visual user (redirected from a protected resource via 302), would be better served with the 200 status code (per #KernelDeimos' answer, for example). Since login pages are typically their own resource (e.g. /login?redirect=original-resource), the unauthenticated user is still authorized to see this page, even if they provide an incorrect username/password. Then, you redirect the authenticated user back to the resource, at which point would show 200 if allowed, or 403 if the user is forbidden to view the resource.
The area where 401 could come into play with a visual login page is a front-end library that leverages the REST API using XHR requests, then relay the 401 response from the REST API back into a meaningful format on the login page.
If login is handled at a higher-level (ex: sending a POST to the server with a username and password), use the appropriate status code in 2xx for a successfully handled login request with the wrong password. If using the HTTP authentication framework provided by RFC 7235, send 401 (see answer by #sjagr for further detail).
Below the line is the rest of my original answer, which explains my train of thought. Also note the thread on sjagr's answer which includes a debate which improved both our answers and a comment from Julian Reschke (one of the RFC's authors).
Before asking "what is the correct HTTP status code", it's important to consider this question: "Should success or failure of login be reflected in the HTTP status code of the response?"
In #sjagr's answer the first part of this section is highlighted. I'm going to highlight the second part and explain why:
If the request included authentication credentials, then the 401 response indicates that authorization has been refused for those credentials. The user agent MAY repeat the request with a new or replaced Authorization header field (Section 4.2).
This refers to an Authorization header, rather than a request body containing login credentials. The phrasing of the first part, unfortunately, could be misinterpreted to refer to a request body containing login information. This ambiguity can be resolved by considering separation of concerns; (https://en.wikipedia.org/wiki/Separation_of_concerns) the server's response header should not depend on the differences of two valid request bodies, with the exception of when it causes an internal server error, otherwise the concerns of data transfer and appliction login begin to creep into each other.
I would use HTTP response 2xx for a valid login request, where the client has permission to attempt a login, that is handled successfully with a response indicating success or failure.
I also like the way #spectras expressed this in the comments:
Attempting to express an application-level error in a transport-level status code is a design mistake.
401 - Unauthorized
403 - Forbidden
http://www.buggybread.com/2012/11/http-error-codes-401-access-denied-403.html
If you try to log into a Google account with the wrong password, it will return a 200 response containing data that indicates the password was incorrect. For that reason, I just use a 200.
At the end of the day, which status code you use is purely a semantic issue and isn't going to change the functionality of your application. What really matters is that your application displays the correct information to the user.
I think what causes all the confusion is that there are two entities that need to be authenticated. One is the client (front-end app) needs to authenticate itself, that its authorized to make a login request for the user, and then the user needs to authenticate itself with his username/password.
The status code should only be related to the client making the request, not the user.
From https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
HTTP response status codes indicate whether a specific HTTP request has been successfully completed.
200 is correct:
Given that you have a front-end application that talks to the backend, the appropriate respond code should be 200 and the response body should contain the information if password matches or not, but that result has no impact on the status code, because the request itself was authorized and successfully parsed.
401 is wrong:
Assume your front-end authenticates with a token for example, then the response code 401 would mean the front-end token is invalid, not the password of the user inside that request.
403 is wrong: Assume your front-end authenticates with a token for example, then the response code 403 would mean the token is vaild, but that token does not have the access right to ask if password/username match.

Permissive CORS policy: Possible to retrieve and parse a response for cross-domain, authenticated request?

I signed up to ask this question after reading dozens of great posts on this site. Here is my unanswered question which is admittedly application security focused:
For a site which returns the following headers upon invoking a REST service:
Content-Type: application/json
Access-Control-Allow-Origin: *
Recognizing such a permissive CORS policy is bad practice for services which return sensitive data, I nevertheless must prove whether or not it is possible for a threat actor to invoke the authenticated REST service (cookie auth) on the behalf of an authenticated victim such that the threat actor has visibility into the response.
I understand this flag instructs the browser to send relevant cookies along with the cross-domain request:
withCredentials: true
I have observed that browsers refuse to allow a threat actor to interpret the returned response, meaning the JSON objects are returned to the browser (as evidenced by a proxy or packet capture) but can never reach the DOM as accessible by the threat actor him or herself.
For example, Chrome produces the message, "Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true" when I invoke the aforementioned REST service via jQuery. If I attempt JSONP I receive the message, "Uncaught SyntaxError: Unexpected token : " because I do not have access to modify the REST service logic to return the proper callback string.
Is it truly impossible for the threat actor to successfully leverage the overly-permissive CORS policy to invoke the REST service and retrieve/parse/return its response on the behalf of the victim's authenticated session?
I fear that:
I am unaware of a trick or two
Some browsers might not actively prevent such an "attack"
Any insight is greatly appreciated as I am not a developer -- thank you!
You cannot use wildcarding when accepting a credentialed request.
when responding to a credentialed request, server must specify a domain, and cannot use wild carding1
Also it looks like you need to set the following header to be sent as a response from the REST service Access-Control-Allow-Credentials: true
If you are using Apache, you can add in a .htaccess :
SetEnvIf Origin "^http(s)?://(.*)$" origin_is=$0
Header set Access-Control-Allow-Origin %{origin_is}e env=origin_is
This directive add a Acess-control-allow-origin valued with the domain name in then request. It copies, in the response header, the value of the Origin request.

Http status code for bad params in post request

I have a server in which the client can register itself as a device (like a mobile device). For the registration, the device must be associated with another resource (say an user) which is already registered on the server. To do that, the client sends a Http Post request to the server, with two params, its own ID and the associated resource ID.
I need to choose an Http Status code to return when the client ask the server to do some procedure and one of the resources indicated in the parameters are not found.
I suggested 404, but my professor said that 404 is used the resource associated to the URI is not found, not when you submit a well-formed request with bad parameters.
What is the most suitable http status and why would you choose?
In my opinion, it fits to:
400 - Bad Request
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.
OR
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.
Ref: fc2616
I would use 403 'Forbidden' - meaning, you are forbidden from accessing the page with the request you have sent

Resources