From: Justin Bailey Date: 2006-07-15T08:07:34+09:00 Subject: [ANN - Resend] Ruby Win32 SSPI 0.0.1 - Enabling NTLM/Negotiate proxy authentication ------=_Part_44474_9294603.1152918451185 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline * fingers slipped and I sent previous announcement early - oops! * My work place implemented install a proxy server recently, and because it demands NTLM/Negotiate authentication, a bunch of my "utility" scripts that scraped the web for me stopped working. Well, that sounded like the opportunity to develop a cool Ruby library! This library provides bindings to the Win32 SSPI library, which enables authentication as the current user with proxy servers using the "Negotiate"/SPNEGO protocol (which typically just means NTLM). There are some pure Ruby implementations of the NTLM protocol, but this is the only one I know of that will authenticate with a proxy server as the current user - meaning you don't have to put your username or password in an environment variable or anywhere else. The library also includes a patch for open-uri and Net:HTTP that will make the authentication process seamless. I have only tested this in my own environment so I'm sure its fragile. Please try it out if you have run into this issue yourself. The project can be found at: http://rubyforge.org/projects/rubysspi/ Gem install will be available when the index updates: gem install rubysspi Documentation is available in the gem, but here is the README from the distribution. Comments and feedback welcome! Justin === README === = Introduction This library provides bindings to the Win32 SSPI libraries, which implement various security protocols for Windows. The library was primarily developed to give Negotiate/NTLM proxy authentication abilities to Net::HTTP, similar to support found in Internet Explorer or Firefox. The libary is NOT an implementation of the NTLM protocol, and does not give the ability to authenticate as any given user. It is able to authenticate with a proxy server as the current user. This project can be found on rubyforge at: http://rubyforge.org/projects/rubysspi = Using with open-uri To use the library with open-uri, make sure to set the environment variable +http_proxy+ to your proxy server. This must be a hostname and port in URL form. E.g.: http://proxy.corp.com:8080 The library will grab your current username and domain from the environment variables +USERNAME+ and +USERDOMAIN+. This should be set for you by Windows already. The library implements a patch on top of Net::HTTP, which means open-uri gets it too. At the top of your script, make sure to require the patch after +open-uri+: require +open-uri+ require +rubysspi/proxy_auth+ open("http://www.google.com") { |f| puts(f.gets(nil)) } Note that this patch does NOT work with the +http_proxy_user+ and +http_proxy_password+ environment variables. The library will ONLY authenticate as the current user. = Using with Net::HTTP Net::HTTP will not use the proxy server supplied in the environment variable automatically, so you have to supply the proxy address yourself. Otherwise, it's exactly the same: require 'net/http' require 'rubysspi/proxy_auth+ Net::HTTP::Proxy("proxy.corp.com", 8080).start("www.google.com") do |http| resp = http.request_get "/" puts resp.body end = Using rubysspi directly As stated, the library is geared primarily towards supporting Negotiate/NTLM authentication with proxy servers. In this vein, you can manually authenticate a given HTTP connection with a single call: require 'rubysspi' Net::HTTP.Proxy(proxy.host, proxy.port).start("www.google.com") do |http| resp = SSPI::NegotiateAuth.proxy_auth_get http, "/" end The +resp+ variable will contain the response from Google, with any proxy authorization necessary taken care of automatically. Note that if the +http+ connection is not closed, any subsequent requests will NOT require authentication. If the above method is used, it is recommended that you do NOT require the 'rubysspi/proxy_auth' library, as the interaction between the two will fail. The library can be used directly to generate tokens appropriate for the current user, too. To get started, first create an instance of the SSPI::NegotiateAuth class: require 'rubysspi' n = SSPI::NegotiateAuth.new Next, get the first token by calling get_initial_token: token = n.get_initial_token This token returned will be Base64 encoded and can be directly placed in an HTTP header. This token can be easily decoded, however, and is usually an NTLM Type 1 message. After getting a response from the server (usually an NTLM Type 2 message), pass it into the complete_authentication: token = n.complete_authentication(server_token) Note that server_token can be Base64 encoded or not, and if it starts with "Negotiate", that phrase will be stripped off. This allows the response from a Proxy-Authentication header to be passed into the method directly. The token can be decoded externally and passed in, too. The token returned (usually an NTLM Type 3) message can then be sent to the server and the connection should be authenticated. = Thanks & References Many references were used in decoding both NTLM messages and integrating with the SSPI library. Among them are: * Managed SSPI Sample - A .NET implementation of a simple client/server using SSPI. A complex undertaking but provides a great resource for playing with the API. * http://msdn.microsoft.com/library/?url=/library/en-us/dndotnet/html/remsspi.asp?frame=true * John Lam's RubyCLR - http://www.rubyclr.com * Originally, I used RubyCLR to call into the Managed SSPI sample which really helped me decode what the SSPI interface did and how it worked. I did not end up using that implementation but it was great for research. * The NTLM Authentication Protocol - The definitive explanation for the NTLM protocol (outside MS internal documents, I presume). * http://davenport.sourceforge.net/ntlm.html * Ruby/NTLM - A pure Ruby implementation of the NTLM protocol. Again, not used in this project but invaluable for decoding NTLM messages and figuring out what SSPI was returning. * http://rubyforge.org/projects/rubyntlm/ * Seamonkey/Mozilla NTLM implementation - The only source for an implementation in an actual browser. How they figured out how to use SSPI themselves is beyond me. * http://lxr.mozilla.org/seamonkey/source/mailnews/base/util/nsMsgProtocol.cpp#899 And of course, thanks to my Lord and Savior, Jesus Christ. In the name of the Father, the Son, and the Holy Spirit. ------=_Part_44474_9294603.1152918451185--