ruby-activeldap 0.8.3 → 0.8.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. data/CHANGES +431 -0
  2. data/COPYING +340 -0
  3. data/LICENSE +58 -0
  4. data/README +104 -0
  5. data/Rakefile +165 -0
  6. data/TODO +22 -0
  7. data/benchmark/bench-al.rb +202 -0
  8. data/benchmark/config.yaml.sample +5 -0
  9. data/data/locale/en/LC_MESSAGES/active-ldap.mo +0 -0
  10. data/data/locale/ja/LC_MESSAGES/active-ldap.mo +0 -0
  11. data/examples/al-admin/README +182 -0
  12. data/examples/al-admin/Rakefile +10 -0
  13. data/examples/al-admin/app/controllers/account_controller.rb +50 -0
  14. data/examples/al-admin/app/controllers/application.rb +15 -0
  15. data/examples/al-admin/app/controllers/directory_controller.rb +22 -0
  16. data/examples/al-admin/app/controllers/users_controller.rb +38 -0
  17. data/examples/al-admin/app/controllers/welcome_controller.rb +4 -0
  18. data/examples/al-admin/app/helpers/account_helper.rb +2 -0
  19. data/examples/al-admin/app/helpers/application_helper.rb +6 -0
  20. data/examples/al-admin/app/helpers/directory_helper.rb +2 -0
  21. data/examples/al-admin/app/helpers/users_helper.rb +13 -0
  22. data/examples/al-admin/app/helpers/welcome_helper.rb +2 -0
  23. data/examples/al-admin/app/models/entry.rb +19 -0
  24. data/examples/al-admin/app/models/ldap_user.rb +49 -0
  25. data/examples/al-admin/app/models/user.rb +91 -0
  26. data/examples/al-admin/app/views/account/login.rhtml +12 -0
  27. data/examples/al-admin/app/views/account/sign_up.rhtml +22 -0
  28. data/examples/al-admin/app/views/directory/index.rhtml +5 -0
  29. data/examples/al-admin/app/views/directory/populate.rhtml +2 -0
  30. data/examples/al-admin/app/views/layouts/application.rhtml +41 -0
  31. data/examples/al-admin/app/views/users/_attribute_information.rhtml +22 -0
  32. data/examples/al-admin/app/views/users/_entry.rhtml +12 -0
  33. data/examples/al-admin/app/views/users/_form.rhtml +29 -0
  34. data/examples/al-admin/app/views/users/_object_class_information.rhtml +23 -0
  35. data/examples/al-admin/app/views/users/edit.rhtml +10 -0
  36. data/examples/al-admin/app/views/users/index.rhtml +9 -0
  37. data/examples/al-admin/app/views/users/show.rhtml +3 -0
  38. data/examples/al-admin/app/views/welcome/index.rhtml +16 -0
  39. data/examples/al-admin/config/boot.rb +45 -0
  40. data/examples/al-admin/config/database.yml.example +19 -0
  41. data/examples/al-admin/config/environment.rb +68 -0
  42. data/examples/al-admin/config/environments/development.rb +21 -0
  43. data/examples/al-admin/config/environments/production.rb +18 -0
  44. data/examples/al-admin/config/environments/test.rb +19 -0
  45. data/examples/al-admin/config/ldap.yml.example +21 -0
  46. data/examples/al-admin/config/routes.rb +26 -0
  47. data/examples/al-admin/db/migrate/001_create_users.rb +16 -0
  48. data/examples/al-admin/lib/accept_http_rails_relative_url_root.rb +9 -0
  49. data/examples/al-admin/lib/authenticated_system.rb +131 -0
  50. data/examples/al-admin/lib/authenticated_test_helper.rb +113 -0
  51. data/examples/al-admin/lib/tasks/gettext.rake +35 -0
  52. data/examples/al-admin/po/en/al-admin.po +190 -0
  53. data/examples/al-admin/po/ja/al-admin.po +190 -0
  54. data/examples/al-admin/po/nl/al-admin.po +202 -0
  55. data/examples/al-admin/public/.htaccess +40 -0
  56. data/examples/al-admin/public/404.html +30 -0
  57. data/examples/al-admin/public/500.html +30 -0
  58. data/examples/al-admin/public/dispatch.cgi +10 -0
  59. data/examples/al-admin/public/dispatch.fcgi +24 -0
  60. data/examples/al-admin/public/dispatch.rb +10 -0
  61. data/examples/al-admin/public/favicon.ico +0 -0
  62. data/examples/al-admin/public/images/rails.png +0 -0
  63. data/examples/al-admin/public/javascripts/application.js +2 -0
  64. data/examples/al-admin/public/javascripts/controls.js +833 -0
  65. data/examples/al-admin/public/javascripts/dragdrop.js +942 -0
  66. data/examples/al-admin/public/javascripts/effects.js +1088 -0
  67. data/examples/al-admin/public/javascripts/prototype.js +2515 -0
  68. data/examples/al-admin/public/robots.txt +1 -0
  69. data/examples/al-admin/public/stylesheets/rails.css +35 -0
  70. data/examples/al-admin/public/stylesheets/screen.css +52 -0
  71. data/examples/al-admin/script/about +3 -0
  72. data/examples/al-admin/script/breakpointer +3 -0
  73. data/examples/al-admin/script/console +3 -0
  74. data/examples/al-admin/script/destroy +3 -0
  75. data/examples/al-admin/script/generate +3 -0
  76. data/examples/al-admin/script/performance/benchmarker +3 -0
  77. data/examples/al-admin/script/performance/profiler +3 -0
  78. data/examples/al-admin/script/plugin +3 -0
  79. data/examples/al-admin/script/process/inspector +3 -0
  80. data/examples/al-admin/script/process/reaper +3 -0
  81. data/examples/al-admin/script/process/spawner +3 -0
  82. data/examples/al-admin/script/runner +3 -0
  83. data/examples/al-admin/script/server +3 -0
  84. data/examples/al-admin/test/fixtures/users.yml +9 -0
  85. data/examples/al-admin/test/functional/account_controller_test.rb +24 -0
  86. data/examples/al-admin/test/functional/directory_controller_test.rb +18 -0
  87. data/examples/al-admin/test/functional/users_controller_test.rb +18 -0
  88. data/examples/al-admin/test/functional/welcome_controller_test.rb +18 -0
  89. data/examples/al-admin/test/run-test.sh +3 -0
  90. data/examples/al-admin/test/test_helper.rb +28 -0
  91. data/examples/al-admin/test/unit/user_test.rb +13 -0
  92. data/examples/al-admin/vendor/plugins/exception_notification/README +111 -0
  93. data/examples/al-admin/vendor/plugins/exception_notification/init.rb +1 -0
  94. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifiable.rb +99 -0
  95. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifier.rb +67 -0
  96. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifier_helper.rb +77 -0
  97. data/examples/al-admin/vendor/plugins/exception_notification/test/exception_notifier_helper_test.rb +61 -0
  98. data/examples/al-admin/vendor/plugins/exception_notification/test/test_helper.rb +7 -0
  99. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_backtrace.rhtml +1 -0
  100. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_environment.rhtml +7 -0
  101. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_inspect_model.rhtml +16 -0
  102. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_request.rhtml +3 -0
  103. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_session.rhtml +2 -0
  104. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_title.rhtml +3 -0
  105. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/exception_notification.rhtml +6 -0
  106. data/examples/config.yaml.example +5 -0
  107. data/examples/example.der +0 -0
  108. data/examples/example.jpg +0 -0
  109. data/examples/groupadd +41 -0
  110. data/examples/groupdel +35 -0
  111. data/examples/groupls +49 -0
  112. data/examples/groupmod +42 -0
  113. data/examples/lpasswd +55 -0
  114. data/examples/objects/group.rb +13 -0
  115. data/examples/objects/ou.rb +4 -0
  116. data/examples/objects/user.rb +20 -0
  117. data/examples/ouadd +38 -0
  118. data/examples/useradd +45 -0
  119. data/examples/useradd-binary +50 -0
  120. data/examples/userdel +34 -0
  121. data/examples/userls +50 -0
  122. data/examples/usermod +42 -0
  123. data/examples/usermod-binary-add +47 -0
  124. data/examples/usermod-binary-add-time +51 -0
  125. data/examples/usermod-binary-del +48 -0
  126. data/examples/usermod-lang-add +43 -0
  127. data/lib/active_ldap.rb +978 -0
  128. data/lib/active_ldap/adapter/base.rb +512 -0
  129. data/lib/active_ldap/adapter/ldap.rb +233 -0
  130. data/lib/active_ldap/adapter/ldap_ext.rb +69 -0
  131. data/lib/active_ldap/adapter/net_ldap.rb +290 -0
  132. data/lib/active_ldap/adapter/net_ldap_ext.rb +29 -0
  133. data/lib/active_ldap/association/belongs_to.rb +47 -0
  134. data/lib/active_ldap/association/belongs_to_many.rb +42 -0
  135. data/lib/active_ldap/association/collection.rb +83 -0
  136. data/lib/active_ldap/association/has_many.rb +31 -0
  137. data/lib/active_ldap/association/has_many_utils.rb +35 -0
  138. data/lib/active_ldap/association/has_many_wrap.rb +46 -0
  139. data/lib/active_ldap/association/proxy.rb +102 -0
  140. data/lib/active_ldap/associations.rb +172 -0
  141. data/lib/active_ldap/attributes.rb +211 -0
  142. data/lib/active_ldap/base.rb +1256 -0
  143. data/lib/active_ldap/callbacks.rb +19 -0
  144. data/lib/active_ldap/command.rb +48 -0
  145. data/lib/active_ldap/configuration.rb +114 -0
  146. data/lib/active_ldap/connection.rb +234 -0
  147. data/lib/active_ldap/distinguished_name.rb +250 -0
  148. data/lib/active_ldap/escape.rb +12 -0
  149. data/lib/active_ldap/get_text/parser.rb +142 -0
  150. data/lib/active_ldap/get_text_fallback.rb +53 -0
  151. data/lib/active_ldap/get_text_support.rb +12 -0
  152. data/lib/active_ldap/helper.rb +23 -0
  153. data/lib/active_ldap/ldap_error.rb +74 -0
  154. data/lib/active_ldap/object_class.rb +93 -0
  155. data/lib/active_ldap/operations.rb +419 -0
  156. data/lib/active_ldap/populate.rb +44 -0
  157. data/lib/active_ldap/schema.rb +427 -0
  158. data/lib/active_ldap/timeout.rb +75 -0
  159. data/lib/active_ldap/timeout_stub.rb +17 -0
  160. data/lib/active_ldap/user_password.rb +93 -0
  161. data/lib/active_ldap/validations.rb +112 -0
  162. data/po/en/active-ldap.po +3011 -0
  163. data/po/ja/active-ldap.po +3044 -0
  164. data/rails/plugin/active_ldap/README +54 -0
  165. data/rails/plugin/active_ldap/generators/scaffold_al/scaffold_al_generator.rb +7 -0
  166. data/rails/plugin/active_ldap/generators/scaffold_al/templates/ldap.yml +21 -0
  167. data/rails/plugin/active_ldap/init.rb +19 -0
  168. data/test/al-test-utils.rb +362 -0
  169. data/test/command.rb +62 -0
  170. data/test/config.yaml.sample +6 -0
  171. data/test/run-test.rb +31 -0
  172. data/test/test-unit-ext.rb +4 -0
  173. data/test/test-unit-ext/always-show-result.rb +28 -0
  174. data/test/test-unit-ext/backtrace-filter.rb +17 -0
  175. data/test/test-unit-ext/long-display-for-emacs.rb +25 -0
  176. data/test/test-unit-ext/priority.rb +163 -0
  177. metadata +211 -4
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/ruby -W0
2
+
3
+ base = File.expand_path(File.join(File.dirname(__FILE__), ".."))
4
+ $LOAD_PATH << File.join(base, "lib")
5
+ $LOAD_PATH << File.join(base, "examples")
6
+
7
+ require 'active_ldap'
8
+ require 'objects/user'
9
+ require 'objects/group'
10
+
11
+ argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
12
+ opts.banner += " USER_NAME CN UID"
13
+ end
14
+
15
+ if argv.size == 3
16
+ name, cn, uid = argv
17
+ else
18
+ $stderr.puts opts
19
+ exit 1
20
+ end
21
+
22
+ pwb = Proc.new do |user|
23
+ ActiveLdap::Command.read_password("[#{user}] Password: ")
24
+ end
25
+
26
+ ActiveLdap::Base.establish_connection(:password_block => pwb,
27
+ :allow_anonymous => false)
28
+
29
+ unless User.exists?(name)
30
+ $stderr.puts("User #{name} doesn't exist.")
31
+ exit 1
32
+ end
33
+
34
+ user = User.find(name)
35
+ user.cn = cn
36
+ user.uid_number = uid
37
+ user.gid_number = uid
38
+
39
+ if user.classes.include?('strongAuthenticationUser')
40
+ user.user_certificate = nil
41
+ user.remove_class('strongAuthenticationUser')
42
+ end
43
+
44
+ unless user.save
45
+ puts "failed"
46
+ puts user.errors.full_messages
47
+ exit 1
48
+ end
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/ruby -W0
2
+
3
+ base = File.expand_path(File.join(File.dirname(__FILE__), ".."))
4
+ $LOAD_PATH << File.join(base, "lib")
5
+ $LOAD_PATH << File.join(base, "examples")
6
+
7
+ require 'active_ldap'
8
+ require 'objects/user'
9
+ require 'objects/group'
10
+
11
+ argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
12
+ opts.banner += " USER_NAME CN UID"
13
+ end
14
+
15
+ if argv.size == 3
16
+ name, cn, uid = argv
17
+ else
18
+ $stderr.puts opts
19
+ exit 1
20
+ end
21
+
22
+ pwb = Proc.new do |user|
23
+ ActiveLdap::Command.read_password("[#{user}] Password: ")
24
+ end
25
+
26
+ ActiveLdap::Base.establish_connection(:password_block => pwb,
27
+ :allow_anonymous => false)
28
+
29
+ unless User.exists?(name)
30
+ $stderr.puts("User #{name} doesn't exist.")
31
+ exit 1
32
+ end
33
+
34
+ user = User.find(name)
35
+ user.cn = [cn, {'lang-en-us' => cn}]
36
+ user.uid_number = uid
37
+ user.gid_number = uid
38
+
39
+ unless user.save
40
+ puts "failed"
41
+ puts user.errors.full_messages
42
+ exit 1
43
+ end
@@ -0,0 +1,978 @@
1
+ #!/usr/bin/ruby
2
+ # = Ruby/ActiveLdap
3
+ #
4
+ # "Ruby/ActiveLdap" Copyright (C) 2004,2005 Will Drewry mailto:will@alum.bu.edu
5
+ #
6
+ # == Introduction
7
+ #
8
+ # Ruby/ActiveLdap is a novel way of interacting with LDAP. Most interaction with
9
+ # LDAP is done using clunky LDIFs, web interfaces, or with painful APIs that
10
+ # required a thick reference manual nearby. Ruby/ActiveLdap aims to fix that.
11
+ # Inspired by ActiveRecord[http://activerecord.rubyonrails.org], Ruby/ActiveLdap provides an
12
+ # object oriented interface to LDAP entries.
13
+ #
14
+ # The target audience is system administrators and LDAP users everywhere that
15
+ # need quick, clean access to LDAP in Ruby.
16
+ #
17
+ # === What's LDAP?
18
+ #
19
+ # LDAP stands for "Lightweight Directory Access Protocol." Basically this means
20
+ # that it is the protocol used for accessing LDAP servers. LDAP servers
21
+ # lightweight directories. An LDAP server can contain anything from a simple
22
+ # digital phonebook to user accounts for computer systems. More and more
23
+ # frequently, it is being used for the latter. My examples in this text will
24
+ # assume some familiarity with using LDAP as a centralized authentication and
25
+ # authorization server for Unix systems. (Unfortunately, I've yet to try this
26
+ # against Microsoft's ActiveDirectory, despite what the name implies.)
27
+ #
28
+ # Further reading:
29
+ # * RFC1777[http://www.faqs.org/rfcs/rfc1777.html] - Lightweight Directory Access Protocol
30
+ # * OpenLDAP[http://www.openldap.org]
31
+ #
32
+ # === So why use Ruby/ActiveLdap?
33
+ #
34
+ # Well if you like to fumble around in the dark, dank innards of LDAP, you can
35
+ # quit reading now. However, if you'd like a cleaner way to integrate LDAP in to
36
+ # your existing code, hopefully that's why you'll want to use Ruby/ActiveLdap.
37
+ #
38
+ # Using LDAP directly (even with the excellent Ruby/LDAP), leaves you bound to
39
+ # the world of the predefined LDAP API. While this API is important for many
40
+ # reasons, having to extract code out of LDAP search blocks and create huge
41
+ # arrays of LDAP.mod entries make code harder to read, less intuitive, and just
42
+ # less fun to write. Hopefully, Ruby/ActiveLdap will remedy all of these
43
+ # problems!
44
+ #
45
+ # == Getting Started
46
+ #
47
+ # Ruby/ActiveLdap does have some overhead when you get started. You must not
48
+ # only install the package and all of it's requirements, but you must also make
49
+ # customizations that will let it work in your environment.
50
+ #
51
+ # === Requirements
52
+ #
53
+ # * Ruby[http://www.ruby-lang.org] 1.8.x
54
+ # * Ruby/LDAP[http://ruby-ldap.sourceforge.net]
55
+ # * Log4r[http://log4r.sourceforge.net]
56
+ # * (Optional) Ruby/LDAP+GSSAPI[http://caliban.org/files/redhat/RPMS/i386/ruby-ldap-0.8.2-4.i386.rpm]
57
+ # * An LDAP server compatible with Ruby/LDAP: OpenLDAP[http://www.openldap.org], etc
58
+ # - Your LDAP server must allow root_dse queries to allow for schema queries
59
+ # * Examples also require: Ruby/Password[http://raa.ruby-lang.org/project/ruby-password/]
60
+ #
61
+ # === Installation
62
+ #
63
+ # Assuming all the requirements are installed, you can install by grabbing the latest tgz file from
64
+ # the download site[http://rubyforge.org/frs/?group_id=381].
65
+ #
66
+ # The following steps will get the Ruby/ActiveLdap installed in no time!
67
+ #
68
+ # $ tar -xzvf ruby-activeldap-current.tgz
69
+ # $ cd ruby-activeldap-VERSION
70
+ #
71
+ # Edit lib/active_ldap/configuration.rb replacing values to match what will work
72
+ # with your LDAP servers. Please note that those variables are required, but can
73
+ # be overridden in any program as detailed later in this document. Also make
74
+ # sure that "ROOT" stays all upcase.
75
+ #
76
+ # Now run:
77
+ #
78
+ # $ (as root) rake install
79
+ #
80
+ # Now as a quick test, you can run:
81
+ #
82
+ # $ irb
83
+ # irb> require 'active_ldap'
84
+ # => true
85
+ # irb> exit
86
+ #
87
+ # If the require returns false or an exception is raised, there has been a
88
+ # problem with the installation. You may need to customize what setup.rb does on
89
+ # install.
90
+ #
91
+ #
92
+ # === Customizations
93
+ #
94
+ # Now that Ruby/ActiveLdap is installed and working, we still have a few more
95
+ # steps to make it useful for programming.
96
+ #
97
+ # Let's say that you are writing a Ruby program for managing user and group
98
+ # accounts in LDAP. I will use this as the running example throughout the
99
+ # document.
100
+ #
101
+ # You will want to make a directory called 'ldapadmin' wherever is convenient. Under this directory,
102
+ # you'll want to make sure you have a 'lib' directory.
103
+ #
104
+ # $ cd ~
105
+ # $ mkdir ldapadmin
106
+ # $ cd ldapadmin
107
+ # $ mkdir lib
108
+ # $ cd lib
109
+ #
110
+ # The lib directory is where we'll be making customizations. You can, of course,
111
+ # make this changes somewhere in Ruby's default search path to make this
112
+ # accessible to every Ruby scripts. Enough of my babbling, I'm sure you'd like to
113
+ # know what we're going to put in lib/.
114
+ #
115
+ # We're going to put extension classes in there. What are extension classes you say . . .
116
+ #
117
+ #
118
+ # == Usage
119
+ #
120
+ # This section covers using Ruby/ActiveLdap from writing extension classes to
121
+ # writing applications that use them.
122
+ #
123
+ # Just to give a taste of what's to come, here is a quick example using irb:
124
+ #
125
+ # irb> require 'active_ldap'
126
+ #
127
+ # Here's an extension class that maps to the LDAP Group objects:
128
+ #
129
+ # irb> class Group < ActiveLdap::Base
130
+ # irb* ldap_mapping
131
+ # irb* end
132
+ #
133
+ # Here is the Group class in use:
134
+ #
135
+ # irb> all_groups = Group.find(:all, '*').collect {|group| group.cn}
136
+ # => ["root", "daemon", "bin", "sys", "adm", "tty", ..., "develop"]
137
+ #
138
+ # irb> group = Group.find("develop")
139
+ # => #<Group:0x..........>
140
+ #
141
+ # irb> group.members.collect {|member| member.uid}
142
+ # => ["drewry"]
143
+ #
144
+ # irb> group.cn
145
+ # => "develop"
146
+ #
147
+ # irb> group.gid_number
148
+ # => "1003"
149
+ #
150
+ # That's it! No let's get back in to it.
151
+ #
152
+ # === Extension Classes
153
+ #
154
+ # Extension classes are classes that are subclassed from ActiveLdap::Base. They
155
+ # are used to represent objects in your LDAP server abstractly.
156
+ #
157
+ # ==== Why do I need them?
158
+ #
159
+ # Extension classes are what make Ruby/ActiveLdap "active"! They do all the
160
+ # background work to make easy-to-use objects by mapping the LDAP object's
161
+ # attributes on to a Ruby class.
162
+ #
163
+ #
164
+ # ==== Special Methods
165
+ #
166
+ # I will briefly talk about each of the methods you can use when defining an
167
+ # extension class. In the above example, I only made one special method call
168
+ # inside the Group class. More than likely, you will want to more than that.
169
+ #
170
+ # ===== ldap_mapping
171
+ #
172
+ # ldap_mapping is the only required method to setup an extension class for use
173
+ # with Ruby/ActiveLdap. It must be called inside of a subclass as shown above.
174
+ #
175
+ # Below is a much more realistic Group class:
176
+ #
177
+ # class Group < ActiveLdap::Base
178
+ # ldap_mapping :dn_attribute => 'cn',
179
+ # :prefix => 'ou=Groups', :classes => ['top', 'posixGroup']
180
+ # :scope => :one
181
+ # end
182
+ #
183
+ # As you can see, this method is used for defining how this class maps in to LDAP. Let's say that
184
+ # my LDAP tree looks something like this:
185
+ #
186
+ # * dc=dataspill,dc=org
187
+ # |- ou=People,dc=dataspill,dc=org
188
+ # |+ ou=Groups,dc=dataspill,dc=org
189
+ # \
190
+ # |- cn=develop,ou=Groups,dc=dataspill,dc=org
191
+ # |- cn=root,ou=Groups,dc=dataspill,dc=org
192
+ # |- ...
193
+ #
194
+ # Under ou=People I store user objects, and under ou=Groups, I store group
195
+ # objects. What |ldap_mapping| has done is mapped the class in to the LDAP tree
196
+ # abstractly. With the given :dnattr and :prefix, it will only work for entries
197
+ # under ou=Groups,dc=dataspill,dc=org using the primary attribute 'cn' as the
198
+ # beginning of the distinguished name.
199
+ #
200
+ # Just for clarity, here's how the arguments map out:
201
+ #
202
+ # cn=develop,ou=Groups,dc=dataspill,dc=org
203
+ # ^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
204
+ # :dn_attribute | |
205
+ # :prefix |
206
+ # :base from configuration.rb
207
+ #
208
+ # :scope tells ActiveLdap to only search under ou=Groups, and not to look deeper
209
+ # for dnattr matches. (e.g. cn=develop,ou=DevGroups,ou=Groups,dc=dataspill,dc=org)
210
+ #
211
+ # Something's missing: :classes. :classes is used to tell Ruby/ActiveLdap what
212
+ # the minimum requirement is when creating a new object. LDAP uses objectClasses
213
+ # to define what attributes a LDAP object may have. Ruby/ActiveLdap needs to know
214
+ # what classes are required when creating a new object. Of course, you can leave
215
+ # that field out to default to ['top'] only. Then you can let each application
216
+ # choose what objectClasses their objects should have by calling the method e.g.
217
+ # Group#add_class(*values).
218
+ #
219
+ # Note that is can be very important to define the default :classes value. Due to
220
+ # implementation choices with most LDAP servers, once an object is created, its
221
+ # structural objectclasses may not be removed (or replaced). Setting a sane default
222
+ # may help avoid programmer error later.
223
+ #
224
+ # :classes isn't the only optional argument. If :dn_attribute is left off,
225
+ # it defaults to underscored class name or 'cn'. If :prefix is left off,
226
+ # it will default to 'ou=PLURALIZED_CLASSNAME'. In this
227
+ # case, it would be 'ou=Groups'.
228
+ #
229
+ # :classes should be an Array. :dn_attribute should be a String and so should
230
+ # :prefix.
231
+ #
232
+ #
233
+ # ===== belongs_to
234
+ #
235
+ # This method allows an extension class to make use of other extension classes
236
+ # tying objects together across the LDAP tree. Often, user objects will be
237
+ # members of, or belong_to, Group objects.
238
+ #
239
+ # * dc=dataspill,dc=org
240
+ # |+ ou=People,dc=dataspill,dc=org
241
+ # \
242
+ # |- uid=drewry,ou=People,dc=dataspill,dc=org
243
+ # |- ou=Groups,dc=dataspill,dc=org
244
+ #
245
+ #
246
+ # In the above tree, one such example would be user 'drewry' who is a part of the
247
+ # group 'develop'. You can see this by looking at the 'memberUid' field of 'develop'.
248
+ #
249
+ # irb> develop = Group.find('develop')
250
+ # => ...
251
+ # irb> develop.memberUid
252
+ # => ['drewry', 'builder']
253
+ #
254
+ # If we look at the LDAP entry for 'drewry', we do not see any references to
255
+ # group 'develop'. In order to remedy that, we can use belongs_to
256
+ #
257
+ # irb> class User < ActiveLdap::Base
258
+ # irb* ldap_mapping :dn_attribute => 'uid', :prefix => 'People', :classes => ['top','account']
259
+ # irb* belongs_to :groups, :class => 'Group', :many => 'memberUid', :foreign_key => 'uid'
260
+ # irb* end
261
+ #
262
+ # Now, class User will have a method called 'groups' which will retrieve all
263
+ # Group objects that a user is in.
264
+ #
265
+ # irb> me = User.find('drewry')
266
+ # irb> me.groups
267
+ # => [#<Group:0x000001 ...>, #<Group:0x000002 ...>, ...]
268
+ # irb> me.groups.each { |group| p group.cn };nil
269
+ # "cdrom"
270
+ # "audio"
271
+ # "develop"
272
+ # => nil
273
+ # (Note: nil is just there to make the output cleaner...)
274
+ #
275
+ # TIP: If you weren't sure what the distinguished name attribute was for Group,
276
+ # you could also do the following:
277
+ #
278
+ # irb> me.groups.each { |group| p group.id };nil
279
+ # "cdrom"
280
+ # "audio"
281
+ # "develop"
282
+ # => nil
283
+ #
284
+ # Now let's talk about the arguments. The first argument is the name of the
285
+ # method you wish to create. In this case, we created a method called groups
286
+ # using the symbol :groups. The next collection of arguments are actually a Hash
287
+ # (as with ldap_mapping). :class should be a string that has the name of a
288
+ # class you've already included. If you class is inside of a module, be sure to
289
+ # put the whole name, e.g. :class => "MyLdapModule::Group". :primary_key
290
+ # tells belongs_to what attribute Group objects have that match the
291
+ # :many. :many is the name of the local attribute whose value
292
+ # should be looked up in Group under the primary key. If :foreign_key is left
293
+ # off of the argument list, it is assumed to be the dn_attribute. With this in
294
+ # mind, the above definition could become:
295
+ #
296
+ # irb> class User < ActiveLdap::Base
297
+ # irb* ldap_mapping :dnattr => 'uid', :prefix => 'People', :classes => ['top','account']
298
+ # irb* belongs_to :groups, :class => 'Group', :many => 'memberUid'
299
+ # irb* end
300
+ #
301
+ # In addition, you can do simple membership tests by doing the following:
302
+ #
303
+ # irb> me.groups.member? 'root'
304
+ # => false
305
+ # irb> me.groups.member? 'develop'
306
+ # => true
307
+ #
308
+ # ===== has_many
309
+ #
310
+ # This method is the opposite of belongs_to. Instead of checking other objects in
311
+ # other parts of the LDAP tree to see if you belong to them, you have multiple
312
+ # objects from other trees listed in your object. To show this, we can just
313
+ # invert the example from above:
314
+ #
315
+ # class Group < ActiveLdap::Base
316
+ # ldap_mapping :dn_attribute => 'cn', :prefix => 'ou=Groups', :classes => ['top', 'posixGroup']
317
+ # has_many :members, :class => "User", :wrap => "memberUid", :primary_key => 'uid'
318
+ # end
319
+ #
320
+ # Now we can see that group develop has user 'drewry' as a member, and it can
321
+ # even return all responses in object form just like belongs_to methods.
322
+ #
323
+ # irb> develop = Group.find('develop')
324
+ # => ...
325
+ # irb> develop.members
326
+ # => [#<User:0x000001 ...>, #<User:...>]
327
+ #
328
+ #
329
+ # The arguments for has_many follow the exact same idea that belongs_to's
330
+ # arguments followed. :wrap's contents are used to search for matching
331
+ # :primary_key content. If :primary_key is not specified, it defaults to the
332
+ # dn_attribute of the specified :class.
333
+ #
334
+ # === Using these new classes
335
+ #
336
+ # These new classes have many method calls. Many of them are automatically
337
+ # generated to provide access to the LDAP object's attributes. Other were defined
338
+ # during class creation by special methods like belongs_to. There are a few other
339
+ # methods that do not fall in to these categories.
340
+ #
341
+ #
342
+ # ==== .find
343
+ #
344
+ # .find is a class method that is accessible from any subclass of Base that has
345
+ # 'ldap_mapping' called. When called it returns the first match of the given
346
+ # class.
347
+ #
348
+ # irb> Group.find('*').cn
349
+ # => "root"
350
+ #
351
+ # In this simple example, Group.find took the search string of 'deve*' and
352
+ # searched for the first match in Group where the dnattr matched the query. This
353
+ # is the simplest example of .find.
354
+ #
355
+ # irb> Group.find(:all, '*').collect {|group| group.cn}
356
+ # => ["root", "daemon", "bin", "sys", "adm", "tty", ..., "develop"]
357
+ #
358
+ # Here .find(:all) returns all matches to the same query. Both .find and
359
+ # .find(:all) also can take more expressive arguments:
360
+ #
361
+ # irb> Group.find(:all, :attribute => 'gidNumber', :value => '1003').collect {|group| group.cn}
362
+ # => ["develop"]
363
+ #
364
+ # So it is pretty clear what :attribute and :value do - they are used to query as
365
+ # :attribute=:value.
366
+ #
367
+ # If :attribute is unspecified, it defaults to the dn_attribute.
368
+ #
369
+ # It is also possible to override :attribute and :value by specifying :filter. This
370
+ # argument allows the direct specification of a LDAP filter to retrieve objects by.
371
+ #
372
+ # ==== .search
373
+ # .search is a class method that is accessible from any subclass of Base, and Base.
374
+ # It lets the user perform an arbitrary search against the current LDAP connection
375
+ # irrespetive of LDAP mapping data. This is meant to be useful as a utility method
376
+ # to cover 80% of the cases where a user would want to use Base.connection directly.
377
+ #
378
+ # irb> Base.search(:base => 'dc=example,dc=com', :filter => '(uid=roo*)',
379
+ # :scope => :sub, :attributes => ['uid', 'cn'])
380
+ # => [["uid=root,ou=People,dc=dataspill,dc=org",{"cn"=>["root"], "uidNumber"=>["0"]}]
381
+ # You can specify the :filter, :base, :scope, and :attributes, but they all have defaults --
382
+ # * :filter defaults to objectClass=* - usually this isn't what you want
383
+ # * :base defaults to the base of the class this is executed from (as set in ldap_mapping)
384
+ # * :scope defaults to :sub. Usually you won't need to change it
385
+ # * :attributes defaults to [] and is the list of attributes you want back. Empty means all of them.
386
+ #
387
+ # ==== #valid?
388
+ #
389
+ # valid? is a method that verifies that all attributes that are required by the
390
+ # objects current objectClasses are populated.
391
+ #
392
+ # ==== #save
393
+ #
394
+ # save is a method that writes any changes to an object back to the LDAP server.
395
+ # It automatically handles the addition of new objects, and the modification of
396
+ # existing ones.
397
+ #
398
+ # ==== .exists?
399
+ #
400
+ # exists? is a simple method which returns true is the current object exists in
401
+ # LDAP, or false if it does not.
402
+ #
403
+ # irb> User.exists?("dshadsadsa")
404
+ # => false
405
+ #
406
+ #
407
+ # === ActiveLdap::Base
408
+ #
409
+ # ActiveLdap::Base has come up a number of times in the examples above. Every
410
+ # time, it was being used as the super class for the wrapper objects. While this
411
+ # is it's main purpose, it also handles quite a bit more in the background.
412
+ #
413
+ # ==== What is it?
414
+ #
415
+ # ActiveLdap::Base is the heart of Ruby/ActiveLdap. It does all the schema
416
+ # parsing for validation and attribute-to-method mangling as well as manage the
417
+ # connection to LDAP.
418
+ #
419
+ # ===== establish_connection
420
+ #
421
+ # Base.establish_connection takes many (optional) arguments and is used to
422
+ # connect to the LDAP server. Sometimes you will want to connect anonymously
423
+ # and other times over TLS with user credentials. Base.establish_connection is
424
+ # here to do all of that for you.
425
+ #
426
+ #
427
+ # By default, if you call any subclass of Base, such as Group, it will call
428
+ # Base.establish_connection() if these is no active LDAP connection. If your
429
+ # server allows anonymous binding, and you only want to access data in a
430
+ # read-only fashion, you won't need to call Base.establish_connection. Here
431
+ # is a fully parameterized call:
432
+ #
433
+ # Base.establish_connection(
434
+ # :host => 'ldap.dataspill.org',
435
+ # :port => 389,
436
+ # :base => 'dc=dataspill,dc=org',
437
+ # :logger => log4r_obj,
438
+ # :bind_dn => "uid=drewry,ou=People,dc=dataspill,dc=org",
439
+ # :password_block => Proc.new { 'password12345' },
440
+ # :allow_anonymous => false,
441
+ # :try_sasl => false
442
+ # )
443
+ #
444
+ # There are quite a few arguments, but luckily many of them have safe defaults:
445
+ # * :host defaults to @@host from configuration.rb waaay back at the setup.rb stage.@
446
+ # * :port defaults to @@port from configuration.rb as well
447
+ # * :base defaults to Base.base() from configuration.rb
448
+ # * :bind_dn defaults @@bind_format from configuration.rb
449
+ # * :logger defaults to a Log4r object that prints fatal messages to stderr
450
+ # * :password_block defaults to nil
451
+ # * :allow_anonymous defaults to true
452
+ # * :try_sasl defaults to false - see Advanced Topics for more on this one.
453
+ #
454
+ #
455
+ # Most of these are obvious, but I'll step through them for completeness:
456
+ # * :host defines the LDAP server hostname to connect to.
457
+ # * :port defines the LDAP server port to connect to.
458
+ # * :method defines the type of connection - :tls, :ssl, :plain
459
+ # * :base specifies the LDAP search base to use with the prefixes defined in all
460
+ # subclasses.
461
+ # * :bind_dn specifies what your server expects when attempting to bind with
462
+ # credentials.
463
+ # * :logger accepts a custom log4r object to integrate with any other logging
464
+ # your application uses.
465
+ # * :password_block, if defined, give the Proc block for acquiring the password
466
+ # * :password, if defined, give the user's password as a String
467
+ # * :store_password indicates whether the password should be stored, or if used
468
+ # whether the :password_block should be called on each reconnect.
469
+ # * :allow_anonymous determines whether anonymous binding is allowed if other
470
+ # bind methods fail
471
+ # * :try_sasl, when true, tells ActiveLdap to attempt a SASL-GSSAPI bind
472
+ # * :sasl_quiet, when true, tells the SASL libraries to not spew messages to STDOUT
473
+ # * :method indicates whether to use :ssl, :tls, or :plain
474
+ # * :retries - indicates the number of attempts to reconnect that will be undertaken when a stale connection occurs. -1 means infinite.
475
+ # * :retry_wait - seconds to wait before retrying a connection
476
+ # * :scope - dictates how to find objects. (Default: :one)
477
+ # * :timeout - time in seconds - defaults to disabled. This CAN interrupt search() requests. Be warned.
478
+ # * :retry_on_timeout - whether to reconnect when timeouts occur. Defaults to true
479
+ # See lib/configuration.rb for defaults for each option
480
+ #
481
+ # Base.establish_connection both connects and binds in one step. It follows
482
+ # roughly the following approach:
483
+ #
484
+ # * Connect to host:port using :method
485
+ #
486
+ # * If bind_dn and password_block/password, attempt to bind with credentials.
487
+ # * If that fails or no password_block and anonymous allowed, attempt to bind
488
+ # anonymously.
489
+ # * If that fails, error out.
490
+ #
491
+ # On connect, the configuration options passed in are stored in an internal class variable
492
+ # @configuration which is used to cache the information without ditching the defaults passed in
493
+ # from configuration.rb
494
+ #
495
+ # ===== connection
496
+ #
497
+ # Base.connection returns the ActiveLdap::Connection object.
498
+ #
499
+ # === Exceptions
500
+ #
501
+ # There are a few custom exceptions used in Ruby/ActiveLdap. They are detailed below.
502
+ #
503
+ # ==== DeleteError
504
+ #
505
+ # This exception is raised when #delete fails. It will include LDAP error
506
+ # information that was passed up during the error.
507
+ #
508
+ # ==== SaveError
509
+ #
510
+ # This exception is raised when there is a problem in #save updating or creating
511
+ # an LDAP entry. Often the error messages are cryptic. Looking at the server
512
+ # logs or doing an Ethereal[http://www.ethereal.com] dump of the connection will
513
+ # often provide better insight.
514
+ #
515
+ # ==== AuthenticationError
516
+ #
517
+ # This exception is raised during Base.establish_connection if no valid authentication methods
518
+ # succeeded.
519
+ #
520
+ # ==== ConnectionError
521
+ #
522
+ # This exception is raised during Base.establish_connection if no valid
523
+ # connection to the LDAP server could be created. Check you configuration.rb,
524
+ # Base.establish_connection arguments, and network connectivity! Also check
525
+ # your LDAP server logs to see if it ever saw the request.
526
+ #
527
+ # ==== ObjectClassError
528
+ #
529
+ # This exception is raised when an object class is used that is not defined
530
+ # in the schema.
531
+ #
532
+ # === Others
533
+ #
534
+ # Other exceptions may be raised by the Ruby/LDAP module, or by other subsystems.
535
+ # If you get one of these exceptions and think it should be wrapped, write me an
536
+ # email and let me know where it is and what you expected. For faster results,
537
+ # email a patch!
538
+ #
539
+ # === Putting it all together
540
+ #
541
+ # Now that all of the components of Ruby/ActiveLdap have been covered, it's time
542
+ # to put it all together! The rest of this section will show the steps to setup
543
+ # example user and group management scripts for use with the LDAP tree described
544
+ # above.
545
+ #
546
+ # All of the scripts here are in the package's examples/ directory.
547
+ #
548
+ # ==== Setting up lib/
549
+ #
550
+ # In ldapadmin/lib/ create the file user.rb:
551
+ # cat <<EOF
552
+ # class User < ActiveLdap::Base
553
+ # ldap_mapping :dn_attribute => 'uid', :prefix => 'ou=People', :classes => ['top', 'account', 'posixAccount']
554
+ # belongs_to :groups, :class => 'Group', :wrap => 'memberUid'
555
+ # end
556
+ # EOF
557
+ #
558
+ # In ldapadmin/lib/ create the file group.rb:
559
+ # cat <<EOF
560
+ # class Group < ActiveLdap::Base
561
+ # ldap_mapping :classes => ['top', 'posixGroup'], :prefix => 'ou=Group'
562
+ # has_many :members, :class => "User", :many => "memberUid"
563
+ # has_many :primary_members, :class => 'User', :foreign_key => 'gidNumber', :primary_key => 'gidNumber'
564
+ # end # Group
565
+ # EOF
566
+ #
567
+ # Now, we can write some small scripts to do simple management tasks.
568
+ #
569
+ # ==== Creating LDAP entries
570
+ #
571
+ # Now let's create a really dumb script for adding users - ldapadmin/useradd:
572
+ #
573
+ # #!/usr/bin/ruby -W0
574
+ #
575
+ # require 'active_ldap'
576
+ # require 'lib/user'
577
+ # require 'lib/group'
578
+ # require 'password'
579
+ #
580
+ # argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
581
+ # opts.banner += " USER_NAME CN UID"
582
+ # end
583
+ #
584
+ # if argv.size == 3
585
+ # name, cn, uid = argv
586
+ # else
587
+ # $stderr.puts opts
588
+ # exit 1
589
+ # end
590
+ #
591
+ # pwb = Proc.new do |user|
592
+ # ActiveLdap::Command.read_password("[#{user}] Password: ")
593
+ # end
594
+ #
595
+ # ActiveLdap::Base.establish_connection(:password_block => pwb,
596
+ # :allow_anonymous => false)
597
+ #
598
+ # if User.exists?(name)
599
+ # $stderr.puts("User #{name} already exists.")
600
+ # exit 1
601
+ # end
602
+ #
603
+ # user = User.new(name)
604
+ # user.add_class('shadowAccount')
605
+ # user.cn = cn
606
+ # user.uid_number = uid
607
+ # user.gid_number = uid
608
+ # user.home_directory = "/home/#{name}"
609
+ # user.sn = "somesn"
610
+ # unless user.save
611
+ # puts "failed"
612
+ # puts user.errors.full_messages
613
+ # exit 1
614
+ # end
615
+ #
616
+ # ==== Managing LDAP entries
617
+ #
618
+ # Now let's create another dumb script for modifying users - ldapadmin/usermod:
619
+ #
620
+ # #!/usr/bin/ruby -W0
621
+ #
622
+ # require 'active_ldap'
623
+ # require 'lib/user'
624
+ # require 'lib/group'
625
+ #
626
+ # argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
627
+ # opts.banner += " USER_NAME CN UID"
628
+ # end
629
+ #
630
+ # if argv.size == 3
631
+ # name, cn, uid = argv
632
+ # else
633
+ # $stderr.puts opts
634
+ # exit 1
635
+ # end
636
+ #
637
+ # pwb = Proc.new do |user|
638
+ # ActiveLdap::Command.read_password("[#{user}] Password: ")
639
+ # end
640
+ #
641
+ # ActiveLdap::Base.establish_connection(:password_block => pwb,
642
+ # :allow_anonymous => false)
643
+ #
644
+ # unless User.exists?(name)
645
+ # $stderr.puts("User #{name} doesn't exist.")
646
+ # exit 1
647
+ # end
648
+ #
649
+ # user = User.find(name)
650
+ # user.cn = cn
651
+ # user.uid_number = uid
652
+ # user.gid_number = uid
653
+ # unless user.save
654
+ # puts "failed"
655
+ # puts user.errors.full_messages
656
+ # exit 1
657
+ # end
658
+ #
659
+ # ==== Removing LDAP entries
660
+ #
661
+ # And finally, a dumb script for removing user - ldapadmin/userdel:
662
+ #
663
+ #
664
+ # #!/usr/bin/ruby -W0
665
+ #
666
+ # require 'active_ldap'
667
+ # require 'lib/user'
668
+ # require 'lib/group'
669
+ #
670
+ # argv, opts, options = ActiveLdap::Command.parse_options do |opts, options|
671
+ # opts.banner += " USER_NAME"
672
+ # end
673
+ #
674
+ # if argv.size == 1
675
+ # name = argv.shift
676
+ # else
677
+ # $stderr.puts opts
678
+ # exit 1
679
+ # end
680
+ #
681
+ # pwb = Proc.new do |user|
682
+ # ActiveLdap::Command.read_password("[#{user}] Password: ")
683
+ # end
684
+ #
685
+ # ActiveLdap::Base.establish_connection(:password_block => pwb,
686
+ # :allow_anonymous => false)
687
+ #
688
+ # unless User.exists?(name)
689
+ # $stderr.puts("User #{name} doesn't exist.")
690
+ # exit 1
691
+ # end
692
+ #
693
+ # User.destroy(name)
694
+ #
695
+ # === Advanced Topics
696
+ #
697
+ # Below are some situation tips and tricks to get the most out of Ruby/ActiveLdap.
698
+ #
699
+ #
700
+ # ==== Binary data and other subtypes
701
+ #
702
+ # Sometimes, you may want to store attributes with language specifiers, or
703
+ # perhaps in binary form. This is (finally!) fully supported. To do so,
704
+ # follow the examples below:
705
+ #
706
+ # irb> user = User.new('drewry')
707
+ # => ...
708
+ # # This adds a cn entry in lang-en and whatever the server default is.
709
+ # irb> user.cn = [ 'wad', {'lang-en' => ['wad', 'foo']} ]
710
+ # => ...
711
+ # irb> user.cn
712
+ # => ["wad", {"lang-en-us" => ["wad", "Will Drewry"]}]
713
+ # # Now let's add a binary X.509 certificate (assume objectClass is correct)
714
+ # irb> user.user_certificate = File.read('example.der')
715
+ # => ...
716
+ # irb> user.save
717
+ #
718
+ # So that's a lot to take in. Here's what is going on. I just set the LDAP
719
+ # object's cn to "wad" and cn:lang-en-us to ["wad", "Will Drewry"].
720
+ # Anytime a LDAP subtype is required, you must encapsulate the data in a Hash.
721
+ #
722
+ # But wait a minute, I just read in a binary certificate without wrapping it up.
723
+ # So any binary attribute _that requires ;binary subtyping_ will automagically
724
+ # get wrapped in {'binary' => value} if you don't do it. This keeps your #writes
725
+ # from breaking, and my code from crying. For correctness, I could have easily
726
+ # done the following:
727
+ #
728
+ # irb> user.user_certificate = {'binary' => File.read('example.der')}
729
+ #
730
+ # You should note that some binary data does not use the binary subtype all the time.
731
+ # One example is jpegPhoto. You can use it as jpegPhoto;binary or just as jpegPhoto.
732
+ # Since the schema dictates that it is a binary value, Ruby/ActiveLdap will write
733
+ # it as binary, but the subtype will not be automatically appended as above. The
734
+ # use of the subtype on attributes like jpegPhoto is ultimately decided by the
735
+ # LDAP site policy and not by any programmatic means.
736
+ #
737
+ # The only subtypes defined in LDAPv3 are lang-* and binary. These can be nested
738
+ # though:
739
+ #
740
+ # irb> user.cn = [{'lang-JP-jp' => {'binary' => 'somejp'}}]
741
+ #
742
+ # As I understand it, OpenLDAP does not support nested subtypes, but some
743
+ # documentation I've read suggests that Netscape's LDAP server does. I only
744
+ # have access to OpenLDAP. If anyone tests this out, please let me know how it
745
+ # goes!
746
+ #
747
+ #
748
+ # And that pretty much wraps up this section.
749
+ #
750
+ # ==== Further integration with your environment aka namespacing
751
+ #
752
+ # If you want this to cleanly integrate into your system-wide Ruby include path,
753
+ # you should put your extension classes inside a custom module.
754
+ #
755
+ #
756
+ # Example:
757
+ #
758
+ # ./myldap.rb:
759
+ # require 'active_ldap'
760
+ # require 'myldap/user'
761
+ # require 'myldap/group'
762
+ # module MyLDAP
763
+ # end
764
+ #
765
+ # ./myldap/user.rb:
766
+ # module MyLDAP
767
+ # class User < ActiveLdap::Base
768
+ # ldap_mapping :dn_attribute => 'uid', :prefix => 'ou=People', :classes => ['top', 'account', 'posixAccount']
769
+ # belongs_to :groups, :class => 'MyLDAP::Group', :many => 'memberUid'
770
+ # end
771
+ # end
772
+ #
773
+ # ./myldap/group.rb:
774
+ # module MyLDAP
775
+ # class Group < ActiveLdap::Base
776
+ # ldap_mapping :classes => ['top', 'posixGroup'], :prefix => 'ou=Group'
777
+ # has_many :members, :class => 'MyLDAP::User', :wrap => 'memberUid'
778
+ # has_many :primary_members, :class => 'MyLDAP::User', :foreign_key => 'gidNumber', :primary_key => 'gidNumber'
779
+ # end
780
+ # end
781
+ #
782
+ # Now in your local applications, you can call
783
+ #
784
+ # require 'myldap'
785
+ #
786
+ # MyLDAP::Group.new('foo')
787
+ # ...
788
+ #
789
+ # and everything should work well.
790
+ #
791
+ #
792
+ # ==== force array results for single values
793
+ #
794
+ # Even though Ruby/ActiveLdap attempts to maintain programmatic ease by
795
+ # returning Array values only. By specifying 'true' as an argument to
796
+ # any attribute method you will get back a Array if it is single value.
797
+ # Here's an example:
798
+ #
799
+ # irb> user = User.new('drewry')
800
+ # => ...
801
+ # irb> user.cn(true)
802
+ # => ["Will Drewry"]
803
+ #
804
+ # ==== Dynamic attribute crawling
805
+ #
806
+ # If you use tab completion in irb, you'll notice that you /can/ tab complete the dynamic
807
+ # attribute methods. You can still see which methods are for attributes using
808
+ # Base#attribute_names:
809
+ #
810
+ # irb> d = Group.new('develop')
811
+ # => ...
812
+ # irb> d.attribute_names
813
+ # => ["gidNumber", "cn", "memberUid", "commonName", "description", "userPassword", "objectClass"]
814
+ #
815
+ #
816
+ # ==== Juggling multiple LDAP connections
817
+ #
818
+ # In the same vein as the last tip, you can use multiple LDAP connections by
819
+ # per class as follows:
820
+ #
821
+ # irb> anon_class = Class.new(Base)
822
+ # => ...
823
+ # irb> anon_class.establish_connection
824
+ # => ...
825
+ # irb> auth_class = Class.new(Base)
826
+ # => ...
827
+ # irb> auth_class.establish_connection(:password_block => {'mypass'})
828
+ # => ...
829
+ #
830
+ # This can be useful for doing authentication tests and other such tricks.
831
+ #
832
+ # ==== :try_sasl
833
+ #
834
+ # If you have the Ruby/LDAP package with the SASL/GSSAPI patch from Ian
835
+ # MacDonald's web site, you can use Kerberos to bind to your LDAP server. By
836
+ # default, :try_sasl is false.
837
+ #
838
+ # Also note that you must be using OpenLDAP 2.1.29 or higher to use SASL/GSSAPI
839
+ # due to some bugs in older versions of OpenLDAP.
840
+ #
841
+ # ==== Don't be afraid! [Internals]
842
+ #
843
+ # Don't be afraid to add more methods to the extensions classes and to
844
+ # experiment. That's exactly how I ended up with this package. If you come up
845
+ # with something cool, please share it!
846
+ #
847
+ # The internal structure of ActiveLdap::Base, and thus all its subclasses, is
848
+ # still in flux. I've tried to minimize the changes to the overall API, but
849
+ # the internals are still rough around the edges.
850
+ #
851
+ # ===== Where's ldap_mapping data stored? How can I get to it?
852
+ #
853
+ # When you call ldap_mapping, it overwrites several class methods inherited
854
+ # from Base:
855
+ # * Base.base()
856
+ # * Base.required_classes()
857
+ # * Base.dn_attribute()
858
+ # You can access these from custom class methods by calling MyClass.base(),
859
+ # or whatever. There are predefined instance methods for getting to these
860
+ # from any new instance methods you define:
861
+ # * Base#base()
862
+ # * Base#required_classes()
863
+ # * Base#dn_attribute()
864
+ #
865
+ # ===== What else?
866
+ #
867
+ # Well if you want to use the LDAP connection for anything, I'd suggest still
868
+ # calling Base.connection to get it. There really aren't many other internals
869
+ # that need to be worried about. You could get the LDAP schema with
870
+ # Base.schema.
871
+ #
872
+ # The only other useful tricks are dereferencing and accessing the stored
873
+ # data. Since LDAP attributes can have multiple names, e.g. cn or commonName,
874
+ # any methods you write might need to figure it out. I'd suggest just
875
+ # calling self[attribname] to get the value, but if that's not good enough,
876
+ # you can call look up the stored name by #to_real_attribute_name as follows:
877
+ # irb> to_real_attribute_name('commonName')
878
+ # => 'cn'
879
+ #
880
+ # This tells you the name the attribute is stored in behind the scenes (@data).
881
+ # Again, self[attribname] should be enough for most extensions, but if not,
882
+ # it's probably safe to dabble here.
883
+ #
884
+ # Also, if you like to look up all aliases for an attribute, you can call the
885
+ # following:
886
+ #
887
+ # irb> schema.attribute_aliases('cn')
888
+ # => ['cn','commonName']
889
+ #
890
+ # This is discovered automagically from the LDAP server's schema.
891
+ #
892
+ # == Limitations
893
+ #
894
+ # === Speed
895
+ #
896
+ # Currently, Ruby/ActiveLdap could be faster. I have some recursive type
897
+ # checking going on which slows object creation down, and I'm sure there
898
+ # are many, many other places optimizations can be done. Feel free
899
+ # to send patches, or just hang in there until I can optimize away the
900
+ # slowness.
901
+ #
902
+ # == Feedback
903
+ #
904
+ # Any and all feedback and patches are welcome. I am very excited about this
905
+ # package, and I'd like to see it prove helpful to more people than just myself.
906
+ #
907
+
908
+ require_gem_if_need = Proc.new do |library_name, gem_name|
909
+ begin
910
+ require library_name
911
+ rescue LoadError
912
+ require 'rubygems'
913
+ gem gem_name
914
+ require library_name
915
+ end
916
+ end
917
+
918
+ require_gem_if_need.call("active_support", "activesupport")
919
+
920
+ if Dependencies.respond_to?(:load_paths)
921
+ Dependencies.load_paths << File.expand_path(File.dirname(__FILE__))
922
+ end
923
+
924
+ module ActiveLdap
925
+ VERSION = "0.8.3.1"
926
+ end
927
+
928
+ if RUBY_PLATFORM.match('linux')
929
+ require 'active_ldap/timeout'
930
+ else
931
+ require 'active_ldap/timeout_stub'
932
+ end
933
+
934
+ require_gem_if_need.call("active_record/base", "activerecord")
935
+ begin
936
+ require_gem_if_need.call("gettext/active_record", "gettext")
937
+ ActiveLdap.const_set("GetText", GetText)
938
+ rescue LoadError
939
+ require 'active_ldap/get_text_fallback'
940
+ end
941
+
942
+ require 'active_ldap/get_text_support'
943
+
944
+ require 'active_ldap/base'
945
+ require 'active_ldap/associations'
946
+ require 'active_ldap/configuration'
947
+ require 'active_ldap/connection'
948
+ require 'active_ldap/operations'
949
+ require 'active_ldap/attributes'
950
+ require 'active_ldap/object_class'
951
+ require 'active_ldap/distinguished_name'
952
+
953
+ require 'active_ldap/populate'
954
+ require 'active_ldap/escape'
955
+ require 'active_ldap/helper'
956
+
957
+ require 'active_ldap/validations'
958
+ require 'active_ldap/callbacks'
959
+
960
+
961
+ ActiveLdap::Base.class_eval do
962
+ include ActiveLdap::Configuration
963
+ include ActiveLdap::Connection
964
+ include ActiveLdap::Operations
965
+ include ActiveLdap::Attributes
966
+ include ActiveLdap::ObjectClass
967
+ include ActiveLdap::Associations
968
+ include ActiveLdap::Validations
969
+ include ActiveLdap::Callbacks
970
+ end
971
+
972
+ unless defined?(ACTIVE_LDAP_CONNECTION_ADAPTERS)
973
+ ACTIVE_LDAP_CONNECTION_ADAPTERS = %w(ldap net_ldap)
974
+ end
975
+
976
+ ACTIVE_LDAP_CONNECTION_ADAPTERS.each do |adapter|
977
+ require "active_ldap/adapter/#{adapter}"
978
+ end