* ext/Win32API/lib/win32/sspi.rb: set properties.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12115 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
25ac9f24fd
commit
e6e5674156
638
ext/Win32API/lib/win32/sspi.rb
Executable file → Normal file
638
ext/Win32API/lib/win32/sspi.rb
Executable file → Normal file
@ -9,323 +9,323 @@
|
|||||||
# modify this program under the same terms of ruby itself ---
|
# modify this program under the same terms of ruby itself ---
|
||||||
# Ruby Distribution License or GNU General Public License.
|
# Ruby Distribution License or GNU General Public License.
|
||||||
#
|
#
|
||||||
|
|
||||||
require 'Win32API'
|
require 'Win32API'
|
||||||
require 'base64'
|
require 'base64'
|
||||||
|
|
||||||
# Implements bindings to Win32 SSPI functions, focused on authentication to a proxy server over HTTP.
|
# Implements bindings to Win32 SSPI functions, focused on authentication to a proxy server over HTTP.
|
||||||
module Win32
|
module Win32
|
||||||
module SSPI
|
module SSPI
|
||||||
# Specifies how credential structure requested will be used. Only SECPKG_CRED_OUTBOUND is used
|
# Specifies how credential structure requested will be used. Only SECPKG_CRED_OUTBOUND is used
|
||||||
# here.
|
# here.
|
||||||
SECPKG_CRED_INBOUND = 0x00000001
|
SECPKG_CRED_INBOUND = 0x00000001
|
||||||
SECPKG_CRED_OUTBOUND = 0x00000002
|
SECPKG_CRED_OUTBOUND = 0x00000002
|
||||||
SECPKG_CRED_BOTH = 0x00000003
|
SECPKG_CRED_BOTH = 0x00000003
|
||||||
|
|
||||||
# Format of token. NETWORK format is used here.
|
# Format of token. NETWORK format is used here.
|
||||||
SECURITY_NATIVE_DREP = 0x00000010
|
SECURITY_NATIVE_DREP = 0x00000010
|
||||||
SECURITY_NETWORK_DREP = 0x00000000
|
SECURITY_NETWORK_DREP = 0x00000000
|
||||||
|
|
||||||
# InitializeSecurityContext Requirement flags
|
# InitializeSecurityContext Requirement flags
|
||||||
ISC_REQ_REPLAY_DETECT = 0x00000004
|
ISC_REQ_REPLAY_DETECT = 0x00000004
|
||||||
ISC_REQ_SEQUENCE_DETECT = 0x00000008
|
ISC_REQ_SEQUENCE_DETECT = 0x00000008
|
||||||
ISC_REQ_CONFIDENTIALITY = 0x00000010
|
ISC_REQ_CONFIDENTIALITY = 0x00000010
|
||||||
ISC_REQ_USE_SESSION_KEY = 0x00000020
|
ISC_REQ_USE_SESSION_KEY = 0x00000020
|
||||||
ISC_REQ_PROMPT_FOR_CREDS = 0x00000040
|
ISC_REQ_PROMPT_FOR_CREDS = 0x00000040
|
||||||
ISC_REQ_CONNECTION = 0x00000800
|
ISC_REQ_CONNECTION = 0x00000800
|
||||||
|
|
||||||
# Win32 API Functions. Uses Win32API to bind methods to constants contained in class.
|
# Win32 API Functions. Uses Win32API to bind methods to constants contained in class.
|
||||||
module API
|
module API
|
||||||
# Can be called with AcquireCredentialsHandle.call()
|
# Can be called with AcquireCredentialsHandle.call()
|
||||||
AcquireCredentialsHandle = Win32API.new("secur32", "AcquireCredentialsHandle", 'ppLpppppp', 'L')
|
AcquireCredentialsHandle = Win32API.new("secur32", "AcquireCredentialsHandle", 'ppLpppppp', 'L')
|
||||||
# Can be called with InitializeSecurityContext.call()
|
# Can be called with InitializeSecurityContext.call()
|
||||||
InitializeSecurityContext = Win32API.new("secur32", "InitializeSecurityContext", 'pppLLLpLpppp', 'L')
|
InitializeSecurityContext = Win32API.new("secur32", "InitializeSecurityContext", 'pppLLLpLpppp', 'L')
|
||||||
# Can be called with DeleteSecurityContext.call()
|
# Can be called with DeleteSecurityContext.call()
|
||||||
DeleteSecurityContext = Win32API.new("secur32", "DeleteSecurityContext", 'P', 'L')
|
DeleteSecurityContext = Win32API.new("secur32", "DeleteSecurityContext", 'P', 'L')
|
||||||
# Can be called with FreeCredentialsHandle.call()
|
# Can be called with FreeCredentialsHandle.call()
|
||||||
FreeCredentialsHandle = Win32API.new("secur32", "FreeCredentialsHandle", 'P', 'L')
|
FreeCredentialsHandle = Win32API.new("secur32", "FreeCredentialsHandle", 'P', 'L')
|
||||||
end
|
end
|
||||||
|
|
||||||
# SecHandle struct
|
# SecHandle struct
|
||||||
class SecurityHandle
|
class SecurityHandle
|
||||||
def upper
|
def upper
|
||||||
@struct.unpack("LL")[1]
|
@struct.unpack("LL")[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
def lower
|
def lower
|
||||||
@struct.unpack("LL")[0]
|
@struct.unpack("LL")[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_p
|
def to_p
|
||||||
@struct ||= "\0" * 8
|
@struct ||= "\0" * 8
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Some familiar aliases for the SecHandle structure
|
# Some familiar aliases for the SecHandle structure
|
||||||
CredHandle = CtxtHandle = SecurityHandle
|
CredHandle = CtxtHandle = SecurityHandle
|
||||||
|
|
||||||
# TimeStamp struct
|
# TimeStamp struct
|
||||||
class TimeStamp
|
class TimeStamp
|
||||||
attr_reader :struct
|
attr_reader :struct
|
||||||
|
|
||||||
def to_p
|
def to_p
|
||||||
@struct ||= "\0" * 8
|
@struct ||= "\0" * 8
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates binary representaiton of a SecBufferDesc structure,
|
# Creates binary representaiton of a SecBufferDesc structure,
|
||||||
# including the SecBuffer contained inside.
|
# including the SecBuffer contained inside.
|
||||||
class SecurityBuffer
|
class SecurityBuffer
|
||||||
|
|
||||||
SECBUFFER_TOKEN = 2 # Security token
|
SECBUFFER_TOKEN = 2 # Security token
|
||||||
|
|
||||||
TOKENBUFSIZE = 12288
|
TOKENBUFSIZE = 12288
|
||||||
SECBUFFER_VERSION = 0
|
SECBUFFER_VERSION = 0
|
||||||
|
|
||||||
def initialize(buffer = nil)
|
def initialize(buffer = nil)
|
||||||
@buffer = buffer || "\0" * TOKENBUFSIZE
|
@buffer = buffer || "\0" * TOKENBUFSIZE
|
||||||
@bufferSize = @buffer.length
|
@bufferSize = @buffer.length
|
||||||
@type = SECBUFFER_TOKEN
|
@type = SECBUFFER_TOKEN
|
||||||
end
|
end
|
||||||
|
|
||||||
def bufferSize
|
def bufferSize
|
||||||
unpack
|
unpack
|
||||||
@bufferSize
|
@bufferSize
|
||||||
end
|
end
|
||||||
|
|
||||||
def bufferType
|
def bufferType
|
||||||
unpack
|
unpack
|
||||||
@type
|
@type
|
||||||
end
|
end
|
||||||
|
|
||||||
def token
|
def token
|
||||||
unpack
|
unpack
|
||||||
@buffer
|
@buffer
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_p
|
def to_p
|
||||||
# Assumption is that when to_p is called we are going to get a packed structure. Therefore,
|
# Assumption is that when to_p is called we are going to get a packed structure. Therefore,
|
||||||
# set @unpacked back to nil so we know to unpack when accessors are next accessed.
|
# set @unpacked back to nil so we know to unpack when accessors are next accessed.
|
||||||
@unpacked = nil
|
@unpacked = nil
|
||||||
# Assignment of inner structure to variable is very important here. Without it,
|
# Assignment of inner structure to variable is very important here. Without it,
|
||||||
# will not be able to unpack changes to the structure. Alternative, nested unpacks,
|
# will not be able to unpack changes to the structure. Alternative, nested unpacks,
|
||||||
# does not work (i.e. @struct.unpack("LLP12")[2].unpack("LLP12") results in "no associated pointer")
|
# does not work (i.e. @struct.unpack("LLP12")[2].unpack("LLP12") results in "no associated pointer")
|
||||||
@sec_buffer ||= [@bufferSize, @type, @buffer].pack("LLP")
|
@sec_buffer ||= [@bufferSize, @type, @buffer].pack("LLP")
|
||||||
@struct ||= [SECBUFFER_VERSION, 1, @sec_buffer].pack("LLP")
|
@struct ||= [SECBUFFER_VERSION, 1, @sec_buffer].pack("LLP")
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Unpacks the SecurityBufferDesc structure into member variables. We
|
# Unpacks the SecurityBufferDesc structure into member variables. We
|
||||||
# only want to do this once per struct, so the struct is deleted
|
# only want to do this once per struct, so the struct is deleted
|
||||||
# after unpacking.
|
# after unpacking.
|
||||||
def unpack
|
def unpack
|
||||||
if ! @unpacked && @sec_buffer && @struct
|
if ! @unpacked && @sec_buffer && @struct
|
||||||
@bufferSize, @type = @sec_buffer.unpack("LL")
|
@bufferSize, @type = @sec_buffer.unpack("LL")
|
||||||
@buffer = @sec_buffer.unpack("LLP#{@bufferSize}")[2]
|
@buffer = @sec_buffer.unpack("LLP#{@bufferSize}")[2]
|
||||||
@struct = nil
|
@struct = nil
|
||||||
@sec_buffer = nil
|
@sec_buffer = nil
|
||||||
@unpacked = true
|
@unpacked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# SEC_WINNT_AUTH_IDENTITY structure
|
# SEC_WINNT_AUTH_IDENTITY structure
|
||||||
class Identity
|
class Identity
|
||||||
SEC_WINNT_AUTH_IDENTITY_ANSI = 0x1
|
SEC_WINNT_AUTH_IDENTITY_ANSI = 0x1
|
||||||
|
|
||||||
attr_accessor :user, :domain, :password
|
attr_accessor :user, :domain, :password
|
||||||
|
|
||||||
def initialize(user = nil, domain = nil, password = nil)
|
def initialize(user = nil, domain = nil, password = nil)
|
||||||
@user = user
|
@user = user
|
||||||
@domain = domain
|
@domain = domain
|
||||||
@password = password
|
@password = password
|
||||||
@flags = SEC_WINNT_AUTH_IDENTITY_ANSI
|
@flags = SEC_WINNT_AUTH_IDENTITY_ANSI
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_p
|
def to_p
|
||||||
[@user, @user ? @user.length : 0,
|
[@user, @user ? @user.length : 0,
|
||||||
@domain, @domain ? @domain.length : 0,
|
@domain, @domain ? @domain.length : 0,
|
||||||
@password, @password ? @password.length : 0,
|
@password, @password ? @password.length : 0,
|
||||||
@flags].pack("PLPLPLL")
|
@flags].pack("PLPLPLL")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Takes a return result from an SSPI function and interprets the value.
|
# Takes a return result from an SSPI function and interprets the value.
|
||||||
class SSPIResult
|
class SSPIResult
|
||||||
# Good results
|
# Good results
|
||||||
SEC_E_OK = 0x00000000
|
SEC_E_OK = 0x00000000
|
||||||
SEC_I_CONTINUE_NEEDED = 0x00090312
|
SEC_I_CONTINUE_NEEDED = 0x00090312
|
||||||
|
|
||||||
# These are generally returned by InitializeSecurityContext
|
# These are generally returned by InitializeSecurityContext
|
||||||
SEC_E_INSUFFICIENT_MEMORY = 0x80090300
|
SEC_E_INSUFFICIENT_MEMORY = 0x80090300
|
||||||
SEC_E_INTERNAL_ERROR = 0x80090304
|
SEC_E_INTERNAL_ERROR = 0x80090304
|
||||||
SEC_E_INVALID_HANDLE = 0x80090301
|
SEC_E_INVALID_HANDLE = 0x80090301
|
||||||
SEC_E_INVALID_TOKEN = 0x80090308
|
SEC_E_INVALID_TOKEN = 0x80090308
|
||||||
SEC_E_LOGON_DENIED = 0x8009030C
|
SEC_E_LOGON_DENIED = 0x8009030C
|
||||||
SEC_E_NO_AUTHENTICATING_AUTHORITY = 0x80090311
|
SEC_E_NO_AUTHENTICATING_AUTHORITY = 0x80090311
|
||||||
SEC_E_NO_CREDENTIALS = 0x8009030E
|
SEC_E_NO_CREDENTIALS = 0x8009030E
|
||||||
SEC_E_TARGET_UNKNOWN = 0x80090303
|
SEC_E_TARGET_UNKNOWN = 0x80090303
|
||||||
SEC_E_UNSUPPORTED_FUNCTION = 0x80090302
|
SEC_E_UNSUPPORTED_FUNCTION = 0x80090302
|
||||||
SEC_E_WRONG_PRINCIPAL = 0x80090322
|
SEC_E_WRONG_PRINCIPAL = 0x80090322
|
||||||
|
|
||||||
# These are generally returned by AcquireCredentialsHandle
|
# These are generally returned by AcquireCredentialsHandle
|
||||||
SEC_E_NOT_OWNER = 0x80090306
|
SEC_E_NOT_OWNER = 0x80090306
|
||||||
SEC_E_SECPKG_NOT_FOUND = 0x80090305
|
SEC_E_SECPKG_NOT_FOUND = 0x80090305
|
||||||
SEC_E_UNKNOWN_CREDENTIALS = 0x8009030D
|
SEC_E_UNKNOWN_CREDENTIALS = 0x8009030D
|
||||||
|
|
||||||
@@map = {}
|
@@map = {}
|
||||||
constants.each { |v| @@map[self.const_get(v.to_s)] = v }
|
constants.each { |v| @@map[self.const_get(v.to_s)] = v }
|
||||||
|
|
||||||
attr_reader :value
|
attr_reader :value
|
||||||
|
|
||||||
def initialize(value)
|
def initialize(value)
|
||||||
# convert to unsigned long
|
# convert to unsigned long
|
||||||
value = [value].pack("L").unpack("L").first
|
value = [value].pack("L").unpack("L").first
|
||||||
raise "#{value.to_s(16)} is not a recognized result" unless @@map.has_key? value
|
raise "#{value.to_s(16)} is not a recognized result" unless @@map.has_key? value
|
||||||
@value = value
|
@value = value
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
@@map[@value].to_s
|
@@map[@value].to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def ok?
|
def ok?
|
||||||
@value == SEC_I_CONTINUE_NEEDED || @value == SEC_E_OK
|
@value == SEC_I_CONTINUE_NEEDED || @value == SEC_E_OK
|
||||||
end
|
end
|
||||||
|
|
||||||
def ==(other)
|
def ==(other)
|
||||||
if other.is_a?(SSPIResult)
|
if other.is_a?(SSPIResult)
|
||||||
@value == other.value
|
@value == other.value
|
||||||
elsif other.is_a?(Fixnum)
|
elsif other.is_a?(Fixnum)
|
||||||
@value == @@map[other]
|
@value == @@map[other]
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Handles "Negotiate" type authentication. Geared towards authenticating with a proxy server over HTTP
|
# Handles "Negotiate" type authentication. Geared towards authenticating with a proxy server over HTTP
|
||||||
class NegotiateAuth
|
class NegotiateAuth
|
||||||
attr_accessor :credentials, :context, :contextAttributes, :user, :domain
|
attr_accessor :credentials, :context, :contextAttributes, :user, :domain
|
||||||
|
|
||||||
# Default request flags for SSPI functions
|
# Default request flags for SSPI functions
|
||||||
REQUEST_FLAGS = ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION
|
REQUEST_FLAGS = ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION
|
||||||
|
|
||||||
# NTLM tokens start with this header always. Encoding alone adds "==" and newline, so remove those
|
# NTLM tokens start with this header always. Encoding alone adds "==" and newline, so remove those
|
||||||
B64_TOKEN_PREFIX = Base64.encode64("NTLMSSP").delete("=\n")
|
B64_TOKEN_PREFIX = Base64.encode64("NTLMSSP").delete("=\n")
|
||||||
|
|
||||||
# Given a connection and a request path, performs authentication as the current user and returns
|
# 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
|
# 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.
|
# 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.
|
# If a user and domain are given, will authenticate as the given user.
|
||||||
# Returns the response received from the get method (usually Net::HTTPResponse)
|
# Returns the response received from the get method (usually Net::HTTPResponse)
|
||||||
def NegotiateAuth.proxy_auth_get(http, path, user = nil, domain = nil)
|
def NegotiateAuth.proxy_auth_get(http, path, user = nil, domain = nil)
|
||||||
raise "http must respond to :get" unless http.respond_to?(:get)
|
raise "http must respond to :get" unless http.respond_to?(:get)
|
||||||
nego_auth = self.new user, domain
|
nego_auth = self.new user, domain
|
||||||
|
|
||||||
resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token }
|
resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token }
|
||||||
if resp["Proxy-Authenticate"]
|
if resp["Proxy-Authenticate"]
|
||||||
resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(resp["Proxy-Authenticate"].split(" ").last.strip) }
|
resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(resp["Proxy-Authenticate"].split(" ").last.strip) }
|
||||||
end
|
end
|
||||||
|
|
||||||
resp
|
resp
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a new instance ready for authentication as the given user in the given domain.
|
# 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["USERDOMAIN"] and ENV["USERNAME"] if
|
# Defaults to current user and domain as defined by ENV["USERDOMAIN"] and ENV["USERNAME"] if
|
||||||
# no arguments are supplied.
|
# no arguments are supplied.
|
||||||
def initialize(user = nil, domain = nil)
|
def initialize(user = nil, domain = nil)
|
||||||
if user.nil? && domain.nil? && ENV["USERNAME"].nil? && ENV["USERDOMAIN"].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"
|
raise "A username or domain must be supplied since they cannot be retrieved from the environment"
|
||||||
end
|
end
|
||||||
|
|
||||||
@user = user || ENV["USERNAME"]
|
@user = user || ENV["USERNAME"]
|
||||||
@domain = domain || ENV["USERDOMAIN"]
|
@domain = domain || ENV["USERDOMAIN"]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets the initial Negotiate token. Returns it as a base64 encoded string suitable for use in HTTP. Can
|
# Gets the initial Negotiate token. Returns it as a base64 encoded string suitable for use in HTTP. Can
|
||||||
# be easily decoded, however.
|
# be easily decoded, however.
|
||||||
def get_initial_token
|
def get_initial_token
|
||||||
raise "This object is no longer usable because its resources have been freed." if @cleaned_up
|
raise "This object is no longer usable because its resources have been freed." if @cleaned_up
|
||||||
get_credentials
|
get_credentials
|
||||||
|
|
||||||
outputBuffer = SecurityBuffer.new
|
outputBuffer = SecurityBuffer.new
|
||||||
@context = CtxtHandle.new
|
@context = CtxtHandle.new
|
||||||
@contextAttributes = "\0" * 4
|
@contextAttributes = "\0" * 4
|
||||||
|
|
||||||
result = SSPIResult.new(API::InitializeSecurityContext.call(@credentials.to_p, nil, nil,
|
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))
|
REQUEST_FLAGS,0, SECURITY_NETWORK_DREP, nil, 0, @context.to_p, outputBuffer.to_p, @contextAttributes, TimeStamp.new.to_p))
|
||||||
|
|
||||||
if result.ok? then
|
if result.ok? then
|
||||||
return encode_token(outputBuffer.token)
|
return encode_token(outputBuffer.token)
|
||||||
else
|
else
|
||||||
raise "Error: #{result.to_s}"
|
raise "Error: #{result.to_s}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Takes a token and gets the next token in the Negotiate authentication chain. Token can be Base64 encoded or not.
|
# 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.
|
# 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.
|
# Does not indicate if SEC_I_CONTINUE or SEC_E_OK was returned.
|
||||||
# Token returned is Base64 encoded w/ all new lines removed.
|
# Token returned is Base64 encoded w/ all new lines removed.
|
||||||
def complete_authentication(token)
|
def complete_authentication(token)
|
||||||
raise "This object is no longer usable because its resources have been freed." if @cleaned_up
|
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
|
# Nil token OK, just set it to empty string
|
||||||
token = "" if token.nil?
|
token = "" if token.nil?
|
||||||
|
|
||||||
if token.include? "Negotiate"
|
if token.include? "Negotiate"
|
||||||
# If the Negotiate prefix is passed in, assume we are seeing "Negotiate <token>" and get the token.
|
# If the Negotiate prefix is passed in, assume we are seeing "Negotiate <token>" and get the token.
|
||||||
token = token.split(" ").last
|
token = token.split(" ").last
|
||||||
end
|
end
|
||||||
|
|
||||||
if token.include? B64_TOKEN_PREFIX
|
if token.include? B64_TOKEN_PREFIX
|
||||||
# indicates base64 encoded token
|
# indicates base64 encoded token
|
||||||
token = Base64.decode64(token.strip)
|
token = Base64.decode64(token.strip)
|
||||||
end
|
end
|
||||||
|
|
||||||
outputBuffer = SecurityBuffer.new
|
outputBuffer = SecurityBuffer.new
|
||||||
result = SSPIResult.new(API::InitializeSecurityContext.call(@credentials.to_p, @context.to_p, nil,
|
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,
|
REQUEST_FLAGS, 0, SECURITY_NETWORK_DREP, SecurityBuffer.new(token).to_p, 0,
|
||||||
@context.to_p,
|
@context.to_p,
|
||||||
outputBuffer.to_p, @contextAttributes, TimeStamp.new.to_p))
|
outputBuffer.to_p, @contextAttributes, TimeStamp.new.to_p))
|
||||||
|
|
||||||
if result.ok? then
|
if result.ok? then
|
||||||
return encode_token(outputBuffer.token)
|
return encode_token(outputBuffer.token)
|
||||||
else
|
else
|
||||||
raise "Error: #{result.to_s}"
|
raise "Error: #{result.to_s}"
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
# need to make sure we don't clean up if we've already cleaned up.
|
# need to make sure we don't clean up if we've already cleaned up.
|
||||||
clean_up unless @cleaned_up
|
clean_up unless @cleaned_up
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def clean_up
|
def clean_up
|
||||||
# free structures allocated
|
# free structures allocated
|
||||||
@cleaned_up = true
|
@cleaned_up = true
|
||||||
API::FreeCredentialsHandle.call(@credentials.to_p)
|
API::FreeCredentialsHandle.call(@credentials.to_p)
|
||||||
API::DeleteSecurityContext.call(@context.to_p)
|
API::DeleteSecurityContext.call(@context.to_p)
|
||||||
@context = nil
|
@context = nil
|
||||||
@credentials = nil
|
@credentials = nil
|
||||||
@contextAttributes = nil
|
@contextAttributes = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets credentials based on user, domain or both. If both are nil, an error occurs
|
# Gets credentials based on user, domain or both. If both are nil, an error occurs
|
||||||
def get_credentials
|
def get_credentials
|
||||||
@credentials = CredHandle.new
|
@credentials = CredHandle.new
|
||||||
ts = TimeStamp.new
|
ts = TimeStamp.new
|
||||||
@identity = Identity.new @user, @domain
|
@identity = Identity.new @user, @domain
|
||||||
result = SSPIResult.new(API::AcquireCredentialsHandle.call(nil, "Negotiate", SECPKG_CRED_OUTBOUND, nil, @identity.to_p,
|
result = SSPIResult.new(API::AcquireCredentialsHandle.call(nil, "Negotiate", SECPKG_CRED_OUTBOUND, nil, @identity.to_p,
|
||||||
nil, nil, @credentials.to_p, ts.to_p))
|
nil, nil, @credentials.to_p, ts.to_p))
|
||||||
raise "Error acquire credentials: #{result}" unless result.ok?
|
raise "Error acquire credentials: #{result}" unless result.ok?
|
||||||
end
|
end
|
||||||
|
|
||||||
def encode_token(t)
|
def encode_token(t)
|
||||||
# encode64 will add newlines every 60 characters so we need to remove those.
|
# encode64 will add newlines every 60 characters so we need to remove those.
|
||||||
Base64.encode64(t).delete("\n")
|
Base64.encode64(t).delete("\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
Loading…
x
Reference in New Issue
Block a user