123456789_123456789_123456789_123456789_123456789_

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

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(user = nil, domain = nil) ⇒ NegotiateAuth

Creates a new instance ready for authentication as the given user in the given domain. Defaults to current user and domain as defined by ENV and ENV if no arguments are supplied.

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 237

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)

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 222

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 209

attr_accessor :credentials, :context, :contextAttributes, :user, :domain

#contextAttributes (rw)

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 209

attr_accessor :credentials, :context, :contextAttributes, :user, :domain

#credentials (rw)

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 209

attr_accessor :credentials, :context, :contextAttributes, :user, :domain

#domain (rw)

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 209

attr_accessor :credentials, :context, :contextAttributes, :user, :domain

#user (rw)

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 209

attr_accessor :credentials, :context, :contextAttributes, :user, :domain

Instance Method Details

#clean_up (private)

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 304

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.

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 270

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 324

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

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 315

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.

[ GitHub ]

  
# File 'ext/win32/lib/win32/sspi.rb', line 248

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