jetty-project/jetty-reactive-httpclient

Reopen Previous issue: java.util.concurrent.ExecutionException: org.eclipse.jetty.client.HttpResponseException: HTTP protocol violation: Authentication challenge without WWW-Authenticate header

Closed this issue · 14 comments

Hi,

I opened an issue here:

#28
jetty/jetty.project#5829

I reported this to Okta in which they replied with teh following:


After investigating this internally I can now provide an answer, Okta does not reply with the www-authenticate header because it does not perform basic authentication, the header tells the client that the user must authenticate but Okta provides that information in the response body: https://developer.okta.com/docs/reference/api/authn/#response-parameters.

In this case, I would recommend submitting this as a New Feature Request, under our Support Portal's Ideas section https://support.okta.com/help/s/ideas.
Features suggested in our community are reviewed and can be voted and commented on by other members of the community, therefore making it much easier for our Product Management Team to prioritize our customers’ needs.

For reference: https://www.okta.com/blog/tag/authentication-methods.


From what got from Okta is that this header is only required when using basic authentication. Most corporate companies are using Okta today, hence, this header restriction/enforcement shouldn't be there unless this restriction doesn't only apply to basic authentication but all methods?

If what Okta is saying is true Is there a way this can be turned off when not using basic authentication?

@majones713 as I have already replied in jetty/jetty.project#5829, Okta is violating RFC7235, which defines a generic framework for HTTP authentication, not only for Basic Authentication.

You can disable HttpClient support for automatic authentication handling, but then you have to do it yourself in your application.

HttpClient client = ...;
client.getProtocolHandlers().remove(WWWAuthenticationProtocolHandler.NAME);

Ask Okta to fix their violation of the standards.

Hi @sbordet , thanks for confirming things in addition to providing a temporary workaround. I'll definitely use this as leverage for reporting purposes to Okta as they are considering this a new feature request vs a defect.

@majones713 some more details for you to use with your discussion to Okta.

History:

HTTP/1.0 spec (1996)
WWW-Authenticate
https://tools.ietf.org/html/rfc1945#section-10.16

"The WWW-Authenticate response-header field must be included in 401 (unauthorized) response messages."

HTTP/1.1 spec (1997)
401 Status Code
https://tools.ietf.org/html/rfc2068#section-10.4.2 - (1997)
https://tools.ietf.org/html/rfc2616#section-10.4.2 - (1999)

"The response MUST include a WWW-Authenticate header field (section 14.46) containing a challenge applicable to the requested resource."

https://tools.ietf.org/html/rfc7235#section-3.1 - (2014)

"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."

This widely supported requirement has been in place on the HTTP spec since 1996 (FYI, this behavior is still present on HTTP/2 and HTTP/3 as well).

There are many registered authentication challenge schemes, BASIC is just one of them. Saying they don't support WWW-Authenticate because they don't support Basic is disingenuous.
The IANA maintains the list of registered authentication schemes:

