You are right in your analysis. Authentication Protocols :
- Anonymous access
- Call Answer Authentication
- Negotiations (Kerberos)
- NTLM
- Digest
- Basic Authentication
In IIS (and most HTTP servers), the authentication process defaults to the order above. i.e. If anonymous access succeeds (details will not be provided here), other authentication providers are ignored, even if they are enabled.
HTTP 401 Challenge
If you want to manage multiple authentication methods and providers, you need to use a mechanism that refuses credentials if you consider them invalid. You can achieve this by sending 401 responses. This is called the HTTP 401 Challenge .
The idea is to inform the client (browser) that the credentials used for the requested resource are rejected.
Depending on the scenario and configuration of the client, the client may handle authentication. And in this case, the authentication process can be different: Challenge-Response providers require a certain number of exchanges to confirm credentials.
In any case, with your anonymous access, the first response 401 will be interpreted by the browser as "authentication is required for this request." The server automatically includes supported authentication providers in the response header if they are included on the server side.
HTTP/1.1 401 Unauthorized Server: Microsoft-IIS/7.5 WWW-Authenticate: Negotiate WWW-Authenticate: NTLM WWW-Authenticate: Digest qop="auth",algorithm=MD5-sess,nonce="+Upgraded+v1b3a89710edce01754fd608...",charset=utf-8,realm="Digest" WWW-Authenticate: Basic realm="host" X-Powered-By: ASP.NET Content-Length: 0 Proxy-Support: Session-Based-Authentication
If your browser is configured correctly to send credentials for the zone of your web application (you said that), it will automatically use the first authentication provider that it knows (e.g. NTLM ) and reprocess the request with credentials that it knows ( Windows credentials in your case).
GET http://host/yourpage.aspx HTTP/1.1 Accept-Encoding: gzip, deflate Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFASgKAAAADw== Connection: Keep-Alive
When the authentication process fails, the server will automatically send a 403 Forbidden response to the client to avoid too much traffic. Answer 403 stops the call. The good news is that this requires some task: more than 4. And, as a rule, HTTP authentication requires about 3 maximum answer to a call to succeed (3 for NTLM and 2 for Negotiate -Kerberos- ).
Because you allow anonymous access, the server will not block client requests, and your pages will be called with anonymous credentials. You can interact with your client on your page by setting the HTTP Response Code . As already mentioned, it only works if you have included another authentication provider in addition to Anonymous .
So, the trick is to process it using a counter on your server side and say "if my authentication session / cookie counter is greater than 3, my client cannot authenticate to the server. Let's say it's anonymous."
Some code
I did not do exactly what you need, but you can adapt my code:
int i = 3; int j = 0; HttpContext httpContext = HttpContext.Current; // Record authentication process HttpCookie httpCookie2 = httpContext.Request.Cookies["loginAttemptCount"]; if (httpCookie2 == null || httpCookie2.Value == String.Empty) { httpCookie2 = new HttpCookie("loginAttemptCount"); } else { j = Int32.Parse(httpCookie2.Value, System.Globalization.CultureInfo.InvariantCulture); } j = (j + 1) % i; string user = Request.ServerVariables["LOGON_USER"]; // Send 401 responses to authenticate the user if (j != 0 && user == String.Empty) { httpCookie2.Value = j.ToString(System.Globalization.CultureInfo.InvariantCulture); httpContext.Response.Cookies.Add(httpCookie2); Response.StatusCode = 401; return; } httpCookie2.Value = String.Empty; httpContext.Response.Cookies.Add(httpCookie2);
If necessary, you can check the authorization provider in the Authorization header.
Request.Headers["Authorization"]
You can use Fiddler to trace your HTTP headers.
Hope this is clear enough.