类 Win32::SSPI::NegotiateAuth

处理“Negotiate”类型身份验证。 旨在通过 HTTP 与代理服务器进行身份验证

常量

B64_TOKEN_PREFIX

NTLM 令牌始终以此标头开头。 Encoding 仅添加“==”和换行符,因此请删除它们

REQUEST_FLAGS

用于 SSPI 函数的默认请求标志

属性

context[RW]
contextAttributes[RW]
credentials[RW]
domain[RW]
user[RW]

公共类方法

new(user = nil, domain = nil) 点击切换源代码

创建一个新的实例,准备以给定域中的给定用户身份进行身份验证。 如果没有提供参数,则默认为当前用户和域,如 ENVENV 所定义。

# File ext/win32/lib/win32/sspi.rb, line 245
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
proxy_auth_get(http, path, user = nil, domain = nil) 点击切换源代码

给定连接和请求路径,以当前用户身份执行身份验证,并返回来自 GET 请求的响应。 连接应为 Net::HTTP 对象,并且应使用 Net::HTTP.Proxy 方法构建,但任何响应“get”的方法都将起作用。 如果提供用户和域,则将以给定用户身份进行身份验证。 返回从 get 方法接收到的响应(通常为 Net::HTTPResponse

# File ext/win32/lib/win32/sspi.rb, line 230
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

公共实例方法

complete_authentication(token) 点击切换源代码

接收一个令牌,获取 Negotiate 身份验证链中的下一个令牌。令牌可以是 Base64 编码或未编码。令牌可以包含“Negotiate”头,它将被剥离。不指示是否返回了 SEC_I_CONTINUE 或 SEC_E_OK。返回的令牌是 Base64 编码的,所有换行符都已删除。

# File ext/win32/lib/win32/sspi.rb, line 278
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
get_initial_token() 点击以切换源代码

获取初始 Negotiate 令牌。将其作为适合在 HTTP 中使用的 base64 编码字符串返回。但是,可以轻松解码。

# File ext/win32/lib/win32/sspi.rb, line 256
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::InitializeSecurityContextA.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

私有实例方法

clean_up() 点击以切换源代码
# File ext/win32/lib/win32/sspi.rb, line 312
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
encode_token(t) 点击以切换源代码
# File ext/win32/lib/win32/sspi.rb, line 332
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() 点击以切换源代码

根据用户、域或两者获取凭据。如果两者都为空,则会发生错误。

# File ext/win32/lib/win32/sspi.rb, line 323
def get_credentials
  @credentials = CredHandle.new
  ts = TimeStamp.new
  @identity = Identity.new @user, @domain
  result = SSPIResult.new(API::AcquireCredentialsHandleA.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