In a recent sharepoint project, I implemented an authentication webpart which should replace the NTLM authentication dialog box. It works fine as long as the user provides valid credentials. Whenever the user provides invalid credentials, the NTLM dialog box pops up in Internet Explorer.
My Javascript code which does the authentication via XmlHttpRequest looks like this:
function Login() {
var request = GetRequest(); // retrieves XmlHttpRequest
request.onreadystatechange = function() {
if (this.status == 401) { // unauthorized request -> invalid credentials
// do something to suppress NTLM dialog box...
// already tried location.reload(); and window.location = <url to authentication form>;
}
}
request.open("GET", "http://myServer", false, "domain\\username", "password");
request.send(null);
}
I don't want the NTLM dialog box to be displayed when the user provides invalid credentials. Instead the postback by the login button in the authentication form should be executed. In other words, the browser should not find out about my unauthorized request.
Is there any way to do this via Javascript?
Mark's comment is correct; The NTLM auth prompt is triggered by a 401 response code and the presence of NTLM as the first mechanism offered in the WWW-Authenticate header (Ref: The NTLM Authentication Protocol).
I'm not sure if I understand the question description correctly, but I think you are trying to wrap the NTLM authentication for SharePoint, which means you don't have control over the server-side authentication protocol, correct? If you're not able to manipulate the server side to avoid sending a 401 response on failed credentials, then you will not be able to avoid this problem, because it's part of the (client-side) spec:
The XMLHttpRequest Object
If the UA supports HTTP Authentication [RFC2617] it SHOULD consider requests
originating from this object to be part of the protection space that includes the
accessed URIs and send Authorization headers and handle 401 Unauthorised requests
appropriately. if authentication fails, UAs should prompt the users for credentials.
So the spec actually calls for the browser to prompt the user accordingly if any 401 response is received in an XMLHttpRequest, just as if the user had accessed the URL directly. As far as I can tell the only way to really avoid this would be for you to have control over the server side and cause 401 Unauthorized responses to be avoided, as Mark mentioned.
One last thought is that you may be able to get around this using a proxy, such a separate server side script on another webserver. That script then takes a user and pass parameter and checks the authentication, so that the user's browser isn't what's making the original HTTP request and therefore isn't receiving the 401 response that's causing the prompt. If you do it this way you can find out from your "proxy" script if it failed, and if so then prompt the user again until it succeeds. On a successful authentication event, you can simply fetch the HTTP request as you are now, since everything works if the credentials are correctly specified.
IIRC, the browser pops the auth dialog when the following comes back in the request stream:
Http status of 401
WWW-Authenticate header
I would guess that you'd need to suppress one or both of those. The easy way to do that is to have a login method that'll take a Base64 username and password (you are using HTTPS, right?) and return 200 with a valid/invalid status. Once the password has been validated, you can use it with XHR.
I was able to get this working for all browsers except firefox. See my blog post below from a few years ago. My post is aimed at IE only but with some small code changes it should work in Chrome and safari.
http://steve.thelineberrys.com/ntlm-login-with-anonymous-fallback-2/
EDIT:
The gist of my post is wrapping your JS xml call in a try catch statement. In IE, Chrome, and Safari, this will suppress the NTLM dialog box. It does not seem to work as expected in firefox.
Related
I'm using Apache Shiro for my Rest service project and I have troubles getting it to work as intended.
For rest service,I use basic authentication and as first,when I send wrong username,It returns 401 as expected.
Then I send correct user name and password,It returns 200 as expected.
As 3th step,When I send again wrong username,It returns 200,should return 401.
I think after first successful login,It doesnt need any authentication process again.How can I force it to authenticate for every request?
I couldnt find any reason or any parameter I should add in my shiro.ini.
This is my shiro.ini:
What you are seeing may be the result of your client. Before a client will send credentials to a server typically has to ask for them (responding with a 401), the client will the add the auth header. A client can work around this using "preemptive" auth, which will send the Authorization header on the initial request.
Your server is likely also configured to use cookies, which the server will process first and then return a 200 (and the client would never send the new credentials).
If this is just a REST server/client setup, you could disable session creation, using the noSessionCreation filter.
https://shiro.apache.org/web.html#default_filters
If you are still stuck take a look at your HTTP logs and watch for the headers (specifically Authorization and an Cookie headers).
Sorry for my English)
I have an account on https://naurok.com.ua (login: kuz.code.official#gmail.com, password: 2455s1). I log in, then follow the link /test/test-po-filosofii-541029/flashcard.
After I followed the link, it loads the cards through a request /api/test/documents/541029/flashcard.
I need to send it successfully:
I test request by Postman api/test/documents/541029/flashcard. Request sends with captured Cookies, but it says I need to log in ("Необходимо авторизоваться").
Why query work on website but doesn`t in Postman?
you need add the most important thing which is to add the cookie PHPSESSID you can find it on your browser when inspecting the request on network tab
like this
click on "cookies" on postman
to have it like this
or click on "code" on postman
I noticed also you need referer header otherwise it won't work
When I ask user for HTTP Basic Auth at some URL, browser sends Authorization header only for this and some other URLs.
Testcase script written in PHP:
http://testauth.veadev.tk/
There are three URLs to ask for credentials (you can use any random).
Logout link (drops current credential after pressing "Cancel" button in browser auth form, not working in IE).
Links to root URL and some test deeper URLs.
Questions:
Why browser not sending Authorization header at / URL if HTTP/1.0 401 Unauthorized was sent at /system/dev?
To repeat: open clean http://testauth.veadev.tk/, click Auth2, enter any credentials, you'll be forwarded to / after that. You'll see Auth: null which means no credentials header was sent by browser.
Why does browser send Authorization header at / if HTTP/1.0 401 Unauthorized was sent at /dev?
To repeat: open clean http://testauth.veadev.tk/, click Auth1, enter any credentials, you'll be forwarded to / after that. You'll see something like Auth: string 'Basic dHQ6dHQ=' (length=14) which means credentials header was sent by browser.
If you repeat first case and then click Auth1 you'll have credentials at Root and all other pages. Why?
If you click Auth3 (/some/deep/and/long/url) and you'll have credentials at Page3 (/some/deep/and/long/3) and nowhere else. Why?
To clear credential state between tests either restart your browser or click Logout, Cancel in Auth form and Root to return back (Firefox, Google Chrome).
What are the rules of sending Authorization header?
RFC 2617, section 2 states:
A client SHOULD assume that all paths at or deeper than the depth of
the last symbolic element in the path field of the Request-URI also
are within the protection space specified by the Basic realm value of
the current challenge. A client MAY preemptively send the
corresponding Authorization header with requests for resources in that
space without receipt of another challenge from the server.
If you are using Digest Challenge, section 3.2 states that you may specify a domain in the WWW-Authenticate header to indicate what the protection space will be. I would try setting that to something like domain=/. I am not sure if this will work with Basic authorization, but it wouldn't hurt to try it; if not, Digest authorization is not much more difficult to work with and is a bit more secure.
I am using Windows Authentication to secure ASP.NET MVC5 application.
Everything works ok, I'm prompted to enter credentials via browser popup, and content it served properly.
However I do notice constantly that some requests are being sent 2 times, or more, with receiving 401 (Unauthorized) code, but shortly after requests are issued again and 200 (OK) is returned.
I assume that is part of negotiation with WWW-Authenticate and Authorize requests headers, but what is unclear to me is why this has to happen all the time even though credentials were supplied at the very start?
Is this normal behavior?
If not, how can it be fixed?
If yes, is it a big performance hit?
Attached is the combined screenshot of Fiddler and Firefox developer console.
What you are experiencing is the normal behavior. Here is a (very) short description of how the authentication works:
Request is sent to server (without credentials) => not authenticated (your first request)
Server responds with 401 (Access denied)
Browser gets error and sends credentials back => authenticated (your second request)
After the 3rd step, if the server has not received the requested credentials, it sends another 401 response and the browser displays the 401 error page. A more complete description can be found here.
This is a conceptual question.
I have a client (mobile) application which needs to support a login action against a RESTful web service. Because the web service is RESTful, this amounts to the client accepting a username/password from the user, verifying that username/password with the service, and then just remembering to send that username/password with all subsequent requests.
All other responses in this web service are provided in a JSON format.
The question is, when I query the web service simply to find out whether a given username/password are valid, should the web service always respond with JSON data telling me its successful or unsuccessful, or should it return HTTP 200 on good credentials and HTTP 401 on bad credentials.
The reason I ask is that some other RESTful services use 401 for bad credentials even when you're just asking if the credentials are valid. However, my understanding of 401 responses are that they represent a resource that you are not supposed to have access to without valid credentials. But the login resource SHOULD be accessible to anyone because the entire purpose of the login resource is to tell you if your credentials are valid.
Put another way, it seems to me that a request like:
myservice.com/this/is/a/user/action
should return 401 if bad credentials are provided. But a request like:
myservice.com/are/these/credentials/valid
should never return 401 because that particular URL (request) is authorized with or without valid credentials.
I'd like to hear some justified opinions one way or the other on this. What is the standard way of handling this, and is the standard way of handling this logically appropriate?
First off. 401 is the proper response code to send when a failed login has happened.
401 Unauthorized
Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the requested resource.
Your confusion about, myservice.com/are/these/credentials/valid sending back 401 when you just do a check, I think is based on the fact that doing boolean requests in REST often is wrong by the RESTful constraints. Every request should return a resource. Doing boolean questions in a RESTful service is a slippery sloop down to RPC.
Now I don't know how the services that you looked on are behaving. But a good way of solving this is to have something like an Account object, that you try to GET. If your credentials are correct, you will get the Account object, if you don't want to waste bandwidth just to do a "check" you can do a HEAD on the same resource.
An Account Object is also a nice place to store all those pesky boolean values that otherwise would be tricky to create individual resources for.
401 should be sent only when the request needs authorization header field and authorization fails. Since the Login API doesn't require authorization, hence 401 is the wrong error code in my opinion
As per the standard here https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
*10.4.2 401 Unauthorized
The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication" [43].*
If the 401 response code is misleading for user authentication, the API can send HTTP status code 200 OK for both successful and failed authentication, but set a custom header on the authentication successful response and omit that header on failed logins.
The client can check if the header exists or not and decide the action.
Example: SpringBoot API Response
The call to OK when login is successful sets the header "gotyouin" with a value (anything). Call to failed does not add the header and client can treat this as a failed login attempt.
public class LoginResponseEntityHelper {
public static ResponseEntity<?> ok(String token) {
return ResponseEntity.status(HttpStatus.OK).header("gotyouin", token).body(null);
}
public static ResponseEntity<?> failed() {
return ResponseEntity.status(HttpStatus.OK).body(null);
}}
It is logical to use 401 http status code when access to a resource is denied because the request lacks or has incorrect credentials. And when correct credentials are provided, the request should complete successfully granting access to the protected resource.
Applicable for your case: myservice.com/this/is/a/user/action.
Maybe we should be clear about this credentials
In most secure applications, credentials are needed to access protected resource(s). These credentials can be sent along every request via HTTP header. Specifically the Authorization Header.
Therefore the Authorization header contains credentials to allow a user to access protected resource(s).
Remember that a user who was verified successfully as an authorized user(successful login), is the one given this priviledged credentials to allow for access on protected resources on the server.
From the server point of view, a HTTP request targeting a protected resource yet it is lacking credentials or containing invalid credentials may cause to validly send back 401 response code.
Therefore the Login API should not send a 401 response code because of a failed login attempt. It is misleading. Reasoning out that you are requesting to the server application via the Login API to grant you with credentials required to access resources that are protected. By itself, the Login API is not a protected resource.
So what is the correct response status?
Well I will opine towards sending back a 400 response code because a failed login attempt is a client error who is at fault for not providing the correct username or password.
According to RFC standards about 400 code:
The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing)
Again I will reiterate that failed login is a client error due to providing details that are incorrect. Sending back a 400 doesn't have to mean that the request syntax is malformed. But a malformed syntax is one of the reasons.
Sending a 401 would really be misleading as the user doesn't need to provide authentication information to access the login API.