Ruby

All posts tagged Ruby

I’ve been trying to use Ruby libraries to access Sharepoint and am having trouble getting to the starting line.  NTLM authentication from Ruby doesn’t seem to be in a good state.  I’m using httpi-0.9.6 as my HTTP library, which by default uses httpclient-2.2.4, and for NTLM support I’m using httpi-ntlm-0.9.6.  All this is running under Ruby 1.8.7 which incorporates Net::NTLM 0.1.1 which http-ntlm relies on.

In my enterprise environment, I need to use NTLM authentication to access the Sharepoint server.  So, I format the username string supplied to httpi as “USERDOMAIN\username”.  It happens that the Sharepoint machine I want to access is in a different NTLM domain than the user account that I want to access it with.  When httpclient does the NTLM authentication phase, it uses facilities from Net::NTLM to format a Type 1 Message.  This is where the problems start.  Firstly, httpclient doesn’t do the right (undocumented) things necessary to get Net::NTLM to properly include the user’s domain into the request.

case state
  when :init
    t1 = Net::NTLM::Message::Type1.new
    t1.domain = domain if domain
    return t1.encode64
end

The trouble here is that this code doesn’t properly tell Net::NTLM that this domain information should be incorporated into the request.  As written, HTTPI generates a corrupt request, as can be seen from a Wireshark trace.  It’s additionally necessary to enable the resulting SecurityBuffer and to set a flag in the request indicating that the domain is being signalled:

case state
  when :init
    t1 = Net::NTLM::Message::Type1.new
    if domain
      t1.domain = domain
      t1.enable(:domain)
      t1.set_flag(:DOMAIN_SUPPLIED)
    end
    return t1.encode64

But when you do this, you find that the packet is still corrupt, because the offset to the domain name data in the resulting request is incorrect.  This is because of what appears to be a bug in Net::NTLM.  That’s not so easy to fix and play about with, because it’s incorporated into Ruby itself.  The problem is that the offsets are calculated by adding the sizes of the SecurityBuffers defined for the message type, regardless of whether a particular SecurityBuffer is active or not. For my testing purposes, I forced the additional “workstation” SecurityBuffer to be active (with an arbitrary non-null value) in the same way as the Domain, and by doing so, was able to generate a valid request.

But imagine my horror when my requests were still denied by the server.  Further investigation revealed that Net::NTLM ignores the user-specified domain when generating the subsequent Type 3 Message, substituting instead the Target value returned in the Challenge of the Type 2 Message.

Further hackery will be required to fix that, but another approach might be to use Curb instead of httpclient.