Class: Win32::SSPI::NegotiateAuth
Relationships & Source Files | |
Inherits: | Object |
Defined in: | ext/win32/lib/win32/sspi.rb |
Overview
Handles “Negotiate” type authentication. Geared towards authenticating with a proxy server over HTTP
Constant Summary
-
B64_TOKEN_PREFIX =
NTLM tokens start with this header always. Encoding alone adds “==” and newline, so remove those
["NTLMSSP"].pack("m").delete("=\n")
-
REQUEST_FLAGS =
Default request flags for ::Win32::SSPI functions
ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION
Class Method Summary
-
.new(user = nil, domain = nil) ⇒ NegotiateAuth
constructor
Creates a new instance ready for authentication as the given user in the given domain.
-
.proxy_auth_get(http, path, user = nil, domain = nil)
Given a connection and a request path, performs authentication as the current user and returns the response from a GET request.
Instance Attribute Summary
- #context rw
- #contextAttributes rw
- #credentials rw
- #domain rw
- #user rw
Instance Method Summary
-
#complete_authentication(token)
Takes a token and gets the next token in the Negotiate authentication chain.
-
#get_initial_token
Gets the initial Negotiate token.
- #clean_up private
- #encode_token(t) private
-
#get_credentials
private
Gets credentials based on user, domain or both.
Constructor Details
.new(user = nil, domain = nil) ⇒ NegotiateAuth
# File 'ext/win32/lib/win32/sspi.rb', line 238
def initialize(user = nil, domain = nil) if user.nil? && domain.nil? && ENV["USERNAME"].nil? && ENV["USERDOMAIN"].nil? raise "A username or domain must be supplied since they cannot be retrieved from the environment" end @user = user || ENV["USERNAME"] @domain = domain || ENV["USERDOMAIN"] end
Class Method Details
.proxy_auth_get(http, path, user = nil, domain = nil)
Given a connection and a request path, performs authentication as the current user and returns the response from a GET request. The connnection should be a Net::HTTP
object, and it should have been constructed using the Net::HTTP.Proxy
method, but anything that responds to “get” will work. If a user and domain are given, will authenticate as the given user. Returns the response received from the get method (usually Net::HTTPResponse
)
# File 'ext/win32/lib/win32/sspi.rb', line 223
def NegotiateAuth.proxy_auth_get(http, path, user = nil, domain = nil) raise "http must respond to :get" unless http.respond_to?(:get) nego_auth = self.new user, domain resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token } if resp["Proxy-Authenticate"] resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(resp["Proxy-Authenticate"].split(" ").last.strip) } end resp end
Instance Attribute Details
#context (rw)
[ GitHub ]# File 'ext/win32/lib/win32/sspi.rb', line 210
attr_accessor :credentials, :context, :contextAttributes, :user, :domain
#contextAttributes (rw)
[ GitHub ]# File 'ext/win32/lib/win32/sspi.rb', line 210
attr_accessor :credentials, :context, :contextAttributes, :user, :domain
#credentials (rw)
[ GitHub ]# File 'ext/win32/lib/win32/sspi.rb', line 210
attr_accessor :credentials, :context, :contextAttributes, :user, :domain
#domain (rw)
[ GitHub ]# File 'ext/win32/lib/win32/sspi.rb', line 210
attr_accessor :credentials, :context, :contextAttributes, :user, :domain
#user (rw)
[ GitHub ]# File 'ext/win32/lib/win32/sspi.rb', line 210
attr_accessor :credentials, :context, :contextAttributes, :user, :domain
Instance Method Details
#clean_up (private)
[ GitHub ]# File 'ext/win32/lib/win32/sspi.rb', line 305
def clean_up # free structures allocated @cleaned_up = true API::FreeCredentialsHandle.call(@credentials.to_p) API::DeleteSecurityContext.call(@context.to_p) @context = nil @credentials = nil @contextAttributes = nil end
#complete_authentication(token)
Takes a token and gets the next token in the Negotiate authentication chain. Token can be Base64 encoded or not. The token can include the “Negotiate” header and it will be stripped. Does not indicate if SEC_I_CONTINUE or SEC_E_OK was returned. Token returned is Base64 encoded w/ all new lines removed.
# File 'ext/win32/lib/win32/sspi.rb', line 271
def complete_authentication(token) raise "This object is no longer usable because its resources have been freed." if @cleaned_up # Nil token OK, just set it to empty string token = "" if token.nil? if token.include? "Negotiate" # If the Negotiate prefix is passed in, assume we are seeing "Negotiate <token>" and get the token. token = token.split(" ").last end if token.include? B64_TOKEN_PREFIX # indicates base64 encoded token token = token.strip.unpack("m")[0] end outputBuffer = SecurityBuffer.new result = SSPIResult.new(API::InitializeSecurityContext.call(@credentials.to_p, @context.to_p, nil, REQUEST_FLAGS, 0, SECURITY_NETWORK_DREP, SecurityBuffer.new(token).to_p, 0, @context.to_p, outputBuffer.to_p, @contextAttributes, TimeStamp.new.to_p)) if result.ok? then return encode_token(outputBuffer.token) else raise "Error: #{result.to_s}" end ensure # need to make sure we don't clean up if we've already cleaned up. clean_up unless @cleaned_up end
#encode_token(t) (private)
[ GitHub ]# File 'ext/win32/lib/win32/sspi.rb', line 325
def encode_token(t) # encode64 will add newlines every 60 characters so we need to remove those. [t].pack("m").delete("\n") end
#get_credentials (private)
Gets credentials based on user, domain or both. If both are nil, an error occurs
# File 'ext/win32/lib/win32/sspi.rb', line 316
def get_credentials @credentials = CredHandle.new ts = TimeStamp.new @identity = Identity.new @user, @domain result = SSPIResult.new(API::AcquireCredentialsHandle.call(nil, "Negotiate", SECPKG_CRED_OUTBOUND, nil, @identity.to_p, nil, nil, @credentials.to_p, ts.to_p)) raise "Error acquire credentials: #{result}" unless result.ok? end
#get_initial_token
Gets the initial Negotiate token. Returns it as a base64 encoded string suitable for use in HTTP. Can be easily decoded, however.
# File 'ext/win32/lib/win32/sspi.rb', line 249
def get_initial_token raise "This object is no longer usable because its resources have been freed." if @cleaned_up get_credentials outputBuffer = SecurityBuffer.new @context = CtxtHandle.new @contextAttributes = "\0" * 4 result = SSPIResult.new(API::InitializeSecurityContext.call(@credentials.to_p, nil, nil, REQUEST_FLAGS,0, SECURITY_NETWORK_DREP, nil, 0, @context.to_p, outputBuffer.to_p, @contextAttributes, TimeStamp.new.to_p)) if result.ok? then return encode_token(outputBuffer.token) else raise "Error: #{result.to_s}" end end