class Thin::NTLMWrapper

Constants

AUTHORIZATION_MESSAGE
AUTHORIZATION_MESSAGE_LENGTH
CONTENT_LENGTH
CONTENT_TYPE
CONTENT_TYPE_AUTH
HTTP_AUTHORIZATION
NTLM_ALLOWED_PACKAGE
NTLM_REQUEST_PACKAGE
REMOTE_USER
WWW_AUTHENTICATE

Public Class Methods

new(app, connection) click to toggle source
# File lib/thin/ntlm/connection.rb, line 30
def initialize(app, connection)
  @app = app
  @connection = WeakRef.new(connection)
end

Public Instance Methods

acquire(package = 'NTLM') click to toggle source

Acquires new OS credentials handle

# File lib/thin/ntlm/connection.rb, line 93
def acquire(package = 'NTLM')
  cleanup
  @ntlm = Win32::SSPI::NegotiateServer.new(package)
  @ntlm.acquire_credentials_handle
  @ntlm
end
call(env) click to toggle source
# File lib/thin/ntlm/connection.rb, line 55
def call(env)
  # check if browser wants to reauthenticate
  if @authenticated_as && http_authorization(env)
    @authenticated_as = nil
  end

  # require authentication
  unless @authenticated_as
    ntlm_start
    @authentication_stage ||= 1
    result = process(env)
    return result unless @authenticated_as
    ntlm_stop
  end

  # pass thru
  env[REMOTE_USER] = @authenticated_as
  @app.call(env)
end
can_persist!() click to toggle source
# File lib/thin/ntlm/connection.rb, line 43
def can_persist!
  @connection.can_persist!
end
cleanup() click to toggle source

Frees credentials handle, if acquired

# File lib/thin/ntlm/connection.rb, line 101
def cleanup
  if @ntlm
    @ntlm.cleanup rescue nil
    @ntlm = nil
  end
  nil
end
deferred?(env) click to toggle source
# File lib/thin/ntlm/connection.rb, line 35
def deferred?(env)
  @app.respond_to?(:deferred?) && @app.deferred?(env)
end
http_authorization(env) click to toggle source

Returns stripped HTTP-Authorization header, nil if none or empty

# File lib/thin/ntlm/connection.rb, line 76
def http_authorization(env)
  auth = env[HTTP_AUTHORIZATION]
  if auth
    auth = auth.strip
    auth = nil if auth.empty?
  end
  auth
end
ntlm_start() click to toggle source
# File lib/thin/ntlm/connection.rb, line 47
def ntlm_start
  @connection.ntlm_start
end
ntlm_stop() click to toggle source
# File lib/thin/ntlm/connection.rb, line 51
def ntlm_stop
  @connection.ntlm_stop
end
persistent?() click to toggle source
# File lib/thin/ntlm/connection.rb, line 39
def persistent?
  @connection.request.persistent?
end
process(env) click to toggle source

Processes current authentication stage Returns rack response if authentication is incomplete Sets @authenticated_as to username if authentication successful

# File lib/thin/ntlm/connection.rb, line 112
def process(env)
  case @authentication_stage
  when 1 # we are waiting for type1 message
    package, t1 = token(env)
    return request_auth(NTLM_REQUEST_PACKAGE, false) if t1.nil?
    return request_auth unless persistent?
    begin
      acquire(package)
      t2 = @ntlm.accept_security_context(t1)
    rescue
      return request_auth
    end
    request_auth("#{package} #{t2}", false, 2)
  when 2 # we are waiting for type3 message
    package, t3 = token(env)
    return request_auth(NTLM_REQUEST_PACKAGE, false) if t3.nil?
    return request_auth unless package == @ntlm.package
    return request_auth unless persistent?
    begin
      t2 = @ntlm.accept_security_context(t3)
      @authenticated_as = @ntlm.get_username_from_context
      @authentication_stage = nil # in case IE wants to reauthenticate
    rescue
      return request_auth
    end
    return request_auth unless @authenticated_as
    cleanup
  else
    raise "Invalid value for @authentication_stage=#{@authentication_stage} detected"
  end
end
request_auth(auth = nil, finished = true, next_stage = 1) click to toggle source

Returns response with authentication request to the client

# File lib/thin/ntlm/connection.rb, line 145
def request_auth(auth = nil, finished = true, next_stage = 1)
  @authentication_stage = next_stage
  can_persist! unless finished
  head = {}
  head[WWW_AUTHENTICATE] = auth if auth
  head[CONTENT_TYPE] = CONTENT_TYPE_AUTH
  head[CONTENT_LENGTH] = AUTHORIZATION_MESSAGE_LENGTH
  [401, head, [AUTHORIZATION_MESSAGE]]
end
token(env) click to toggle source

Returns token type and value from HTTP-Authorization header

# File lib/thin/ntlm/connection.rb, line 86
def token(env)
  auth = http_authorization(env)
  return [nil, nil] unless auth && auth.match(/\A(#{NTLM_ALLOWED_PACKAGE}) (.*)\Z/)
  [$1, Base64.decode64($2.strip)]
end