ldaptic 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +104 -0
- data/Rakefile +41 -0
- data/lib/ldaptic.rb +151 -0
- data/lib/ldaptic/active_model.rb +37 -0
- data/lib/ldaptic/adapters.rb +90 -0
- data/lib/ldaptic/adapters/abstract_adapter.rb +123 -0
- data/lib/ldaptic/adapters/active_directory_adapter.rb +78 -0
- data/lib/ldaptic/adapters/active_directory_ext.rb +12 -0
- data/lib/ldaptic/adapters/ldap_conn_adapter.rb +262 -0
- data/lib/ldaptic/adapters/net_ldap_adapter.rb +173 -0
- data/lib/ldaptic/adapters/net_ldap_ext.rb +24 -0
- data/lib/ldaptic/attribute_set.rb +283 -0
- data/lib/ldaptic/dn.rb +365 -0
- data/lib/ldaptic/entry.rb +646 -0
- data/lib/ldaptic/error_set.rb +34 -0
- data/lib/ldaptic/errors.rb +136 -0
- data/lib/ldaptic/escape.rb +110 -0
- data/lib/ldaptic/filter.rb +282 -0
- data/lib/ldaptic/methods.rb +387 -0
- data/lib/ldaptic/railtie.rb +9 -0
- data/lib/ldaptic/schema.rb +246 -0
- data/lib/ldaptic/syntaxes.rb +319 -0
- data/test/core.schema +582 -0
- data/test/ldaptic_active_model_test.rb +40 -0
- data/test/ldaptic_adapters_test.rb +35 -0
- data/test/ldaptic_attribute_set_test.rb +57 -0
- data/test/ldaptic_dn_test.rb +110 -0
- data/test/ldaptic_entry_test.rb +22 -0
- data/test/ldaptic_errors_test.rb +23 -0
- data/test/ldaptic_escape_test.rb +47 -0
- data/test/ldaptic_filter_test.rb +53 -0
- data/test/ldaptic_hierarchy_test.rb +90 -0
- data/test/ldaptic_schema_test.rb +44 -0
- data/test/ldaptic_syntaxes_test.rb +66 -0
- data/test/mock_adapter.rb +47 -0
- data/test/rbslapd1.rb +111 -0
- data/test/rbslapd4.rb +172 -0
- data/test/test_helper.rb +2 -0
- metadata +146 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2007 Tim Pope
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
= Ldaptic
|
|
2
|
+
|
|
3
|
+
This is an object-oriented LDAP wrapper library I started back in 2007 but
|
|
4
|
+
only recently polished up and released. It's unique in that it creates a
|
|
5
|
+
class hierarchy (in a namespace your provide) that exactly mirrors the class
|
|
6
|
+
hierarchy on the server. For example, on a typical server, you'll get an
|
|
7
|
+
+InetOrgPerson+ class which inherits from +OrganizationalPerson+ which
|
|
8
|
+
inherits from +Person+ which inherits from +Top+. You can reopen any of these
|
|
9
|
+
classes to add additional client side behavior.
|
|
10
|
+
|
|
11
|
+
Ldaptic started as mainly a tool to interact with my company's Active
|
|
12
|
+
Directory server, and I lost interest in it when I left that job. Recently,
|
|
13
|
+
I've become motivated to work on it again, as some of the blocking issues I
|
|
14
|
+
faced are now potentially solvable with Active Model.
|
|
15
|
+
|
|
16
|
+
== Getting Started
|
|
17
|
+
|
|
18
|
+
You need to have either the ruby-ldap or net-ldap gem installed. The former
|
|
19
|
+
is preferred because it's faster native C. Ldaptic is configured by including
|
|
20
|
+
a dynamically created module into a namespace of your choosing.
|
|
21
|
+
|
|
22
|
+
module Example
|
|
23
|
+
include Ldaptic::Module(
|
|
24
|
+
:adapter => :ldap_conn,
|
|
25
|
+
:base => 'ou=Users,dc=example,dc=com',
|
|
26
|
+
:host => 'example.com',
|
|
27
|
+
:username => 'cn=admin,ou=Users,dc=example,dc=com',
|
|
28
|
+
:password => 'password'
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
The adapter field can usually be omitted as it defaults to :ldap_conn or
|
|
33
|
+
:net_ldap, based on which of the above two gems can be found (though you might
|
|
34
|
+
want to use the :active_directory adapter, which depends on ruby-ldap,
|
|
35
|
+
instead). If the base is omitted, it will use the first naming context on the
|
|
36
|
+
server (usually what you want).
|
|
37
|
+
|
|
38
|
+
Entries are retrieved using the search method. Named parameters include
|
|
39
|
+
:base, :filter, :sort, :limit, :scope, and :attributes. All are optional.
|
|
40
|
+
|
|
41
|
+
entries = Example.search(
|
|
42
|
+
:filter => {:objectClass => 'inetOrgPerson'}
|
|
43
|
+
:sort => :cn,
|
|
44
|
+
:limit => 10
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
A Ruby class is created for each objectClass defined on the server. Entries
|
|
48
|
+
are instances of these classes.
|
|
49
|
+
|
|
50
|
+
>> entry = Example.find('cn=admin,ou=Users,dc=example,dc=com')
|
|
51
|
+
=> #<Example::InetOrgPerson cn=admin,ou=Users,dc=example,dc=com ...>
|
|
52
|
+
>> entry.class.superclass
|
|
53
|
+
=> Example::OrganizationalPerson
|
|
54
|
+
|
|
55
|
+
Predictably, entries have attribute readers and writers.
|
|
56
|
+
|
|
57
|
+
>> entry.cn
|
|
58
|
+
=> <["admin"]>
|
|
59
|
+
>> entry.cn = "root"
|
|
60
|
+
>> entry[:cn]
|
|
61
|
+
=> <["root"]>
|
|
62
|
+
>> entry[:cn] = "admin"
|
|
63
|
+
|
|
64
|
+
The returned object is an attribute set and behaves similar to an array. Some
|
|
65
|
+
attributes are marked by the server as "single value;" those will return the
|
|
66
|
+
first element on method access but an attribute set on indexing access, for
|
|
67
|
+
programmatic convenience.
|
|
68
|
+
|
|
69
|
+
>> entry.uidNumber
|
|
70
|
+
=> 0
|
|
71
|
+
>> entry[:uidNumber]
|
|
72
|
+
=> <[0]>
|
|
73
|
+
|
|
74
|
+
The indexing syntax can also be used to create and fetch children.
|
|
75
|
+
|
|
76
|
+
>> users
|
|
77
|
+
=> #<Example::OrganizationalUnit ou=Users,dc=example,dc=com ...>
|
|
78
|
+
>> users[:cn=>'admin'] = Example::InetOrgPerson.new
|
|
79
|
+
=> #<Example::InetOrgPerson cn=admin,ou=Users,dc=example,dc=com ...>
|
|
80
|
+
>> users[:cn=>'admin']
|
|
81
|
+
=> #<Example::InetOrgPerson cn=admin,ou=Users,dc=example,dc=com ...>
|
|
82
|
+
|
|
83
|
+
Entries also implement many of the standard methods you've come to expect in
|
|
84
|
+
an Active Record world (save, valid?, errors, to_param, attributes, ...).
|
|
85
|
+
In fact, it is fully Active Model compliant.
|
|
86
|
+
|
|
87
|
+
For more information, see in particular Ldaptic::Methods (for namespace
|
|
88
|
+
methods like search), Ldaptic::Entry, and Ldaptic::AttributeSet.
|
|
89
|
+
|
|
90
|
+
== To Do
|
|
91
|
+
|
|
92
|
+
* Verify everything still works. The tests take care of much of this, but
|
|
93
|
+
there are no integration tests for the adapters. In particular, I have no
|
|
94
|
+
way to verify the Active Directory adapter still works.
|
|
95
|
+
|
|
96
|
+
* The test suite (reflecting my fledgling testing abilities from 2007) is more
|
|
97
|
+
smoke test than BDD. Perhaps switch to RSpec in the quest to rectify this.
|
|
98
|
+
|
|
99
|
+
* Potential new features (mostly along the lines of "make it more like Active
|
|
100
|
+
Record") are in the GitHub issue tracker. Vote for and comment on the ones
|
|
101
|
+
you would find useful, as most are on hold until someone has a real use
|
|
102
|
+
case.
|
|
103
|
+
|
|
104
|
+
* Pick a better name? Ldaptic has an ambiguous spelling.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
end
|
|
5
|
+
require 'rake/testtask'
|
|
6
|
+
require 'rake/rdoctask'
|
|
7
|
+
require 'rake/packagetask'
|
|
8
|
+
require 'rake/gempackagetask'
|
|
9
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
|
10
|
+
|
|
11
|
+
task :default => :test
|
|
12
|
+
|
|
13
|
+
Rake::TestTask.new do |t|
|
|
14
|
+
t.libs << "test"
|
|
15
|
+
t.test_files = Dir['test/*_test.rb']
|
|
16
|
+
t.verbose = true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Rake::RDocTask.new do |rdoc|
|
|
20
|
+
rdoc.rdoc_dir = 'doc'
|
|
21
|
+
rdoc.rdoc_files.add('README.rdoc', 'lib')
|
|
22
|
+
rdoc.main = 'README.rdoc'
|
|
23
|
+
rdoc.title = 'Ldaptic'
|
|
24
|
+
rdoc.options << '--inline-source'
|
|
25
|
+
rdoc.options << '-d' if `which dot` =~ /\/dot/
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
spec = eval(File.read(File.join(File.dirname(__FILE__), 'ldaptic.gemspec')))
|
|
29
|
+
Rake::GemPackageTask.new(spec) do |p|
|
|
30
|
+
p.gem_spec = spec
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
begin
|
|
34
|
+
require 'rcov/rcovtask'
|
|
35
|
+
Rcov::RcovTask.new do |t|
|
|
36
|
+
t.test_files = Dir['test/*_test.rb']
|
|
37
|
+
t.verbose = true
|
|
38
|
+
t.rcov_opts << "--exclude '/(rcov|net-ldap|i18n|active(?:support|model))-'"
|
|
39
|
+
end
|
|
40
|
+
rescue LoadError
|
|
41
|
+
end
|
data/lib/ldaptic.rb
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'ldaptic/dn'
|
|
4
|
+
require 'ldaptic/filter'
|
|
5
|
+
require 'ldaptic/errors'
|
|
6
|
+
require 'ldaptic/schema'
|
|
7
|
+
require 'ldaptic/syntaxes'
|
|
8
|
+
require 'ldaptic/adapters'
|
|
9
|
+
require 'ldaptic/entry'
|
|
10
|
+
require 'ldaptic/methods'
|
|
11
|
+
|
|
12
|
+
# = Getting started
|
|
13
|
+
#
|
|
14
|
+
# See the methods of the Ldaptic module (below) for information on connecting.
|
|
15
|
+
#
|
|
16
|
+
# See the Ldaptic::Methods module for information on searching with your
|
|
17
|
+
# connection object.
|
|
18
|
+
#
|
|
19
|
+
# Search results are Ldaptic::Entry objects. See the documentation for this
|
|
20
|
+
# class for information on manipulating and updating them, as well as creating
|
|
21
|
+
# new entries.
|
|
22
|
+
module Ldaptic
|
|
23
|
+
|
|
24
|
+
SCOPES = {
|
|
25
|
+
:base => 0, # ::LDAP::LDAP_SCOPE_BASE,
|
|
26
|
+
:onelevel => 1, # ::LDAP::LDAP_SCOPE_ONELEVEL,
|
|
27
|
+
:subtree => 2 # ::LDAP::LDAP_SCOPE_SUBTREE
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Default logger. If none given, creates a new logger on $stderr.
|
|
31
|
+
def self.logger
|
|
32
|
+
unless @logger
|
|
33
|
+
if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
|
34
|
+
return Rails.logger
|
|
35
|
+
else
|
|
36
|
+
require 'logger'
|
|
37
|
+
@logger = Logger.new($stderr)
|
|
38
|
+
@logger.level = Logger::WARN
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
@logger
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.logger=(logger)
|
|
45
|
+
@logger = logger
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns an object that can be assigned directly to a variable. This allows
|
|
49
|
+
# for an "anonymous" Ldaptic object.
|
|
50
|
+
# @my_company = Ldaptic::Object(options)
|
|
51
|
+
# @my_company::User.class_eval do
|
|
52
|
+
# alias login sAMAccountName
|
|
53
|
+
# end
|
|
54
|
+
def self.Object(options={}, &block)
|
|
55
|
+
base = ::Module.new do
|
|
56
|
+
include Ldaptic::Module(options)
|
|
57
|
+
end
|
|
58
|
+
if block_given?
|
|
59
|
+
base.class_eval(&block)
|
|
60
|
+
end
|
|
61
|
+
base
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Similar to Ldaptic::Class, accepting the same options. Instead of
|
|
65
|
+
# returning an anonymous class that activates upon inheritance, it returns an
|
|
66
|
+
# anonymous module that activates upon inclusion.
|
|
67
|
+
# module MyCompany
|
|
68
|
+
# include Ldaptic::Module(options)
|
|
69
|
+
# # This class and many others are created automatically based on
|
|
70
|
+
# # information from the server.
|
|
71
|
+
# class User
|
|
72
|
+
# alias login sAMAccountName
|
|
73
|
+
# end
|
|
74
|
+
# end
|
|
75
|
+
#
|
|
76
|
+
# me = MyCompany.search(:filter => {:cn => "Name, My"}).first
|
|
77
|
+
# puts me.login
|
|
78
|
+
def self.Module(options={})
|
|
79
|
+
Ldaptic::Module.new(options)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The core constructor of Ldaptic. This method returns an anonymous class
|
|
83
|
+
# which can then be inherited from.
|
|
84
|
+
#
|
|
85
|
+
# The new class is not intended to be instantiated, instead serving as a
|
|
86
|
+
# namespace. Included in this namespace is a set of class methods, as found
|
|
87
|
+
# in Ldaptic::Methods, and a class hierarchy mirroring the object classes
|
|
88
|
+
# found on the server.
|
|
89
|
+
#
|
|
90
|
+
# options = {
|
|
91
|
+
# :adapter => :active_directory,
|
|
92
|
+
# :host => "pdc.mycompany.com",
|
|
93
|
+
# :username => "mylogin@mycompany.com",
|
|
94
|
+
# :password => "mypassword"
|
|
95
|
+
# }
|
|
96
|
+
#
|
|
97
|
+
# class MyCompany < Ldaptic::Class(options)
|
|
98
|
+
# # This class and many others are created automatically based on
|
|
99
|
+
# # information from the server.
|
|
100
|
+
# class User
|
|
101
|
+
# alias login sAMAccountName
|
|
102
|
+
# end
|
|
103
|
+
# end
|
|
104
|
+
#
|
|
105
|
+
# me = MyCompany.search(:filter => {:cn => "Name, My"}).first
|
|
106
|
+
# puts me.login
|
|
107
|
+
#
|
|
108
|
+
# Options given to this method are relayed to Ldaptic::Adapters.for. The
|
|
109
|
+
# documentation for this method should be consulted for further information.
|
|
110
|
+
def self.Class(options={})
|
|
111
|
+
klass = ::Class.new(Class)
|
|
112
|
+
klass.instance_variable_set(:@options, Ldaptic::Adapters.for(options))
|
|
113
|
+
klass
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
class << self
|
|
117
|
+
alias Namespace Class
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# An instance of this subclass of ::Module is returned by the Ldaptic::Module
|
|
121
|
+
# method.
|
|
122
|
+
class Module < ::Module #:nodoc:
|
|
123
|
+
def initialize(options={})
|
|
124
|
+
super()
|
|
125
|
+
@options = options
|
|
126
|
+
end
|
|
127
|
+
def append_features(base)
|
|
128
|
+
base.extend(Methods)
|
|
129
|
+
base.instance_variable_set(:@adapter, Ldaptic::Adapters.for(@options))
|
|
130
|
+
base.module_eval { build_hierarchy }
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# The anonymous class returned by the Ldaptic::Class method descends from
|
|
135
|
+
# this class.
|
|
136
|
+
class Class #:nodoc:
|
|
137
|
+
class << self
|
|
138
|
+
# Callback which triggers the magic.
|
|
139
|
+
def inherited(subclass)
|
|
140
|
+
if options = @options
|
|
141
|
+
subclass.class_eval { include Ldaptic::Module.new(options) }
|
|
142
|
+
else
|
|
143
|
+
subclass.instance_variable_set(:@adapter, @adapter)
|
|
144
|
+
end
|
|
145
|
+
super
|
|
146
|
+
end
|
|
147
|
+
private :inherited, :new
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'active_model'
|
|
2
|
+
require 'ldaptic'
|
|
3
|
+
|
|
4
|
+
ActiveModel::EachValidator.class_eval do
|
|
5
|
+
def validate(record)
|
|
6
|
+
attributes.each do |attribute|
|
|
7
|
+
values = record.read_attribute_for_validation(attribute)
|
|
8
|
+
values = [values] unless values.respond_to?(:before_type_cast)
|
|
9
|
+
values.each do |value|
|
|
10
|
+
next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
|
|
11
|
+
validate_each(record, attribute, value)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Ldaptic::Entry
|
|
18
|
+
include ActiveModel::Validations
|
|
19
|
+
include ActiveModel::Serializers::Xml
|
|
20
|
+
include ActiveModel::Serializers::JSON
|
|
21
|
+
include ActiveModel::Dirty
|
|
22
|
+
include ActiveModel::Callbacks
|
|
23
|
+
|
|
24
|
+
def read_attribute_for_validation(attribute)
|
|
25
|
+
read_attribute(attribute.to_sym, true)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# define_model_callbacks(:save, :destroy)
|
|
29
|
+
|
|
30
|
+
validate do
|
|
31
|
+
@attributes.keys.each do |key|
|
|
32
|
+
self[key].errors.each do |error|
|
|
33
|
+
errors.add(key, error)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end if respond_to?(:validate)
|
|
37
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module Ldaptic
|
|
2
|
+
# RFC1823 - The LDAP Application Program Interface
|
|
3
|
+
module Adapters
|
|
4
|
+
|
|
5
|
+
@adapters ||= {}
|
|
6
|
+
|
|
7
|
+
class <<self
|
|
8
|
+
|
|
9
|
+
# Internally used by adapters to make themselves available.
|
|
10
|
+
def register(name, mod) #:nodoc:
|
|
11
|
+
@adapters[name.to_sym] = mod
|
|
12
|
+
@adapters
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns a new adapter for a given set of options. This method is not
|
|
16
|
+
# for end user use but is instead called by the Ldaptic::Class,
|
|
17
|
+
# Ldaptic::Module, and Ldaptic::Object methods.
|
|
18
|
+
#
|
|
19
|
+
# The <tt>:adapter</tt> key of the +options+ hash selects which adapter
|
|
20
|
+
# to use. The following adapters are included with Ldaptic.
|
|
21
|
+
#
|
|
22
|
+
# * <tt>:ldap_conn</tt>: a Ruby/LDAP LDAP::Conn connection.
|
|
23
|
+
# * <tt>:ldap_sslconn</tt>: a Ruby/LDAP LDAP::SSLConn connection.
|
|
24
|
+
# * <tt>:active_directory</tt>: A wrapper around Ruby/LDAP which takes
|
|
25
|
+
# into account some of the idiosyncrasies of Active Directory.
|
|
26
|
+
# * <tt>:net_ldap</tt>: a net-ldap Net::LDAP connection.
|
|
27
|
+
#
|
|
28
|
+
# All other options given are passed directly to the adapter. While
|
|
29
|
+
# different adapters support different options, the following are
|
|
30
|
+
# typically supported.
|
|
31
|
+
#
|
|
32
|
+
# * <tt>:host</tt>: The host to connect to. The default is localhost.
|
|
33
|
+
# * <tt>:port</tt>: The TCP port to use. Default is provided by the
|
|
34
|
+
# underlying connection.
|
|
35
|
+
# * <tt>:username</tt>: The DN to bind with. If not given, an anonymous
|
|
36
|
+
# bind is used.
|
|
37
|
+
# * <tt>:password</tt>: Password for binding.
|
|
38
|
+
# * <tt>:base</tt>: The default base DN. Derived from the server by
|
|
39
|
+
# default.
|
|
40
|
+
def for(options)
|
|
41
|
+
require 'ldaptic/adapters/abstract_adapter'
|
|
42
|
+
# Allow an adapter to be passed directly in for backwards compatibility.
|
|
43
|
+
if defined?(::LDAP::Conn) && options.kind_of?(::LDAP::Conn)
|
|
44
|
+
options = {:adapter => :ldap_conn, :connection => options}
|
|
45
|
+
elsif defined?(::Net::LDAP) && options.kind_of?(::Net::LDAP)
|
|
46
|
+
options = {:adapter => :net_ldap, :connection => options}
|
|
47
|
+
end
|
|
48
|
+
if options.kind_of?(Hash)
|
|
49
|
+
options = options.inject({}) {|h,(k,v)| h[k.to_sym] = v; h}
|
|
50
|
+
if options.has_key?(:connection) && !options.has_key?(:adapter)
|
|
51
|
+
options[:adapter] = options[:connection].class.name.downcase.gsub('::','_')
|
|
52
|
+
end
|
|
53
|
+
options[:adapter] ||= default_adapter
|
|
54
|
+
unless options[:adapter]
|
|
55
|
+
Ldaptic::Errors.raise(ArgumentError.new("No adapter specfied"))
|
|
56
|
+
end
|
|
57
|
+
begin
|
|
58
|
+
require "ldaptic/adapters/#{options[:adapter]}_adapter"
|
|
59
|
+
rescue LoadError
|
|
60
|
+
end
|
|
61
|
+
if adapter = @adapters[options[:adapter].to_sym]
|
|
62
|
+
adapter.new(options)
|
|
63
|
+
else
|
|
64
|
+
Ldaptic::Errors.raise(ArgumentError.new("Adapter #{options[:adapter]} not found"))
|
|
65
|
+
end
|
|
66
|
+
else
|
|
67
|
+
if options.kind_of?(::Ldaptic::Adapters::AbstractAdapter)
|
|
68
|
+
options
|
|
69
|
+
else
|
|
70
|
+
Ldaptic::Errors.raise(TypeError.new("#{options.class} is not a valid connection type"))
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
def default_adapter
|
|
77
|
+
require 'ldap'
|
|
78
|
+
:ldap_conn
|
|
79
|
+
rescue LoadError
|
|
80
|
+
begin
|
|
81
|
+
require 'net/ldap'
|
|
82
|
+
:net_ldap
|
|
83
|
+
rescue LoadError
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
end
|