If Okta decides they want to do the authentication in a way that isn't registered with the IANA, they are free to do that, BUT ...
they are still obligated by the HTTP spec to respond with a WWW-Authenticate header if they choose to use the 401 response status code, Okta is even free to use their own unique challenge scheme (that doesn't conflict with the registered names on the IANA).
If they choose to do their own challenge scheme, then they should document what that new challenge scheme requires.
(This is what Microsoft did with their kerberos implementation, and their unique "Negotiate" auth challenge scheme. Which I believe the Jetty HttpClient supports as well.)

@joakime I heard the word! This was really helpful and just shared with our Architects/Dev leads. This was very helpful. Thanks again!

@sbordet I'm trying to deactivate this validation using the JettyConnectorProvider and JettyHttpClientSupplier but it is not working.

final HttpClient httpClient = new HttpClient();
httpClient.getProtocolHandlers().remove(WWWAuthenticationProtocolHandler.NAME);

baseClientConfiguration = new ClientConfig();
baseClientConfiguration.connectorProvider(new JettyConnectorProvider());
baseClientConfiguration.register(new JettyHttpClientSupplier(httpClient));

Actually the handlers list is empty. Is there anything else I have to do? I'm using the version 2.34.

it is not working.

Too little information.

I'm using the version 2.34.

There is no such version of this project.

Sorry @sbordet. I'm using the project org.glassfish.jersey.connectors:jersey-jetty-connector:2.34. When Jetty client receives a 401 error without the header www-authenticate it is returning protocol violation error. I tried send a httpClient to JettyConnectorProvider following the documentation but Jetty client is still complaining about the header.

https://eclipse-ee4j.github.io/jersey.github.io/apidocs/2.29/jersey/org/glassfish/jersey/jetty/connector/JettyHttpClientSupplier.html

I found the problem. Before removing the protocol handler HttpClient must be started:

final HttpClient httpClient = new HttpClient();
httpClient.start();
httpClient.getProtocolHandlers().remove(WWWAuthenticationProtocolHandler.NAME);

baseClientConfiguration = new ClientConfig();
baseClientConfiguration.connectorProvider(new JettyConnectorProvider());
baseClientConfiguration.register(new JettyHttpClientSupplier(httpClient));
cowwoc commented

It doesn't look like anyone reported this issue to Okta or they are ignoring it because the issue is still present and is annoying :(

Is anyone here an Okta paying customer? Can you update us on the status of this issue on their end?

In a world of service to service comms this is causing some pain, we have services returning 401 without WWW-Authenticate header and it would be nice if Jetty just log.debug-ed this instead of breaking all HTTP error handling code by throwing it's own exception.

In my opinion the standard is a bit outdated, no negotiation is ever going to happen between services, it's only for browsers, in the server side you either have the Bearer/JWT/API Token or not.

I would prefer using Jetty as driver for Spring RestTemplate due to the way read and so timeouts are easy to set, just need to dig now how to turn off this exception (not using raw jetty). Alternatively I could go try to convince people that their production services are implemented incorrectly, but that seems like a lot of effort

Edit: complaining sometimes helps, found a constructor that takes HttpClient and workaround also works with Spring RestClient:

public JettyClientHttpRequestFactory(HttpClient httpClient)

@tarmolehtpuu wrote:

In my opinion the standard is a bit outdated

From June 2022:
https://www.rfc-editor.org/rfc/rfc9110.html#name-www-authenticate

There are users that may rely on this behavior, so breaking all the HTTP specs over the years because your server-side applications do not respect the specifications seems a little too extreme, sorry.

What we can do is to allow you to override the behavior by writing your own AuthenticationProtocolHandler subclass.
If that is acceptable, file an issue to the Jetty project here: https://github.com/jetty/jetty.project/issues

In my opinion the standard is a bit outdated, no negotiation is ever going to happen between services, it's only for browsers, in the server side you either have the Bearer/JWT/API Token or not.

Wonderful thing about IETF specs, they can evolve, and change.
File a proposal to change that aspect of the spec. (You could propose to eliminate it, or soften it, or put conditions around it, etc).
Heck try to get someone at okta to co-sponsor your proposal.

This aspect of the HTTP spec has been around since 1997, with the introduction of HTTP/1.x, and it still applies even in HTTP/2 and HTTP/3.

If you read through the changes of the spec over time you will quickly discover is that the HTTP spec is fluid, and does change.

What you will also learn, is that these specs make no distinction of what kind of HTTP Client is being used.
The terminology used in the specs is "User Agent".

The definition of "User Agent" even points out that the general-purpose Web Browser is the minority.

The term "user agent" refers to any of the various client programs that initiate a request.

The most familiar form of user agent is the general-purpose Web browser, but that's only a small percentage of implementations. Other common user agents include spiders (web-traversing robots), command-line tools, billboard screens, household appliances, scales, light bulbs, firmware update scripts, mobile apps, and communication devices in a multitude of shapes and sizes.

Being a user agent does not imply that there is a human user directly interacting with the software agent at the time of a request. In many cases, a user agent is installed or configured to run in the background and save its results for later inspection (or save only a subset of those results that might be interesting or erroneous). Spiders, for example, are typically given a start URI and configured to follow certain behavior while crawling the Web as a hypertext graph.

Many user agents cannot, or choose not to, make interactive suggestions to their user or provide adequate warning for security or privacy concerns. In the few cases where this specification requires reporting of errors to the user, it is acceptable for such reporting to only be observable in an error console or log file. Likewise, requirements that an automated action be confirmed by the user before proceeding might be met via advance configuration choices, run-time options, or simple avoidance of the unsafe action; confirmation does not imply any specific user interface or interruption of normal processing if the user has already made that choice.

In short, there is no aspect of the HTTP spec (defined at the IETF) that is "only for browsers".
There are other spec organizations out there for browsers to follow, see the https://whatwg.org/ and https://www.w3.org/

The options you have in front of you right now.

  1. use the HTTP spec properly, as it is defined.
  2. file an issue with the service provider (okta?) about not following the published HTTP specs.
  3. submit a feature request to the HTTP client you have an issue with to request a non-default configuration option to work around this behavior. (see comment 33)
  4. change the HTTP spec by starting a conversation on the HTTP spec mailing lists about your concerns. (https://datatracker.ietf.org/wg/httpbis/about/)
  5. change the HTTP spec by submitting an errata against that section of the HTTP spec and starting the conversation that way. (https://www.rfc-editor.org/errata/rfc9110)

I managed to sort it out, thanks for the thorough explanation :)