httpclient basic auth sometimes broken (specifically, with post) #181

Closed
terabyte opened this Issue Sep 27, 2013 · 6 comments

Comments

Projects
None yet
4 participants

The following code, roughly, fails to work:

http = HTTPClient.new
http.ssl_config.add_trust_ca("path/to/our/cert.pem")
http.set_auth(nil, USERNAME, PASSWORD)
http.post(url, nil, {})

The following change fixes it:

http = HTTPClient.new
http.ssl_config.add_trust_ca("path/to/our/cert.pem")
http.set_auth(nil, USERNAME, PASSWORD)
headers = {
  "Authorization" => "Basic " + Base64.encode64(USERNAME + ':' + PASSWORD).gsub("\n",''),
}
http.post(url, nil, headers)

I am using ruby 2.0.0-p195. Other similar issues currently open imply other HTTP verbs may be affected, and it may be ruby-2.0 related.

in case more details are needed to repro, I am trying to call artifactory's "copy" API: http://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API#ArtifactoryRESTAPI-CopyItem and enabled debug output using http.debug_dev = $stderr, which shows the authorization header isn't being set. The same code, with "post" changed to "get", sends the header.

BrackXs commented Oct 8, 2013

I have the same problem with ruby 1.9.2p180 (2011-02-18 revision 30909) [i686-linux]

Owner

nahi commented Dec 2, 2013

Can you show me the wiredump? The initial request of GET or POST should not send 'Authorization' header but when httpclient receives 401 error (unauthorized) for the request, it should re-send the request with Authorization header.

You can skip the initial authentication negotiation by;

http.set_auth(url, user, password)
http.www_auth.basic_auth.challenge(url)
http.get(...)

which is ugly... I'm gonna change this behavior at the next release.

terabyte commented Dec 2, 2013

nahi - I don't have a wire dump handy, but my guess is artifactory ignores the standard and doesn't send a 401 error, instead sending a 404 not found or something else (because they don't want to leak the existence of URLs to unauthorized requesters). IF this is what is going on, it is dumb, but it's common. I've seen several services fail to correctly implement auth as per the standard. A reasonable fix might be to have a flag to force sending auth on every request instead of waiting for the 401. (maybe call it the :my_server_sucks_and_doesnt_follow_RFCs => true)

EDIT: oh, I didn't quite catch what you said about skipping the negotiation at first. Are you saying that if you call basic_auth.challenge(URL) first it will always send the Auth headers for that URL henceforth? If that's true, it'd just be nice to document that (or, if you are going to clean it up, do that, then document the cleaned up API). Thanks!

dkam commented Oct 14, 2014

These other issues look to be related: #133 and #131

nahi added a commit that referenced this issue Oct 19, 2014

Add :force_basic_auth config
Generally HTTP client must send Authorization header after it gets 401
error from server from security reason. But in some situation (e.g.
API client) you might want to send Authorization from the beginning.

You can turn on/off force_basic_auth flag for sending Authorization
header from the beginning. (Of cource, if a request URI matches with
the URI you set in set_auth method)

Syntax:
  HTTPClient.new(:force_basic_auth => true)
or
  c = HTTPClient.new
  c.force_basic_auth = true

Closes #166, #179, #181.
Owner

nahi commented Oct 19, 2014

I finally added :force_basic_auth config to HTTPClient.
5be11cb

@nahi nahi closed this Oct 19, 2014

@tkudiyarova tkudiyarova referenced this issue in Datacom/Viewpoint Nov 6, 2015

Merged

Add support for Streaming Notifications #3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment