Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NTLM Support with Full Domain and Server Authentication #87

Merged
merged 2 commits into from
Jul 20, 2013

Conversation

pmorton
Copy link
Contributor

@pmorton pmorton commented Mar 20, 2013

  • You can now specify a domain as the last parameter of ntlm authentication ['user','password','domain']. If the domain is omitted we assume that you want to authenticate to the local server. (Note that this is a behavior change from the current implementation) Currently, if you did not specify a domain it would select the default target which is the machine for a non-domain joined machine, or the domain for a domain joined machine.
  • Some newer microsoft services only allow Negotiate authentication. Negotiate will degrade to NTLM authentication and is 100% compatible with the NTLM scheme. The client will now query the server for valid auth types and use Negotiate or NTLM in that order. If the auth type is not supported we try NTLM anyhow.
  • Type 1 Packets where malformed because they did not include the domain and workstation. In the general case, these should always be null for a type 1 packet. This is purely aesthetic, but the inclusion of this information quiets wireshark warnings about the packet being malformed. Note: Chrome, Firfox and Curl also fill these values in a null by default.
  • Type 2 Packets were missing the Workstation name. This is now included by default.
  • Type 2 Packets were missing the target domain. Without this the server would try to authenticate using the default target (my first comment on the behavior change).

* You can now specify a domain as the last parameter of ntlm authentication ['user','password','domain']. If the domain is omitted we assume that you want to authenticate to the local server. (Note that this is a behavior change from the current implementation) Currently, if you did not specify a domain it would select the default target which is the machine for a non-domain joined machine, or the domain for a domain joined machine.

* Some newer microsoft services only allow Negotiate authentication. Negotiate will degrade to NTLM authentication and is 100% compatible with the NTLM scheme. The client will now query the server for valid auth types and use Negotiate or NTLM in that order. If the auth type is not supported we try NTLM anyhow.

* Type 1 Packets where malformed because they did not include the domain and workstation. In the general case, these should always be null for a type 1 packet. This is purely aesthetic, but the inclusion of this information quiets wireshark warnings about the packet being malformed. Note: Chrome, Firfox and Curl also fill these values in a null by default.

* Type 2 Packets were missing the Workstation name. This is now included by default.

* Type 2 Packets were missing the target domain. Without this the server would try to authenticate using the default target (my first comment on the behavior change).
@rubiii
Copy link
Contributor

rubiii commented Mar 20, 2013

wow. thank you very much @pmorton!

@rogerleite can you check on this? we need to run the manual integration test i think.
@coldnebo would you be able to take a look at this?

@pmorton
Copy link
Contributor Author

pmorton commented Mar 20, 2013

Below are the manual testing steps that I have taken.

Test Script

 HTTPI.adapter = :net_http
  r = HTTPI::Request.new('http://localhost:8080')
  r.auth.ntlm 'domain user', 'domain password', 'domain'
  t = HTTPI.get(r)
  puts t.inspect

  HTTPI.adapter = :net_http
  r = HTTPI::Request.new('http://localhost:8080')
  r.auth.ntlm 'vagrant', 'vagrant'
  t = HTTPI.get(r)
  puts t.inspect
  1. Configure IIS to use Negotiate authentication only and run the test script
