Forked from antoniusostermann/net_ntlm_monkeypatch.rb
Created
February 27, 2019 21:33
-
-
Save coliver/5660cf421f96faa2d3906ce4fbee1b97 to your computer and use it in GitHub Desktop.
A monkey patch to solve the problem described in https://github.com/savonrb/httpi/issues/139. This monkey patch prioritizes ntlm over negotiate and makes it possible to use the httpi gem if server supports both / sends header including both arguments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A monkey patch concerning this issue: https://github.com/savonrb/httpi/issues/139 | |
# Basically, this monkey patch priors NTLM over Negotiate and not vice-versa | |
# All monkey patched spots are marked with "## MONKEY PATCHED" | |
# All in all, there are 2 monkey patched spots, both in private method "negotiate_ntlm_auth" | |
# Compare it with: https://github.com/savonrb/httpi/blob/d6a3825a8e896f794e54b634c39521e6956f72ff/lib/httpi/adapter/net_http.rb | |
require "uri" | |
require "httpi/adapter/base" | |
require "httpi/response" | |
require 'kconv' | |
require 'socket' | |
module HTTPI | |
module Adapter | |
class NetHTTP < Base | |
private | |
def negotiate_ntlm_auth(http, &requester) | |
unless Net.const_defined?(:NTLM) | |
raise NotSupportedError, 'Net::NTLM is not available. Install via gem install rubyntlm.' | |
end | |
## MONKEY PATCHED | |
## !! change if statements: prior NTLM over Negotiate | |
## !! it would be much better if we have a config for that (force_ntlm: true) | |
## !! luckily, include? exists on String and on Array, so we do not need to differ if we have an array or a string (unlike below) | |
nego_auth_response = respond_with(requester.call(http, request_client(:head))) | |
if nego_auth_response.headers['www-authenticate'].include? 'NTLM' | |
auth_method = 'NTLM' | |
elsif nego_auth_response.headers['www-authenticate'].include? 'Negotiate' | |
auth_method = 'Negotiate' | |
else | |
auth_method = 'NTLM' | |
HTTPI.logger.debug 'Server does not support NTLM/Negotiate. Trying NTLM anyway' | |
end | |
# initiate a request is to authenticate (exchange secret and auth) using the method determined above... | |
ntlm_message_type1 = Net::NTLM::Message::Type1.new | |
%w(workstation domain).each do |a| | |
ntlm_message_type1.send("#{a}=",'') | |
ntlm_message_type1.enable(a.to_sym) | |
end | |
@request.headers["Authorization"] = "#{auth_method} #{ntlm_message_type1.encode64}" | |
auth_response = respond_with(requester.call(http, request_client(:head))) | |
## MONKEY PATCHED | |
## !! If there are two possible authentication methods given (ntlm AND negotiate), use that one which contains auth_method | |
if auth_response.headers["WWW-Authenticate"].is_a?(Array) | |
fitting_headers = auth_response.headers["WWW-Authenticate"].select{|h| h.downcase.include?(auth_method.downcase)} | |
auth_response.headers["WWW-Authenticate"] = fitting_headers.first | |
end | |
# build an authentication request based on the token provided by the server | |
if auth_response.headers["WWW-Authenticate"] =~ /(NTLM|Negotiate) (.+)/ | |
auth_token = $2 | |
ntlm_message = Net::NTLM::Message.decode64(auth_token) | |
message_builder = {} | |
# copy the username and password from the authorization parameters | |
message_builder[:user] = @request.auth.ntlm[0] | |
message_builder[:password] = @request.auth.ntlm[1] | |
# we need to provide a domain in the packet if an only if it was provided by the user in the auth request | |
if @request.auth.ntlm[2] | |
message_builder[:domain] = @request.auth.ntlm[2].upcase | |
else | |
message_builder[:domain] = '' | |
end | |
ntlm_response = ntlm_message.response(message_builder , | |
{:ntlmv2 => true}) | |
# Finally add header of Authorization | |
@request.headers["Authorization"] = "#{auth_method} #{ntlm_response.encode64}" | |
end | |
nil | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment