lib/omniauth/strategies/ldap/adaptor.rb in oa-enterprise-0.1.6 vs lib/omniauth/strategies/ldap/adaptor.rb in oa-enterprise-0.2.0.beta1
- old
+ new
@@ -1,247 +1,268 @@
#this code boughts pieces from activeldap and net-ldap
+
require 'rack'
require 'net/ldap'
require 'net/ntlm'
require 'uri'
+
module OmniAuth
module Strategies
class LDAP
class Adaptor
- class LdapError < StandardError; end
- class ConfigurationError < StandardError; end
- class AuthenticationError < StandardError; end
- class ConnectionError < StandardError; end
- VALID_ADAPTER_CONFIGURATION_KEYS = [:host, :port, :method, :bind_dn, :password,
- :try_sasl, :sasl_mechanisms, :uid, :base]
- MUST_HAVE_KEYS = [:host, :port, :method, :uid, :base]
- METHOD = {
- :ssl => :simple_tls,
- :tls => :start_tls,
- :plain => nil
- }
- attr_accessor :bind_dn, :password
- attr_reader :connection, :uid, :base
- def initialize(configuration={})
- @connection = nil
- @disconnected = false
- @bound = false
- @configuration = configuration.dup
- @logger = @configuration.delete(:logger)
- message = []
- MUST_HAVE_KEYS.each do |name|
- message << name if configuration[name].nil?
- end
- raise ArgumentError.new(message.join(",") +" MUST be provided") unless message.empty?
- VALID_ADAPTER_CONFIGURATION_KEYS.each do |name|
- instance_variable_set("@#{name}", configuration[name])
- end
- end
+ class LdapError < StandardError; end
+ class ConfigurationError < StandardError; end
+ class AuthenticationError < StandardError; end
+ class ConnectionError < StandardError; end
+
+ VALID_ADAPTER_CONFIGURATION_KEYS = [:host, :port, :method, :bind_dn, :password,
+ :try_sasl, :sasl_mechanisms, :uid, :base]
+
+ MUST_HAVE_KEYS = [:host, :port, :method, :uid, :base]
+
+ METHOD = {
+ :ssl => :simple_tls,
+ :tls => :start_tls,
+ :plain => nil
+ }
+
+ attr_accessor :bind_dn, :password
+ attr_reader :connection, :uid, :base
+
+ def initialize(configuration={})
+ @connection = nil
+ @disconnected = false
+ @bound = false
+ @configuration = configuration.dup
+ @logger = @configuration.delete(:logger)
+ message = []
+ MUST_HAVE_KEYS.each do |name|
+ message << name if configuration[name].nil?
+ end
+ raise ArgumentError.new(message.join(",") +" MUST be provided") unless message.empty?
+ VALID_ADAPTER_CONFIGURATION_KEYS.each do |name|
+ instance_variable_set("@#{name}", configuration[name])
+ end
+ end
- def connect(options={})
- host = options[:host] || @host
- method = options[:method] || @method || :plain
- port = options[:port] || @port || ensure_port(method)
- method = ensure_method(method)
- @disconnected = false
- @bound = false
- @bind_tried = false
+ def connect(options={})
+ host = options[:host] || @host
+ method = options[:method] || @method || :plain
+ port = options[:port] || @port || ensure_port(method)
+ method = ensure_method(method)
+ @disconnected = false
+ @bound = false
+ @bind_tried = false
+
config = {
:host => host,
:port => port,
}
+
config[:encryption] = {:method => method} if method
- @connection, @uri, @with_start_tls =
- begin
+
+ @connection, @uri, @with_start_tls = begin
uri = construct_uri(host, port, method == :simple_tls)
with_start_tls = method == :start_tls
puts ({:uri => uri, :with_start_tls => with_start_tls}).inspect
[Net::LDAP::Connection.new(config), uri, with_start_tls]
rescue Net::LDAP::LdapError
raise ConnectionError, $!.message
end
- end
+
+ end
- def unbind(options={})
- @connection.close # Net::LDAP doesn't implement unbind.
- end
+ def unbind(options={})
+ @connection.close # Net::LDAP doesn't implement unbind.
+ end
- def bind(options={})
- connect(options) unless connecting?
- begin
- @bind_tried = true
+ def bind(options={})
+ connect(options) unless connecting?
+ begin
+ @bind_tried = true
+
+ bind_dn = (options[:bind_dn] || @bind_dn).to_s
+ try_sasl = options.has_key?(:try_sasl) ? options[:try_sasl] : @try_sasl
- bind_dn = (options[:bind_dn] || @bind_dn).to_s
- try_sasl = options.has_key?(:try_sasl) ? options[:try_sasl] : @try_sasl
-
- # Rough bind loop:
- # Attempt 1: SASL if available
- # Attempt 2: SIMPLE with credentials if password block
- if try_sasl and sasl_bind(bind_dn, options)
- puts "bind with sasl"
- elsif simple_bind(bind_dn, options)
- puts "bind with simple"
- else
- message = yield if block_given?
- message ||= ('All authentication methods for %s exhausted.') % target
- raise AuthenticationError, message
- end
-
- @bound = true
- rescue Net::LDAP::LdapError
- raise AuthenticationError, $!.message
- end
+ # Rough bind loop:
+ # Attempt 1: SASL if available
+ # Attempt 2: SIMPLE with credentials if password block
+ if try_sasl and sasl_bind(bind_dn, options)
+ puts "bind with sasl"
+ elsif simple_bind(bind_dn, options)
+ puts "bind with simple"
+ else
+ message = yield if block_given?
+ message ||= ('All authentication methods for %s exhausted.') % target
+ raise AuthenticationError, message
+ end
+
+ @bound = true
+ rescue Net::LDAP::LdapError
+ raise AuthenticationError, $!.message
end
+ end
- def disconnect!(options={})
- unbind(options)
- @connection = @uri = @with_start_tls = nil
- @disconnected = true
- end
+ def disconnect!(options={})
+ unbind(options)
+ @connection = @uri = @with_start_tls = nil
+ @disconnected = true
+ end
- def rebind(options={})
- unbind(options) if bound?
- connect(options)
- end
+ def rebind(options={})
+ unbind(options) if bound?
+ connect(options)
+ end
- def connecting?
- !@connection.nil? and !@disconnected
- end
+ def connecting?
+ !@connection.nil? and !@disconnected
+ end
- def bound?
- connecting? and @bound
- end
+ def bound?
+ connecting? and @bound
+ end
- def search(options={}, &block)
- base = options[:base]
- filter = options[:filter]
- limit = options[:limit]
+ def search(options={}, &block)
+ base = options[:base]
+ filter = options[:filter]
+ limit = options[:limit]
- args = {
- :base => @base,
- :filter => filter,
- :size => limit
- }
- puts args.inspect
+ args = {
+ :base => @base,
+ :filter => filter,
+ :size => limit
+ }
+
+ puts args.inspect
+
attributes = {}
execute(:search, args) do |entry|
entry.attribute_names.each do |name|
attributes[name] = entry[name]
end
- end
- attributes
- end
- private
- def execute(method, *args, &block)
- result = @connection.send(method, *args, &block)
- message = nil
- if result.is_a?(Hash)
- message = result[:errorMessage]
- result = result[:resultCode]
- end
- unless result.zero?
- message = [Net::LDAP.result2string(result), message].compact.join(": ")
- raise LdapError, message
- end
- end
+ end
+ attributes
+ end
+
+ private
+
+ def execute(method, *args, &block)
+ result = @connection.send(method, *args, &block)
+ message = nil
+
+ if result.is_a?(Hash)
+ message = result[:errorMessage]
+ result = result[:resultCode]
+ end
+
+ unless result.zero?
+ message = [Net::LDAP.result2string(result), message].compact.join(": ")
+ raise LdapError, message
+ end
+ end
- def ensure_port(method)
- if method == :ssl
- URI::LDAPS::DEFAULT_PORT
- else
- URI::LDAP::DEFAULT_PORT
- end
+ def ensure_port(method)
+ if method == :ssl
+ URI::LDAPS::DEFAULT_PORT
+ else
+ URI::LDAP::DEFAULT_PORT
end
+ end
- def prepare_connection(options)
- end
+ def prepare_connection(options)
+ end
- def ensure_method(method)
- method ||= "plain"
- normalized_method = method.to_s.downcase.to_sym
- return METHOD[normalized_method] if METHOD.has_key?(normalized_method)
-
- available_methods = METHOD.keys.collect {|m| m.inspect}.join(", ")
- format = "%s is not one of the available connect methods: %s"
- raise ConfigurationError, format % [method.inspect, available_methods]
- end
+ def ensure_method(method)
+ method ||= "plain"
+ normalized_method = method.to_s.downcase.to_sym
+ return METHOD[normalized_method] if METHOD.has_key?(normalized_method)
+
+ available_methods = METHOD.keys.collect {|m| m.inspect}.join(", ")
+ format = "%s is not one of the available connect methods: %s"
+ raise ConfigurationError, format % [method.inspect, available_methods]
+ end
- def sasl_bind(bind_dn, options={})
- sasl_mechanisms = options[:sasl_mechanisms] || @sasl_mechanisms
- sasl_mechanisms.each do |mechanism|
- begin
- normalized_mechanism = mechanism.downcase.gsub(/-/, '_')
- sasl_bind_setup = "sasl_bind_setup_#{normalized_mechanism}"
- next unless respond_to?(sasl_bind_setup, true)
- initial_credential, challenge_response =
- send(sasl_bind_setup, bind_dn, options)
- args = {
- :method => :sasl,
- :initial_credential => initial_credential,
- :mechanism => mechanism,
- :challenge_response => challenge_response,
- }
- info = {
- :name => "bind: SASL", :dn => bind_dn, :mechanism => mechanism,
- }
- puts info.inspect
- execute(:bind, args)
- return true
- rescue Exception => e
- puts e.message
- end
- end
- false
- end
-
- def sasl_bind_setup_digest_md5(bind_dn, options)
- initial_credential = ""
- challenge_response = Proc.new do |cred|
- pref = SASL::Preferences.new :digest_uri => "ldap/#{@host}", :username => bind_dn, :has_password? => true, :password => options[:password]||@password
- sasl = SASL.new("DIGEST-MD5", pref)
- response = sasl.receive("challenge", cred)
- response[1]
+ def sasl_bind(bind_dn, options={})
+ sasl_mechanisms = options[:sasl_mechanisms] || @sasl_mechanisms
+ sasl_mechanisms.each do |mechanism|
+ begin
+ normalized_mechanism = mechanism.downcase.gsub(/-/, '_')
+ sasl_bind_setup = "sasl_bind_setup_#{normalized_mechanism}"
+ next unless respond_to?(sasl_bind_setup, true)
+ initial_credential, challenge_response = send(sasl_bind_setup, bind_dn, options)
+
+ args = {
+ :method => :sasl,
+ :initial_credential => initial_credential,
+ :mechanism => mechanism,
+ :challenge_response => challenge_response,
+ }
+
+ info = {
+ :name => "bind: SASL", :dn => bind_dn, :mechanism => mechanism,
+ }
+ puts info.inspect
+
+ execute(:bind, args)
+ return true
+
+ rescue Exception => e
+ puts e.message
+ end
+ end
+
+ false
end
- [initial_credential, challenge_response]
- end
- def sasl_bind_setup_gss_spnego(bind_dn, options)
- puts options.inspect
- user,psw = [bind_dn, options[:password]||@password]
- raise LdapError.new( "invalid binding information" ) unless (user && psw)
- nego = proc {|challenge|
- t2_msg = Net::NTLM::Message.parse( challenge )
- user, domain = user.split('\\').reverse
- t2_msg.target_name = Net::NTLM::encode_utf16le(domain) if domain
- t3_msg = t2_msg.response( {:user => user, :password => psw}, {:ntlmv2 => true} )
- t3_msg.serialize
- }
- [Net::NTLM::Message::Type1.new.serialize, nego]
- end
+ def sasl_bind_setup_digest_md5(bind_dn, options)
+ initial_credential = ""
+ challenge_response = Proc.new do |cred|
+ pref = SASL::Preferences.new :digest_uri => "ldap/#{@host}", :username => bind_dn, :has_password? => true, :password => options[:password]||@password
+ sasl = SASL.new("DIGEST-MD5", pref)
+ response = sasl.receive("challenge", cred)
+ response[1]
+ end
+ [initial_credential, challenge_response]
+ end
+
+ def sasl_bind_setup_gss_spnego(bind_dn, options)
+ puts options.inspect
+ user,psw = [bind_dn, options[:password]||@password]
+ raise LdapError.new( "invalid binding information" ) unless (user && psw)
+
+ nego = proc {|challenge|
+ t2_msg = Net::NTLM::Message.parse( challenge )
+ user, domain = user.split('\\').reverse
+ t2_msg.target_name = Net::NTLM::encode_utf16le(domain) if domain
+ t3_msg = t2_msg.response( {:user => user, :password => psw}, {:ntlmv2 => true} )
+ t3_msg.serialize
+ }
+ [Net::NTLM::Message::Type1.new.serialize, nego]
+ end
- def simple_bind(bind_dn, options={})
- args = {
- :method => :simple,
- :username => bind_dn,
- :password => options[:password]||@password,
- }
- execute(:bind, args)
- true
- end
+ def simple_bind(bind_dn, options={})
+ args = {
+ :method => :simple,
+ :username => bind_dn,
+ :password => options[:password]||@password,
+ }
+ execute(:bind, args)
+ true
+ end
- def construct_uri(host, port, ssl)
- protocol = ssl ? "ldaps" : "ldap"
- URI.parse("#{protocol}://#{host}:#{port}").to_s
- end
-
- def target
- return nil if @uri.nil?
- if @with_start_tls
- "#{@uri}(StartTLS)"
- else
- @uri
- end
- end
+ def construct_uri(host, port, ssl)
+ protocol = ssl ? "ldaps" : "ldap"
+ URI.parse("#{protocol}://#{host}:#{port}").to_s
+ end
+
+ def target
+ return nil if @uri.nil?
+ if @with_start_tls
+ "#{@uri}(StartTLS)"
+ else
+ @uri
+ end
+ end
end
end
end
-end
\ No newline at end of file
+end