HTTP Authentication and Authorization Failure always sending 401 Challenge
HTTP Authentication Failures are always always returning a challenge.
The Challenge and Response RFC does not require that a Server sends a Challenge for Failed Authentication but if it does require that when a server sends a 401 then it must send 1 or more WWW-Authenticate headers with a comma separated list of parameters describing the Authentication Scheme.
I need thee the following from NegotiateSecurityFilter abilities
- to not challenge on Failed Authentication; especially Basic
- hide resources when there is not Authorization Header
- hide resources when there is an Authentication failure
- specify the order of NTLM and Negotiate for WWW-Authenticate challenges, e.g. Workgroups, Domains and no local credential manager
- these are the following orders that required for various deployments,
- Basic,, NTLM, Negotiate
- NTLM, Negotiate, Basic
- Basic, Negotiate, NTLM
- Negotiate, NTLM, Basic
See this MDN article for HTTP Basic Authentication Challenge and Basic Authentication Failure
RFC7617 obsoletes RFC2617 which is the current implementation of BasicSecurityFilterProvider
IE and Chrome preemptive Authorization Headers Domain / Enterprise Deployments of Negotiate Security Filter
Withe reference RFC7235#section-3.1 and RFC7231#section-6.5.3 a server is not required to return a challenge and the server can choose to hide the existence of a resource by sending a 404 instead of a 403, (IIS and .NET supports this configuration option) and considering that AD configuration for IE and Chrome for Business provide the ability to use Negotiate or NTLM preemptive means that NegotiateSecurityFilter could be configured to hide the existence of a resource.
extract from RFC7617 Upon receipt of a request for a URI within the protection space that lacks credentials, the server can reply with a challenge using the 401 (Unauthorized) status code ([RFC7235], Section 3.1) and the WWW-Authenticate header field ([RFC7235], Section 4.1).
For instance:
HTTP/1.1 401 Unauthorized
Date: Mon, 04 Feb 2014 16:50:53 GMT
WWW-Authenticate: Basic realm="WallyWorld"
I would like to modify NegotiateSecurityFilter or create a new Filter that Extends NegotiateSecurityFilter to Implement the following
- new init parameter permissiveAuthorization
- true which will be the default leaving NegotiateSecurityFilter to continue to work as is current and will set WWW-Authenticate for requests with Authorization Header
- false no Challenges are sent to Requests with no Authorization Header
- new init parameter hideResources - mutually exclusive of permissiveAuthorization - for failed authentication if hideResources = true, return 404 else return 403
- new init parameter challengeFailedAuthentication
Notes on permissiveAuthorization and hideResources:
during Initialization of NegotiateSecurityFilter if permissiveAuthorization is false and hideResources = fase = throw ConflictingParameterRuntimeException message = 404 response will be returned for Forbidden access because permissiveAuthorization has been disabled permissiveAuthorization = false
Notes on behaviour of NegotiateSecurityFilter with the new parameters and only a BasicSecurityFilterProvider configured
no Authorization header and permissiveAuthorization = false then return 404 no Authorization header and permissiveAuthorization = true then return 403 no Authorization header and permissiveAuthorization = true and hideResources = true then return 403
no Authorization header and permissiveAuthorization = false and hideResources = false then return 404
Notes about allowGuestLogon false hideResources and successful authentication
- a successful password authentication where allowGuestLogin is false, if hideResources then return a 404 otherwise return 403
https://tools.ietf.org/html/rfc7231#section-6.5.3
A server that receives valid credentials that are not adequate to gain access ought to respond with the 403 (Forbidden) status code (Section 6.5.3 of [RFC7231]).
The Client MAY submit credentials when receiving a WWW-Authenticate and the Client MAY preemptivley submit an Authorization on first request to a resource If failed Authentication then return with 403 or 404 [RFC7231 7231#section-6.5.3)(https://tools.ietf.org/html/rfc7231#section-6.5.3)
6.5.3. 403 Forbidden
The 403 (Forbidden) status code indicates that the server understood
the request but refuses to authorize it. A server that wishes to
make public why the request has been forbidden can describe that
reason in the response payload (if any).
If authentication credentials were provided in the request, the
server considers them insufficient to grant access. The client
SHOULD NOT automatically repeat the request with the same
credentials. The client MAY repeat the request with new or different
credentials. However, a request might be forbidden for reasons
unrelated to the credentials.
An origin server that wishes to "hide" the current existence of a
forbidden target resource MAY instead respond with a status code of
404 (Not Found).
I think it's the same debate as disableSSO in #636. Personally I am not opposed to an enabled flag in every filter that avoids having to comment the filter out.
Naming wise, I would change disableSSO to enabled and default that to true and implement the same in this filter (and every other) in some base class that prevents calling doFilter altogether.
@dblock thank you very much for the feedback.
I require the basic security filter provider to be enabled and handle a request.
I only don't want the challenge if authorization fails.
This first request to my servlet includes an Authorization: Basic bae64creds and if this fails i dont want the challenge sent because the browser because chrome handles the challenge which causes the pop up box. the speech says.
I'll update my working example, thats in test, to send the challenge if there was no authorization header.
I change my current deployment in Test to use sendChallengeOnFailedAuthorization this will have a default of true and leave the basic security filter provider sending the challenge if there is not Authorization header.
The spec says that the vendor MAY send a challenge if authorization fails, the parameter is to make sure that current deployments work as expected.
That the first request can include the authorization header and the vendor's implementation.
Another approach to address my issue of the browser pop might be to have a Custom Authorzation Scheme and a new Provider waffle.servlet.spi.BasicSecurityFilterProvider/protocols, but adding the parameter and conditionally sending the challenge doesn't go off spec.
NTLM
Negotiate
Basic
xhrBasic
For enabled I opened https://github.com/Waffle/waffle/issues/639 so we don't lose it. Maybe someone wants to contribute!
I send the Authorization Header; I do not want to disable any filters
Please see this diagram RFC7617 at MDN where rfc7617 obsoletes 2617 which is the current implementation of BasicSecurityFilterProvider
- 401 is a Challenge that the server can reply with a challenge if the resource is protected
- In the diagram the Authentication failure is returned a 403 - Forbidden
- The Client MAY submit credentials when receiving a WWW-Authenticate
extract from RFC7617
Upon receipt of a request for a URI within the protection space that lacks credentials, the server can reply with a challenge using the 401 (Unauthorized) status code ([RFC7235], Section 3.1) and the WWW-Authenticate header field ([RFC7235], Section 4.1).
For instance:
HTTP/1.1 401 Unauthorized
Date: Mon, 04 Feb 2014 16:50:53 GMT
WWW-Authenticate: Basic realm="WallyWorld"
@dblock and @hazendaz - should I close and create a new issue or change this issue's title?
I see. You should change this issue's title and update to what you really want. I was confused because disableBasicAuthMode seems like "disable everything" for a basic auth filter, so I suggest finding a better name. And again, I personally find negaive, ie. disable-like flags a poor choice for naming because you're doing something to prevent something from happening. Like Windows where you have to press Start to shut the computer down :) So I would call things enableSomething and default it to true.
@dblock thanks for challenging my options and helping me find the cause of my issue; I'll update the title and the desciption