D, [2013-03-20T12:48:39.728322 #78822] DEBUG -- : HTTPI GET request to localhost (net_http)
#<HTTPI::Response:0x007f8ff42d5dd0 @code=200, @headers={"content-type"=>"text/html", "last-modified"=>"Mon, 18 Mar 2013 20:46:57 GMT", "accept-ranges"=>"bytes", "etag"=>"\"93684bbb1924ce1:0\"", "server"=>"Microsoft-IIS/7.5", "persistent-auth"=>"true", "date"=>"Wed, 20 Mar 2013 19:48:54 GMT", "content-length"=>"689"}, @raw_body="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\r\n<title>IIS7</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody {\r\n\tcolor:#000000;\r\n\tbackground-color:#B3B3B3;\r\n\tmargin:0;\r\n}\r\n\r\n#container {\r\n\tmargin-left:auto;\r\n\tmargin-right:auto;\r\n\ttext-align:center;\r\n\t}\r\n\r\na img {\r\n\tborder:none;\r\n}\r\n\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"container\">\r\n<a href=\"http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409\"><img src=\"welcome.png\" alt=\"IIS7\" width=\"571\" height=\"411\" /></a>\r\n</div>\r\n</body>\r\n</html>">

D, [2013-03-20T12:48:54.750096 #78822] DEBUG -- : HTTPI GET request to localhost (net_http)
#<HTTPI::Response:0x007f8ff433caf8 @code=200, @headers={"content-type"=>"text/html", "last-modified"=>"Mon, 18 Mar 2013 20:46:57 GMT", "accept-ranges"=>"bytes", "etag"=>"\"93684bbb1924ce1:0\"", "server"=>"Microsoft-IIS/7.5", "persistent-auth"=>"true", "date"=>"Wed, 20 Mar 2013 19:48:54 GMT", "content-length"=>"689"}, @raw_body="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\r\n<title>IIS7</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody {\r\n\tcolor:#000000;\r\n\tbackground-color:#B3B3B3;\r\n\tmargin:0;\r\n}\r\n\r\n#container {\r\n\tmargin-left:auto;\r\n\tmargin-right:auto;\r\n\ttext-align:center;\r\n\t}\r\n\r\na img {\r\n\tborder:none;\r\n}\r\n\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"container\">\r\n<a href=\"http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409\"><img src=\"welcome.png\" alt=\"IIS7\" width=\"571\" height=\"411\" /></a>\r\n</div>\r\n</body>\r\n</html>">
  1. Configure for NTLM and Negotiate. Run Script.
D, [2013-03-20T12:52:09.795030 #78968] DEBUG -- : HTTPI GET request to localhost (net_http)
#<HTTPI::Response:0x007fdc24b1c2b0 @code=200, @headers={"content-type"=>"text/html", "last-modified"=>"Mon, 18 Mar 2013 20:46:57 GMT", "accept-ranges"=>"bytes", "etag"=>"\"93684bbb1924ce1:0\"", "server"=>"Microsoft-IIS/7.5", "persistent-auth"=>"true", "date"=>"Wed, 20 Mar 2013 19:52:24 GMT", "content-length"=>"689"}, @raw_body="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\r\n<title>IIS7</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody {\r\n\tcolor:#000000;\r\n\tbackground-color:#B3B3B3;\r\n\tmargin:0;\r\n}\r\n\r\n#container {\r\n\tmargin-left:auto;\r\n\tmargin-right:auto;\r\n\ttext-align:center;\r\n\t}\r\n\r\na img {\r\n\tborder:none;\r\n}\r\n\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"container\">\r\n<a href=\"http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409\"><img src=\"welcome.png\" alt=\"IIS7\" width=\"571\" height=\"411\" /></a>\r\n</div>\r\n</body>\r\n</html>">

D, [2013-03-20T12:52:24.793451 #78968] DEBUG -- : HTTPI GET request to localhost (net_http)
#<HTTPI::Response:0x007fdc24b867a0 @code=200, @headers={"content-type"=>"text/html", "last-modified"=>"Mon, 18 Mar 2013 20:46:57 GMT", "accept-ranges"=>"bytes", "etag"=>"\"93684bbb1924ce1:0\"", "server"=>"Microsoft-IIS/7.5", "persistent-auth"=>"true", "date"=>"Wed, 20 Mar 2013 19:52:24 GMT", "content-length"=>"689"}, @raw_body="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\r\n<title>IIS7</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody {\r\n\tcolor:#000000;\r\n\tbackground-color:#B3B3B3;\r\n\tmargin:0;\r\n}\r\n\r\n#container {\r\n\tmargin-left:auto;\r\n\tmargin-right:auto;\r\n\ttext-align:center;\r\n\t}\r\n\r\na img {\r\n\tborder:none;\r\n}\r\n\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"container\">\r\n<a href=\"http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409\"><img src=\"welcome.png\" alt=\"IIS7\" width=\"571\" height=\"411\" /></a>\r\n</div>\r\n</body>\r\n</html>">
  1. Configure for NTLM only. Run Script
#<HTTPI::Response:0x007fe68ca297f0 @code=200, @headers={"content-type"=>"text/html", "last-modified"=>"Mon, 18 Mar 2013 20:46:57 GMT", "accept-ranges"=>"bytes", "etag"=>"\"93684bbb1924ce1:0\"", "server"=>"Microsoft-IIS/7.5", "persistent-auth"=>"true", "date"=>"Wed, 20 Mar 2013 19:53:08 GMT", "content-length"=>"689"}, @raw_body="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\r\n<title>IIS7</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody {\r\n\tcolor:#000000;\r\n\tbackground-color:#B3B3B3;\r\n\tmargin:0;\r\n}\r\n\r\n#container {\r\n\tmargin-left:auto;\r\n\tmargin-right:auto;\r\n\ttext-align:center;\r\n\t}\r\n\r\na img {\r\n\tborder:none;\r\n}\r\n\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"container\">\r\n<a href=\"http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409\"><img src=\"welcome.png\" alt=\"IIS7\" width=\"571\" height=\"411\" /></a>\r\n</div>\r\n</body>\r\n</html>">

D, [2013-03-20T12:53:08.129358 #79008] DEBUG -- : HTTPI GET request to localhost (net_http)
#<HTTPI::Response:0x007fe68ca90770 @code=200, @headers={"content-type"=>"text/html", "last-modified"=>"Mon, 18 Mar 2013 20:46:57 GMT", "accept-ranges"=>"bytes", "etag"=>"\"93684bbb1924ce1:0\"", "server"=>"Microsoft-IIS/7.5", "persistent-auth"=>"true", "date"=>"Wed, 20 Mar 2013 19:53:08 GMT", "content-length"=>"689"}, @raw_body="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\r\n<title>IIS7</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody {\r\n\tcolor:#000000;\r\n\tbackground-color:#B3B3B3;\r\n\tmargin:0;\r\n}\r\n\r\n#container {\r\n\tmargin-left:auto;\r\n\tmargin-right:auto;\r\n\ttext-align:center;\r\n\t}\r\n\r\na img {\r\n\tborder:none;\r\n}\r\n\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"container\">\r\n<a href=\"http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409\"><img src=\"welcome.png\" alt=\"IIS7\" width=\"571\" height=\"411\" /></a>\r\n</div>\r\n</body>\r\n</html>">
  1. Un-Join the machine from the domain and run script. Note the first request failed with 401 as it should have (because it is trying to use a domain account).
D, [2013-03-20T12:57:19.109520 #79181] DEBUG -- : HTTPI GET request to localhost (net_http)
#<HTTPI::Response:0x007fc1daabe700 @code=401, @headers={"content-type"=>"text/html", "server"=>"Microsoft-IIS/7.5", "www-authenticate"=>"NTLM", "date"=>"Wed, 20 Mar 2013 19:57:17 GMT", "content-length"=>"1293"}, @raw_body="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"/>\r\n<title>401 - Unauthorized: Access is denied due to invalid credentials.</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}\r\nfieldset{padding:0 15px 10px 15px;} \r\nh1{font-size:2.4em;margin:0;color:#FFF;}\r\nh2{font-size:1.7em;margin:0;color:#CC0000;} \r\nh3{font-size:1.2em;margin:10px 0 0 0;color:#000000;} \r\n#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:\"trebuchet MS\", Verdana, sans-serif;color:#FFF;\r\nbackground-color:#555555;}\r\n#content{margin:0 0 0 2%;position:relative;}\r\n.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"header\"><h1>Server Error</h1></div>\r\n<div id=\"content\">\r\n <div class=\"content-container\"><fieldset>\r\n  <h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>\r\n  <h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>\r\n </fieldset></div>\r\n</div>\r\n</body>\r\n</html>\r\n">

D, [2013-03-20T12:57:19.336814 #79181] DEBUG -- : HTTPI GET request to localhost (net_http)
#<HTTPI::Response:0x007fc1dab25d38 @code=200, @headers={"content-type"=>"text/html", "last-modified"=>"Mon, 18 Mar 2013 20:46:57 GMT", "accept-ranges"=>"bytes", "etag"=>"\"93684bbb1924ce1:0\"", "server"=>"Microsoft-IIS/7.5", "persistent-auth"=>"true", "date"=>"Wed, 20 Mar 2013 19:57:17 GMT", "content-length"=>"689"}, @raw_body="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\r\n<title>IIS7</title>\r\n<style type=\"text/css\">\r\n<!--\r\nbody {\r\n\tcolor:#000000;\r\n\tbackground-color:#B3B3B3;\r\n\tmargin:0;\r\n}\r\n\r\n#container {\r\n\tmargin-left:auto;\r\n\tmargin-right:auto;\r\n\ttext-align:center;\r\n\t}\r\n\r\na img {\r\n\tborder:none;\r\n}\r\n\r\n-->\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"container\">\r\n<a href=\"http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409\"><img src=\"welcome.png\" alt=\"IIS7\" width=\"571\" height=\"411\" /></a>\r\n</div>\r\n</body>\r\n</html>">

@rogerleite
Copy link
Member

@pmorton 🤘 we need to update https://github.com/savonrb/httpi/wiki/NTLM-Integration-Test-Plan guide?
It seems we only need to update Changelog and https://github.com/savonrb/httpirb.com

@pmorton
Copy link
Contributor Author

pmorton commented Mar 20, 2013

@rogerleite I think that it would make sense to update https://github.com/savonrb/httpi/wiki/NTLM-Integration-Test-Plan . The nice part of what you have setup already is that it is straight forward and covers most use cases. By adding domain authentication to the manual test we add a huge amount of complexity and or raise the bar for who can develop in this area (I.e. you need to have a domain to develop easily). How do you think we best cover the added complexity in the Wiki?

The matrix that needs to be covered is

Auth MethodCredential TypeSystem State
NTLMDomain User, Local UserDomain Joined
NTLM, NegotiateDomain User, Local UserDomain Joined
NegotiateDomain User, Local UserDomain Joined
NTLMLocal UserNon-Domain Joined
NTLM, Negotiate Local UserNon-Domain Joined
NegotiateLocal UserNon-Domain Joined

@coldnebo
Copy link
Contributor

Hi guys, just looked at this, I like this a lot. I had a basic knowledge of NTLM auth, and a use case at my work that guided me through the first stab, but it seems like @pmorton has more experience with all the different variations.

@pmorton, I threw together the NTLM-Integration-Test-Plan just enough to get the basics working, it could stand expansion. I think you're right, configuring a domain server is probably a bit more work as well as the variations of user. (I'm not a windows net admin, so my knowledge gets a bit fuzzy here). If the test setup is too complex, we could possibly look at packaging it into a VM image (like the rails team).

@coldnebo
Copy link
Contributor

@rubiii , everyone: I ran the external NTLM test on @pmorton's branch and it works fine with the existing NTLM test plan vm... so it's compatible to boot. Combined with the more extensive manual testing that Paul has done above, I think this is a win. Thoughts?

@rubiii
Copy link
Contributor

rubiii commented Mar 21, 2013

@coldnebo thank you very much for your feedback. regarding the test image idea: the problem with this is the windows evaluation image, right? doesn't that expire after n days?

@pmorton
Copy link
Contributor Author

pmorton commented Mar 21, 2013

I am thinking that some vagrant magic with windows trials will do the
trick.

Would it be possible to merge this change and open a new issue to make the
ntlm test infrastructure more robust.

I am working on a major update to the WinRM and vagrant windows gem. Once I
can ship those, I will be happy to give you a vagrant setup...

P

On Mar 21, 2013, at 1:31 AM, Daniel Harrington [email protected]
wrote:

@coldnebo https://github.com/coldnebo thank you very much for your
feedback. regarding the test image idea: the problem with this is the
windows evaluation image, right?


Reply to this email directly or view it on
GitHubhttps://github.com//pull/87#issuecomment-15224666
.

@rubiii
Copy link
Contributor

rubiii commented Mar 21, 2013

@pmorton sounds like a plan 👍

@coldnebo
Copy link
Contributor

@pmorton I forgot about that wrinkle. Another solution might be to come up with a Chef recipe... while I'm fairly sure a recipe could be made for setting up our NTLM test environment, there seems to be quite a few steps to get chef installed on a fresh Windows trial image... 😦

So... what other rabbits in the hat? We could use a VM based on a private Win server license -- but I really have no idea how to make such a VM private for an open source project. A hosted Win server is an option, but since Microsoft itself advises solution developers to not use NTLM it's going to be hard if not impossible to find a hosting provider who would open their server or network up to NTLM auth unless it could be sufficiently sandboxed.

Which leaves us with a few scattered devs running manual tests?

👍 @pmorton one thing we could do is to automate your manual tests similar to the way in which I did it by setting a console var and including the appropriate connection info in the test:

$ NTLM=external bundle exec rspec

Caveats are (of course) if your manual test is done in your own intranet and you can't very well put your private company information in a public test spec... 👎

📓 Note: we may wonder why bother since Microsoft advises against NTLM and these other factors complicate support for it. The reason NTLM is still so prevalent (in spite of these problems) is that it enables Windows workstations on the intranet to seamlessly autologin to IIS when using IE. This means Windows users using IE get a drastically better experience logging into things like Sharepoint and other IIS authenticated intranet sites. Other browsers/OSes still have to log in manually. I agree this is a pretty weak reason to keep an antiquated security protocol, but there it is.

@coldnebo
Copy link
Contributor

@rubiii:

Would it be possible to merge this change and open a new issue to make the
ntlm test infrastructure more robust.

agreed.

@rubiii
Copy link
Contributor

rubiii commented Mar 21, 2013

@coldnebo i think you could use chef solo to solve this. we should definitely use some sort of automated provisioning.

@rogerleite
Copy link
Member

Agree with @coldnebo and @rubiii ...

Would it be possible to merge this change and open a new issue to make the
ntlm test infrastructure more robust.

IMHO, for today, we would carefully document all these NTLM "secrets" and keep walking.

@pmorton great work!
@coldnebo thanks for helping!

@pmorton
Copy link
Contributor Author

pmorton commented Mar 21, 2013

Hold off on the merge. I have another commit that will fix a bug that I found... Specifically if the server does not offer authentication methods the code will fail.

@pmorton
Copy link
Contributor Author

pmorton commented Mar 22, 2013

In addition, I need to push a new version of the rubynltm gem to rubygems and update the gemspec on this gem. The reason that this was not caught in testing was because I had a custom version of the gem installed.

@pmorton
Copy link
Contributor Author

pmorton commented Mar 22, 2013

I have pushed a new version of the gem to rubygem and will update the dependencies.

@rubiii I am working at addressing anther issue. If you issue a request to a server that does not support the HEAD verb, the remote server will return a 405 not supported. I looked at how other libraries handle this and what they seem to do it piggyback on the verb that was originally requested. Do you have any pointers on how I might be able to find the verb of the request that I am trying to authenticate.

@rubiii
Copy link
Contributor

rubiii commented Mar 22, 2013

@pmorton can you open another issue for that? i think i need a more detailed explanation of the problem.
like what's your workflow and what do you mean by "the verb that was originally requested"?

@pmorton
Copy link
Contributor Author

pmorton commented Mar 22, 2013

@rubiii I would be happy to open a new issue, but let me see if I can summarize it here to see if it makes sense.

If you call HTTPI.post , The authentication method should only everPOST to the server while performing authentication. Likewise if you call HTTPI.get the server should only ever GET from the server while performing authentication. If you take a look at Line 87, you will see that we are always performing a HEAD request to negotiate authentication.

HEAD seems like a logical choice except some servers have elected to disable the HEAD HTTP verb. This breaks the negotiation protocol because the server returns a 405 instead of a 401. In fact I will go a step further and say that many other HTTP clients use the orignal request to negotiate authentication. What I mean by this is that all requests that hit the remote server include the headers, full body and http verb of the original request. This gives me the sense that using a modified version of the original request is the right thing to do.

So when the user has called HTTPI.post I need to know that they intended to POST to the server. Is that stored anywhere in the state that would be accessible to the authentication method?

@coldnebo
Copy link
Contributor

Yeah, I chose head initially because it seemed more efficient than a full get or post, but I didn't support this legacy case.

There's another optimization that I didn't pursue, which is caching the auth for subsequent requests.

Sent from my iPhone

On Mar 22, 2013, at 9:55 AM, Paul Morton [email protected] wrote:

@rubiii I would be happy to open a new issue, but let me see if I can summarize it here to see if it makes sense.

If you call HTTPI.post , The authentication method should only everPOST to the server while performing authentication. Likewise if you call HTTPI.get the server should only ever GET from the server while performing authentication. If you take a look at Line 87, you will see that we are always performing a HEAD request to negotiate authentication.

HEAD seems like a logical choice except some servers have elected to disable the HEAD HTTP verb. This breaks the negotiation protocol because the server returns a 405 instead of a 401. In fact I will go a step further and say that many other HTTP clients use the orignal request to negotiate authentication. What I mean by this is that all requests that hit the remote server include the headers, full body and http verb of the original request. This gives me the sense that using a modified version of the original request is the right thing to do.

So when the user has called HTTPI.post I need to know that they intended to POST to the server. Is that stored anywhere in the state that would be accessible to the authentication method?


Reply to this email directly or view it on GitHub.

@rubiii
Copy link
Contributor

rubiii commented Mar 22, 2013

@pmorton i see. i don't think that information is available, but i could be wrong. /cc @rogerleite

@rogerleite
Copy link
Member

@pmorton at line 66 you have to pass type variable to negotiate_ntlm_auth.
At line 74 you replace :head by type variable.

Hope that helps!

@rogerleite
Copy link
Member

@pmorton this PR is kind of blocking @rubiii to release new version of savon (savonrb/savon#405). Do you need some help? What can i do to help you?

@rubiii
Copy link
Contributor

rubiii commented May 5, 2013

@pmorton sorry for spamming you with notifications, but i feel like this is almost done and it would be very sad if we could not get it released. so if you could just give us a quick update, i would really appreciate it.

@coldnebo
Copy link
Contributor

coldnebo commented May 6, 2013

I think @pmorton said the hold up was trying to figure out how to find the verb of the request being authenticated. This is so he can issue the existing verb instead of (my solution) issuing a HEAD request for the first part.

I can look at this tonight for you. @rubiii, @rogerleite is there anything else that needs to be addressed? I too would like to see this in the release! 😄

@pmorton
Copy link
Contributor Author

pmorton commented May 6, 2013

Hey All - Sorry for going silent. There are still two things to do here.

  1. Update the gemspec to use Version 0.3.1 of ruby-ntlm (I released this about a month ago. It will now obey the :domain option)
  2. Retrying the request with the original verb. In specific this causes issues with WinRM because the http.sys service only supports POST, so substituting a HEAD request results in a 403. Note that this bug pre-existed my pull request. It is entirely possible to ship this code with the bug (since no-one but me has complained).
  3. I would like someone else to try running the integration tests.( Trust but verify )

@rogerleite
Copy link
Member

@pmorton this constraint "rubyntlm requires Ruby version >= 1.9.2" is really necessary? Travis is "broken" because of this and HTTPI support many ruby versions https://travis-ci.org/savonrb/httpi/builds/6929272
Support to 1.8.7 is questionable, but JRuby and Rubinius i think is crucial.

@rubiii what are the directives about Ruby versions?

@coldnebo To launch this new release, it should be good to close this two issues too. #88 and #90. I don't know if is mandatory.

@rogerleite
Copy link
Member

Another thing. Using rubyntlm last version, when running rake spec on httpi, i'm having this failure:

Failures:

  1) HTTPI::Adapter::NetHTTP http requests supports ntlm authentication
     Failure/Error: response = HTTPI.get(request, adapter)
     Net::HTTPBadResponse:
       wrong status line: "ntlm-authHTTP/1.1 200 OK"
     # ./lib/httpi/adapter/net_http.rb:42:in `block in request'
     # ./lib/httpi/adapter/net_http.rb:66:in `call'
     # ./lib/httpi/adapter/net_http.rb:66:in `block in do_request'
     # ./lib/httpi/adapter/net_http.rb:64:in `do_request'
     # ./lib/httpi/adapter/net_http.rb:33:in `request'
     # ./lib/httpi.rb:138:in `request'
     # ./lib/httpi.rb:104:in `get'
     # ./spec/httpi/adapter/net_http_spec.rb:67:in `block (3 levels) in <top (required)>'

@pmorton and @rubiii some idea what should be? Using version 0.1.1 doesn't occur. Weird. 😕

@rubiii
Copy link
Contributor

rubiii commented May 6, 2013

@rogerleite @pmorton i think it would be good to have it support 1.8 if it's an easy fix.
i'll think about dropping support for 1.8 when it reaches its end of life in june.
right now the travis build matrix defines the supported versions.

@rogerleite
Copy link
Member

Rubyntlm works only with 1.9 version because replaced Kconv for "native 1.9 encoding". WinRb/rubyntlm@3f54039. It seems a no way back.

@rubiii
Copy link
Contributor

rubiii commented May 6, 2013

@rogerleite you could still conditionally use kconv on 1.8 in a separate method and remove it as soon as support for 1.8 is dropped. of course this is not my decision. but i haven't thought about dropping support for 1.8 for httpi and therefore savon just yet.

@pmorton
Copy link
Contributor Author

pmorton commented May 6, 2013

@rogerleite @rubiii I would happily accept a pull request that supports 1.8 and (with passing tests Note rbx is broken already so no need to update). There was a non-trivial amount of work to make encoding work properly in both versions of ruby. I dropped 1.8 support because of EOL. 1.8 is very close to EOL and IMHO there are few reasons to use it.

Note: I can unlock the dependency, but it will no longer support some NTLM scenarios. In specific older versions of the rubyntlm gem did not respect the domain and would always use the domain received in the type 2 request. I am not a fan of unlocking it because the behavior is determined by the dependency that is taken.

@coldnebo
Copy link
Contributor

coldnebo commented May 7, 2013

@pmorton, it's not pretty, but checkout these hacks, especially the one to figure out the current verb in the request.

The only problem is it delays the request by 20 seconds... not sure why. Maybe this will help you get to the next part? That's all for tonight.

P.S. I fiddled with rubyntlm looking at 1.8, but realized it was non-trivial to adapt Iconv and the new encoding at the same time. It's possible, but I realized you're probably looking at having a conditional adapter -- don't know if you want that much refactoring, so decided to punt on helping with that part for now.

@mmmries
Copy link

mmmries commented May 14, 2013

Hey Guys -
I had updated a fork of pyu-ntlm and was using that with httpi-ntlm to get NTLM support, but I think this is a much nicer solution. rubyntlm looks clean and the support it provides looks much broader.

I just pulled down a copy of @pmorton branch and tested it against my production servers. Everything worked great. Performance looked fine. I can't speak to all of the variations of Windows Servers mentioned in this discussion, but it certainly worked for me on ruby 2.0 and jruby 1.7.3 talking to my production servers (Microsoft Dynamics CRM 2012).

@pmorton I would be happy to run the integration tests as a second set of verifications, but I'm not sure if you are talking about the integrations tests in rubyntlm or httpi.

@rogerleite
Copy link
Member

Hi everybody!

@pmorton and @coldnebo, i did a pull request to support Ruby 1.8.7. This way, httpi can still support 1.8.7 too. If the PR needs change, just notify me.

@hqmq thanks for the feedback.

@rubiii rubiii merged commit 2abc46c into savonrb:master Jul 20, 2013
@rubiii
Copy link
Contributor

rubiii commented Jul 20, 2013

finally merged and pushed this to master. there are three failing tests which appear to be related to ntlm.
can someone take a look at these and open a new pull request?
this is kind of like the last thing to solve for v2.1.0.

@ghost ghost assigned rubiii Jul 20, 2013
@rubiii rubiii mentioned this pull request Jul 20, 2013
27 tasks
@coldnebo
Copy link
Contributor

I'll take a look tonight.

Sent from my iPhone

On Jul 20, 2013, at 11:24 AM, Daniel Harrington [email protected] wrote:

finally merged and pushed this to master. there are three failing tests which appear to be related to ntlm.
can someone take a look at these and open a new pull request?
this is kind of like the last thing to solve for v2.1.0.


Reply to this email directly or view it on GitHub.

@rubiii
Copy link
Contributor

rubiii commented Jul 21, 2013

thanks @coldnebo. i really appreciate it.

@rubiii
Copy link
Contributor

rubiii commented Jul 22, 2013

continue at #97

@rubiii
Copy link
Contributor

rubiii commented Jul 22, 2013

this has finally been released with version 2.1.0.

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

Successfully merging this pull request may close these issues.

5 participants