activeldap3 1.2.3

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.
Files changed (443) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGES +691 -0
  3. data/COPYING +340 -0
  4. data/LICENSE +58 -0
  5. data/README +154 -0
  6. data/Rakefile +121 -0
  7. data/TODO +32 -0
  8. data/activeldap3.gemspec +18 -0
  9. data/benchmark/bench-al.rb +263 -0
  10. data/benchmark/config.yaml.sample +5 -0
  11. data/examples/al-admin/README +182 -0
  12. data/examples/al-admin/Rakefile +16 -0
  13. data/examples/al-admin/app/controllers/account_controller.rb +60 -0
  14. data/examples/al-admin/app/controllers/application_controller.rb +46 -0
  15. data/examples/al-admin/app/controllers/attributes_controller.rb +17 -0
  16. data/examples/al-admin/app/controllers/directory_controller.rb +49 -0
  17. data/examples/al-admin/app/controllers/object_classes_controller.rb +17 -0
  18. data/examples/al-admin/app/controllers/syntaxes_controller.rb +17 -0
  19. data/examples/al-admin/app/controllers/users_controller.rb +66 -0
  20. data/examples/al-admin/app/controllers/welcome_controller.rb +12 -0
  21. data/examples/al-admin/app/helpers/account_helper.rb +2 -0
  22. data/examples/al-admin/app/helpers/application_helper.rb +46 -0
  23. data/examples/al-admin/app/helpers/attributes_helper.rb +15 -0
  24. data/examples/al-admin/app/helpers/directory_helper.rb +7 -0
  25. data/examples/al-admin/app/helpers/object_classes_helper.rb +10 -0
  26. data/examples/al-admin/app/helpers/syntaxes_helper.rb +10 -0
  27. data/examples/al-admin/app/helpers/url_helper.rb +17 -0
  28. data/examples/al-admin/app/helpers/users_helper.rb +17 -0
  29. data/examples/al-admin/app/helpers/welcome_helper.rb +2 -0
  30. data/examples/al-admin/app/models/entry.rb +23 -0
  31. data/examples/al-admin/app/models/ldap_user.rb +58 -0
  32. data/examples/al-admin/app/models/user.rb +91 -0
  33. data/examples/al-admin/app/views/_entry/_attributes_information.html.erb +29 -0
  34. data/examples/al-admin/app/views/_entry/_entry.html.erb +15 -0
  35. data/examples/al-admin/app/views/_schema/_aliases.html.erb +7 -0
  36. data/examples/al-admin/app/views/_switcher/_after.html.erb +2 -0
  37. data/examples/al-admin/app/views/_switcher/_before.html.erb +5 -0
  38. data/examples/al-admin/app/views/account/login.html.erb +26 -0
  39. data/examples/al-admin/app/views/account/sign_up.html.erb +29 -0
  40. data/examples/al-admin/app/views/attributes/_attributes.html.erb +19 -0
  41. data/examples/al-admin/app/views/attributes/_detail.html.erb +29 -0
  42. data/examples/al-admin/app/views/attributes/index.html.erb +3 -0
  43. data/examples/al-admin/app/views/attributes/show.html.erb +31 -0
  44. data/examples/al-admin/app/views/directory/_tree.html.erb +10 -0
  45. data/examples/al-admin/app/views/directory/_tree_view_js.html.erb +25 -0
  46. data/examples/al-admin/app/views/directory/index.html.erb +13 -0
  47. data/examples/al-admin/app/views/directory/populate.html.erb +2 -0
  48. data/examples/al-admin/app/views/layouts/_footer.html.erb +11 -0
  49. data/examples/al-admin/app/views/layouts/_header_menu.html.erb +10 -0
  50. data/examples/al-admin/app/views/layouts/_main_menu.html.erb +18 -0
  51. data/examples/al-admin/app/views/layouts/application.html.erb +57 -0
  52. data/examples/al-admin/app/views/object_classes/_attributes.html.erb +28 -0
  53. data/examples/al-admin/app/views/object_classes/_object_classes.html.erb +19 -0
  54. data/examples/al-admin/app/views/object_classes/index.html.erb +3 -0
  55. data/examples/al-admin/app/views/object_classes/show.html.erb +39 -0
  56. data/examples/al-admin/app/views/syntaxes/_detail.html.erb +14 -0
  57. data/examples/al-admin/app/views/syntaxes/_syntaxes.html.erb +19 -0
  58. data/examples/al-admin/app/views/syntaxes/index.html.erb +3 -0
  59. data/examples/al-admin/app/views/syntaxes/show.html.erb +22 -0
  60. data/examples/al-admin/app/views/users/_attributes_update_form.html.erb +42 -0
  61. data/examples/al-admin/app/views/users/_form.html.erb +13 -0
  62. data/examples/al-admin/app/views/users/_object_classes_update_form.html.erb +46 -0
  63. data/examples/al-admin/app/views/users/_password_change_form.html.erb +20 -0
  64. data/examples/al-admin/app/views/users/edit.html.erb +15 -0
  65. data/examples/al-admin/app/views/users/index.html.erb +10 -0
  66. data/examples/al-admin/app/views/users/show.html.erb +11 -0
  67. data/examples/al-admin/app/views/welcome/index.html.erb +13 -0
  68. data/examples/al-admin/config.ru +7 -0
  69. data/examples/al-admin/config/boot.rb +110 -0
  70. data/examples/al-admin/config/database.yml.example +19 -0
  71. data/examples/al-admin/config/environment.rb +73 -0
  72. data/examples/al-admin/config/environments/development.rb +17 -0
  73. data/examples/al-admin/config/environments/production.rb +24 -0
  74. data/examples/al-admin/config/environments/test.rb +22 -0
  75. data/examples/al-admin/config/initializers/exception_notifier.rb +2 -0
  76. data/examples/al-admin/config/initializers/fast_gettext.rb +3 -0
  77. data/examples/al-admin/config/initializers/inflections.rb +10 -0
  78. data/examples/al-admin/config/initializers/mime_types.rb +5 -0
  79. data/examples/al-admin/config/initializers/session_store.rb +23 -0
  80. data/examples/al-admin/config/ldap.yml.example +21 -0
  81. data/examples/al-admin/config/routes.rb +58 -0
  82. data/examples/al-admin/db/migrate/001_create_users.rb +16 -0
  83. data/examples/al-admin/doc/README_FOR_APP +2 -0
  84. data/examples/al-admin/lib/authenticated_system.rb +124 -0
  85. data/examples/al-admin/lib/authenticated_test_helper.rb +113 -0
  86. data/examples/al-admin/lib/ldap_test_helper.rb +38 -0
  87. data/examples/al-admin/lib/tasks/testing.rake +10 -0
  88. data/examples/al-admin/po/en/al-admin.po +343 -0
  89. data/examples/al-admin/po/ja/al-admin.po +343 -0
  90. data/examples/al-admin/po/nl/al-admin.po +380 -0
  91. data/examples/al-admin/public/.htaccess +40 -0
  92. data/examples/al-admin/public/404.html +30 -0
  93. data/examples/al-admin/public/500.html +30 -0
  94. data/examples/al-admin/public/dispatch.cgi +10 -0
  95. data/examples/al-admin/public/dispatch.fcgi +24 -0
  96. data/examples/al-admin/public/dispatch.rb +10 -0
  97. data/examples/al-admin/public/favicon.ico +0 -0
  98. data/examples/al-admin/public/images/active-ldap.svg +6351 -0
  99. data/examples/al-admin/public/images/al-admin.png +0 -0
  100. data/examples/al-admin/public/images/al-admin.svg +6371 -0
  101. data/examples/al-admin/public/images/header-background.png +0 -0
  102. data/examples/al-admin/public/images/header-background.svg +99 -0
  103. data/examples/al-admin/public/images/rails.png +0 -0
  104. data/examples/al-admin/public/images/spinelz/accordion_tab_left_active.gif +0 -0
  105. data/examples/al-admin/public/images/spinelz/accordion_tab_left_inactive.gif +0 -0
  106. data/examples/al-admin/public/images/spinelz/accordion_tab_middle_active.gif +0 -0
  107. data/examples/al-admin/public/images/spinelz/accordion_tab_middle_inactive.gif +0 -0
  108. data/examples/al-admin/public/images/spinelz/accordion_tab_right_active.gif +0 -0
  109. data/examples/al-admin/public/images/spinelz/accordion_tab_right_inactive.gif +0 -0
  110. data/examples/al-admin/public/images/spinelz/balloon_back.gif +0 -0
  111. data/examples/al-admin/public/images/spinelz/balloon_bottom_left.gif +0 -0
  112. data/examples/al-admin/public/images/spinelz/balloon_bottom_middle.gif +0 -0
  113. data/examples/al-admin/public/images/spinelz/balloon_bottom_right.gif +0 -0
  114. data/examples/al-admin/public/images/spinelz/balloon_left_down_arrow.gif +0 -0
  115. data/examples/al-admin/public/images/spinelz/balloon_left_up_arrow.gif +0 -0
  116. data/examples/al-admin/public/images/spinelz/balloon_middle_left.gif +0 -0
  117. data/examples/al-admin/public/images/spinelz/balloon_middle_right.gif +0 -0
  118. data/examples/al-admin/public/images/spinelz/balloon_right_down_arrow.gif +0 -0
  119. data/examples/al-admin/public/images/spinelz/balloon_right_up_arrow.gif +0 -0
  120. data/examples/al-admin/public/images/spinelz/balloon_top_left.gif +0 -0
  121. data/examples/al-admin/public/images/spinelz/balloon_top_middle.gif +0 -0
  122. data/examples/al-admin/public/images/spinelz/balloon_top_right.gif +0 -0
  123. data/examples/al-admin/public/images/spinelz/barchart_h.gif +0 -0
  124. data/examples/al-admin/public/images/spinelz/barchart_v.gif +0 -0
  125. data/examples/al-admin/public/images/spinelz/button.gif +0 -0
  126. data/examples/al-admin/public/images/spinelz/calendar_default_handler.gif +0 -0
  127. data/examples/al-admin/public/images/spinelz/calendar_delete.gif +0 -0
  128. data/examples/al-admin/public/images/spinelz/calendar_next.gif +0 -0
  129. data/examples/al-admin/public/images/spinelz/calendar_next_second.gif +0 -0
  130. data/examples/al-admin/public/images/spinelz/calendar_pre.gif +0 -0
  131. data/examples/al-admin/public/images/spinelz/calendar_pre_second.gif +0 -0
  132. data/examples/al-admin/public/images/spinelz/calendar_private_icon.gif +0 -0
  133. data/examples/al-admin/public/images/spinelz/calendar_schedule.gif +0 -0
  134. data/examples/al-admin/public/images/spinelz/calender_back.gif +0 -0
  135. data/examples/al-admin/public/images/spinelz/calender_back_second.gif +0 -0
  136. data/examples/al-admin/public/images/spinelz/datepicker2_back.gif +0 -0
  137. data/examples/al-admin/public/images/spinelz/datepicker2_back_second.gif +0 -0
  138. data/examples/al-admin/public/images/spinelz/datepicker2_next.gif +0 -0
  139. data/examples/al-admin/public/images/spinelz/datepicker2_next_second.gif +0 -0
  140. data/examples/al-admin/public/images/spinelz/datepicker2_pre.gif +0 -0
  141. data/examples/al-admin/public/images/spinelz/datepicker2_pre_second.gif +0 -0
  142. data/examples/al-admin/public/images/spinelz/datepicker_back.gif +0 -0
  143. data/examples/al-admin/public/images/spinelz/datepicker_back_second.gif +0 -0
  144. data/examples/al-admin/public/images/spinelz/datepicker_next.gif +0 -0
  145. data/examples/al-admin/public/images/spinelz/datepicker_next_second.gif +0 -0
  146. data/examples/al-admin/public/images/spinelz/datepicker_pre.gif +0 -0
  147. data/examples/al-admin/public/images/spinelz/datepicker_pre_second.gif +0 -0
  148. data/examples/al-admin/public/images/spinelz/grid_down.gif +0 -0
  149. data/examples/al-admin/public/images/spinelz/grid_state.gif +0 -0
  150. data/examples/al-admin/public/images/spinelz/grid_up.gif +0 -0
  151. data/examples/al-admin/public/images/spinelz/icon_day.gif +0 -0
  152. data/examples/al-admin/public/images/spinelz/icon_month.gif +0 -0
  153. data/examples/al-admin/public/images/spinelz/icon_week.gif +0 -0
  154. data/examples/al-admin/public/images/spinelz/menubar_back.gif +0 -0
  155. data/examples/al-admin/public/images/spinelz/menubar_subcontents_back.gif +0 -0
  156. data/examples/al-admin/public/images/spinelz/navPanel_tab_left_active.gif +0 -0
  157. data/examples/al-admin/public/images/spinelz/navPanel_tab_left_inactive.gif +0 -0
  158. data/examples/al-admin/public/images/spinelz/navPanel_tab_middle_active.gif +0 -0
  159. data/examples/al-admin/public/images/spinelz/navPanel_tab_middle_inactive.gif +0 -0
  160. data/examples/al-admin/public/images/spinelz/navPanel_tab_right_active.gif +0 -0
  161. data/examples/al-admin/public/images/spinelz/navPanel_tab_right_inactive.gif +0 -0
  162. data/examples/al-admin/public/images/spinelz/select_date.gif +0 -0
  163. data/examples/al-admin/public/images/spinelz/selectabletable_selected.gif +0 -0
  164. data/examples/al-admin/public/images/spinelz/sideBarBox_about.gif +0 -0
  165. data/examples/al-admin/public/images/spinelz/sideBarBox_menu.gif +0 -0
  166. data/examples/al-admin/public/images/spinelz/sideBarBox_sample.gif +0 -0
  167. data/examples/al-admin/public/images/spinelz/sideBarBox_tabBottomActive.gif +0 -0
  168. data/examples/al-admin/public/images/spinelz/sideBarBox_tabBottomInactive.gif +0 -0
  169. data/examples/al-admin/public/images/spinelz/sideBarBox_tabMiddleActive.gif +0 -0
  170. data/examples/al-admin/public/images/spinelz/sideBarBox_tabMiddleActive2.gif +0 -0
  171. data/examples/al-admin/public/images/spinelz/sideBarBox_tabMiddleInactive.gif +0 -0
  172. data/examples/al-admin/public/images/spinelz/sideBarBox_tabMiddleInactive2.gif +0 -0
  173. data/examples/al-admin/public/images/spinelz/sideBarBox_tabTopActive.gif +0 -0
  174. data/examples/al-admin/public/images/spinelz/sideBarBox_tabTopInactive.gif +0 -0
  175. data/examples/al-admin/public/images/spinelz/sideBarBox_tabbar.gif +0 -0
  176. data/examples/al-admin/public/images/spinelz/sortableTable_down.gif +0 -0
  177. data/examples/al-admin/public/images/spinelz/sortableTable_normal.gif +0 -0
  178. data/examples/al-admin/public/images/spinelz/sortableTable_up.gif +0 -0
  179. data/examples/al-admin/public/images/spinelz/switcher_close.gif +0 -0
  180. data/examples/al-admin/public/images/spinelz/switcher_open.gif +0 -0
  181. data/examples/al-admin/public/images/spinelz/tabBox_close.gif +0 -0
  182. data/examples/al-admin/public/images/spinelz/tabBox_tabLeftActive.gif +0 -0
  183. data/examples/al-admin/public/images/spinelz/tabBox_tabLeftInactive.gif +0 -0
  184. data/examples/al-admin/public/images/spinelz/tabBox_tabMiddleActive.gif +0 -0
  185. data/examples/al-admin/public/images/spinelz/tabBox_tabMiddleInactive.gif +0 -0
  186. data/examples/al-admin/public/images/spinelz/tabBox_tabRightActive.gif +0 -0
  187. data/examples/al-admin/public/images/spinelz/tabBox_tabRightInactive.gif +0 -0
  188. data/examples/al-admin/public/images/spinelz/tab_bar.gif +0 -0
  189. data/examples/al-admin/public/images/spinelz/table_back.gif +0 -0
  190. data/examples/al-admin/public/images/spinelz/timepicker_clock.gif +0 -0
  191. data/examples/al-admin/public/images/spinelz/toolbar_close.gif +0 -0
  192. data/examples/al-admin/public/images/spinelz/toolbar_left.gif +0 -0
  193. data/examples/al-admin/public/images/spinelz/toolbar_max.gif +0 -0
  194. data/examples/al-admin/public/images/spinelz/toolbar_middle.gif +0 -0
  195. data/examples/al-admin/public/images/spinelz/toolbar_min.gif +0 -0
  196. data/examples/al-admin/public/images/spinelz/toolbar_next.gif +0 -0
  197. data/examples/al-admin/public/images/spinelz/toolbar_right.gif +0 -0
  198. data/examples/al-admin/public/images/spinelz/treeview_dir.gif +0 -0
  199. data/examples/al-admin/public/images/spinelz/treeview_file.gif +0 -0
  200. data/examples/al-admin/public/images/spinelz/treeview_group.gif +0 -0
  201. data/examples/al-admin/public/images/spinelz/treeview_group_special.gif +0 -0
  202. data/examples/al-admin/public/images/spinelz/treeview_state.gif +0 -0
  203. data/examples/al-admin/public/images/spinelz/treeview_user.gif +0 -0
  204. data/examples/al-admin/public/images/spinelz/window_bottom_left.gif +0 -0
  205. data/examples/al-admin/public/images/spinelz/window_bottom_middle.gif +0 -0
  206. data/examples/al-admin/public/images/spinelz/window_bottom_right.gif +0 -0
  207. data/examples/al-admin/public/images/spinelz/window_close.gif +0 -0
  208. data/examples/al-admin/public/images/spinelz/window_max.gif +0 -0
  209. data/examples/al-admin/public/images/spinelz/window_middle_left.gif +0 -0
  210. data/examples/al-admin/public/images/spinelz/window_middle_right.gif +0 -0
  211. data/examples/al-admin/public/images/spinelz/window_min.gif +0 -0
  212. data/examples/al-admin/public/images/spinelz/window_top_left.gif +0 -0
  213. data/examples/al-admin/public/images/spinelz/window_top_middle.gif +0 -0
  214. data/examples/al-admin/public/images/spinelz/window_top_right.gif +0 -0
  215. data/examples/al-admin/public/javascripts/application.js +2 -0
  216. data/examples/al-admin/public/javascripts/controls.js +963 -0
  217. data/examples/al-admin/public/javascripts/dragdrop.js +973 -0
  218. data/examples/al-admin/public/javascripts/effects.js +1128 -0
  219. data/examples/al-admin/public/javascripts/prototype.js +4320 -0
  220. data/examples/al-admin/public/javascripts/spinelz/accordion.js +185 -0
  221. data/examples/al-admin/public/javascripts/spinelz/ajaxHistory.js +157 -0
  222. data/examples/al-admin/public/javascripts/spinelz/balloon.js +287 -0
  223. data/examples/al-admin/public/javascripts/spinelz/barchart.js +524 -0
  224. data/examples/al-admin/public/javascripts/spinelz/calendar.js +3012 -0
  225. data/examples/al-admin/public/javascripts/spinelz/colorpicker.js +128 -0
  226. data/examples/al-admin/public/javascripts/spinelz/datepicker.js +438 -0
  227. data/examples/al-admin/public/javascripts/spinelz/grid.js +1391 -0
  228. data/examples/al-admin/public/javascripts/spinelz/grid_resizeEx.js +100 -0
  229. data/examples/al-admin/public/javascripts/spinelz/grid_sortabletableEx.js +129 -0
  230. data/examples/al-admin/public/javascripts/spinelz/inplaceEditorEx.js +148 -0
  231. data/examples/al-admin/public/javascripts/spinelz/menubar.js +232 -0
  232. data/examples/al-admin/public/javascripts/spinelz/navPanel.js +170 -0
  233. data/examples/al-admin/public/javascripts/spinelz/selectableTable.js +433 -0
  234. data/examples/al-admin/public/javascripts/spinelz/sideBarBox.js +282 -0
  235. data/examples/al-admin/public/javascripts/spinelz/sideBarBox_effects.js +83 -0
  236. data/examples/al-admin/public/javascripts/spinelz/sortableTable.js +270 -0
  237. data/examples/al-admin/public/javascripts/spinelz/switcher.js +78 -0
  238. data/examples/al-admin/public/javascripts/spinelz/tabBox.js +469 -0
  239. data/examples/al-admin/public/javascripts/spinelz/timepicker.js +384 -0
  240. data/examples/al-admin/public/javascripts/spinelz/toolbar.js +152 -0
  241. data/examples/al-admin/public/javascripts/spinelz/treeview.js +703 -0
  242. data/examples/al-admin/public/javascripts/spinelz/window.js +641 -0
  243. data/examples/al-admin/public/javascripts/spinelz/window_resizeEx.js +130 -0
  244. data/examples/al-admin/public/javascripts/spinelz_lib/builder.js +131 -0
  245. data/examples/al-admin/public/javascripts/spinelz_lib/controls.js +835 -0
  246. data/examples/al-admin/public/javascripts/spinelz_lib/dragdrop.js +944 -0
  247. data/examples/al-admin/public/javascripts/spinelz_lib/effects.js +1090 -0
  248. data/examples/al-admin/public/javascripts/spinelz_lib/json.js +139 -0
  249. data/examples/al-admin/public/javascripts/spinelz_lib/prototype.js +2515 -0
  250. data/examples/al-admin/public/javascripts/spinelz_lib/resize.js +215 -0
  251. data/examples/al-admin/public/javascripts/spinelz_lib/scriptaculous.js +51 -0
  252. data/examples/al-admin/public/javascripts/spinelz_lib/slider.js +278 -0
  253. data/examples/al-admin/public/javascripts/spinelz_lib/spinelz_util.js +1266 -0
  254. data/examples/al-admin/public/javascripts/spinelz_lib/unittest.js +564 -0
  255. data/examples/al-admin/public/robots.txt +1 -0
  256. data/examples/al-admin/public/stylesheets/account.css +41 -0
  257. data/examples/al-admin/public/stylesheets/attributes.css +1 -0
  258. data/examples/al-admin/public/stylesheets/base.css +104 -0
  259. data/examples/al-admin/public/stylesheets/detail.css +36 -0
  260. data/examples/al-admin/public/stylesheets/directory.css +22 -0
  261. data/examples/al-admin/public/stylesheets/object-classes.css +6 -0
  262. data/examples/al-admin/public/stylesheets/rails.css +35 -0
  263. data/examples/al-admin/public/stylesheets/spinelz/accordion.css +59 -0
  264. data/examples/al-admin/public/stylesheets/spinelz/balloon.css +151 -0
  265. data/examples/al-admin/public/stylesheets/spinelz/calendar.css +564 -0
  266. data/examples/al-admin/public/stylesheets/spinelz/datepicker.css +175 -0
  267. data/examples/al-admin/public/stylesheets/spinelz/grid.css +137 -0
  268. data/examples/al-admin/public/stylesheets/spinelz/menubar.css +78 -0
  269. data/examples/al-admin/public/stylesheets/spinelz/modal.css +22 -0
  270. data/examples/al-admin/public/stylesheets/spinelz/navPanel.css +58 -0
  271. data/examples/al-admin/public/stylesheets/spinelz/selectableTable.css +28 -0
  272. data/examples/al-admin/public/stylesheets/spinelz/sideBarBox.css +82 -0
  273. data/examples/al-admin/public/stylesheets/spinelz/sortableTable.css +51 -0
  274. data/examples/al-admin/public/stylesheets/spinelz/switcher.css +23 -0
  275. data/examples/al-admin/public/stylesheets/spinelz/tabBox.css +94 -0
  276. data/examples/al-admin/public/stylesheets/spinelz/timepicker.css +508 -0
  277. data/examples/al-admin/public/stylesheets/spinelz/toolbar.css +82 -0
  278. data/examples/al-admin/public/stylesheets/spinelz/treeview.css +121 -0
  279. data/examples/al-admin/public/stylesheets/spinelz/window.css +140 -0
  280. data/examples/al-admin/public/stylesheets/structure.css +81 -0
  281. data/examples/al-admin/public/stylesheets/syntaxes.css +1 -0
  282. data/examples/al-admin/public/stylesheets/users.css +13 -0
  283. data/examples/al-admin/public/stylesheets/welcome.css +0 -0
  284. data/examples/al-admin/script/about +3 -0
  285. data/examples/al-admin/script/console +3 -0
  286. data/examples/al-admin/script/dbconsole +3 -0
  287. data/examples/al-admin/script/destroy +3 -0
  288. data/examples/al-admin/script/generate +3 -0
  289. data/examples/al-admin/script/performance/benchmarker +3 -0
  290. data/examples/al-admin/script/performance/profiler +3 -0
  291. data/examples/al-admin/script/performance/request +3 -0
  292. data/examples/al-admin/script/plugin +3 -0
  293. data/examples/al-admin/script/process/inspector +3 -0
  294. data/examples/al-admin/script/process/reaper +3 -0
  295. data/examples/al-admin/script/process/spawner +3 -0
  296. data/examples/al-admin/script/runner +3 -0
  297. data/examples/al-admin/script/server +3 -0
  298. data/examples/al-admin/test/fixtures/users.yml +9 -0
  299. data/examples/al-admin/test/functional/account_controller_test.rb +12 -0
  300. data/examples/al-admin/test/functional/attributes_controller_test.rb +8 -0
  301. data/examples/al-admin/test/functional/directory_controller_test.rb +8 -0
  302. data/examples/al-admin/test/functional/object_classes_controller_test.rb +8 -0
  303. data/examples/al-admin/test/functional/syntaxes_controller_test.rb +8 -0
  304. data/examples/al-admin/test/functional/users_controller_test.rb +8 -0
  305. data/examples/al-admin/test/functional/welcome_controller_test.rb +8 -0
  306. data/examples/al-admin/test/integration/sign_up_test.rb +44 -0
  307. data/examples/al-admin/test/run-test.sh +3 -0
  308. data/examples/al-admin/test/test_helper.rb +52 -0
  309. data/examples/al-admin/test/unit/user_test.rb +12 -0
  310. data/examples/al-admin/vendor/plugins/exception_notification/README +111 -0
  311. data/examples/al-admin/vendor/plugins/exception_notification/init.rb +1 -0
  312. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifiable.rb +99 -0
  313. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifier.rb +66 -0
  314. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifier_helper.rb +78 -0
  315. data/examples/al-admin/vendor/plugins/exception_notification/test/exception_notifier_helper_test.rb +61 -0
  316. data/examples/al-admin/vendor/plugins/exception_notification/test/test_helper.rb +7 -0
  317. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_backtrace.rhtml +1 -0
  318. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_environment.rhtml +7 -0
  319. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_inspect_model.rhtml +16 -0
  320. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_request.rhtml +4 -0
  321. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_session.rhtml +2 -0
  322. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_title.rhtml +3 -0
  323. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/exception_notification.rhtml +6 -0
  324. data/examples/config.yaml.example +5 -0
  325. data/examples/example.der +0 -0
  326. data/examples/example.jpg +0 -0
  327. data/examples/groupadd +41 -0
  328. data/examples/groupdel +35 -0
  329. data/examples/groupls +49 -0
  330. data/examples/groupmod +42 -0
  331. data/examples/lpasswd +55 -0
  332. data/examples/objects/group.rb +13 -0
  333. data/examples/objects/ou.rb +4 -0
  334. data/examples/objects/user.rb +20 -0
  335. data/examples/ouadd +38 -0
  336. data/examples/useradd +45 -0
  337. data/examples/useradd-binary +53 -0
  338. data/examples/userdel +34 -0
  339. data/examples/userls +50 -0
  340. data/examples/usermod +42 -0
  341. data/examples/usermod-binary-add +50 -0
  342. data/examples/usermod-binary-add-time +54 -0
  343. data/examples/usermod-binary-del +48 -0
  344. data/examples/usermod-lang-add +43 -0
  345. data/lib/active_ldap.rb +105 -0
  346. data/lib/active_ldap/action_controller/ldap_benchmarking.rb +55 -0
  347. data/lib/active_ldap/acts/tree.rb +75 -0
  348. data/lib/active_ldap/adapter/base.rb +705 -0
  349. data/lib/active_ldap/adapter/jndi.rb +184 -0
  350. data/lib/active_ldap/adapter/jndi_connection.rb +185 -0
  351. data/lib/active_ldap/adapter/ldap.rb +290 -0
  352. data/lib/active_ldap/adapter/ldap_ext.rb +105 -0
  353. data/lib/active_ldap/adapter/net_ldap.rb +309 -0
  354. data/lib/active_ldap/adapter/net_ldap_ext.rb +23 -0
  355. data/lib/active_ldap/association/belongs_to.rb +47 -0
  356. data/lib/active_ldap/association/belongs_to_many.rb +58 -0
  357. data/lib/active_ldap/association/children.rb +21 -0
  358. data/lib/active_ldap/association/collection.rb +105 -0
  359. data/lib/active_ldap/association/has_many.rb +31 -0
  360. data/lib/active_ldap/association/has_many_utils.rb +44 -0
  361. data/lib/active_ldap/association/has_many_wrap.rb +62 -0
  362. data/lib/active_ldap/association/proxy.rb +107 -0
  363. data/lib/active_ldap/associations.rb +202 -0
  364. data/lib/active_ldap/attributes.rb +184 -0
  365. data/lib/active_ldap/base.rb +1594 -0
  366. data/lib/active_ldap/callbacks.rb +52 -0
  367. data/lib/active_ldap/command.rb +49 -0
  368. data/lib/active_ldap/compatible.rb +44 -0
  369. data/lib/active_ldap/configuration.rb +147 -0
  370. data/lib/active_ldap/connection.rb +294 -0
  371. data/lib/active_ldap/distinguished_name.rb +291 -0
  372. data/lib/active_ldap/entry_attribute.rb +78 -0
  373. data/lib/active_ldap/escape.rb +12 -0
  374. data/lib/active_ldap/get_text.rb +9 -0
  375. data/lib/active_ldap/get_text/parser.rb +161 -0
  376. data/lib/active_ldap/get_text_fallback.rb +60 -0
  377. data/lib/active_ldap/get_text_support.rb +20 -0
  378. data/lib/active_ldap/helper.rb +92 -0
  379. data/lib/active_ldap/human_readable.rb +132 -0
  380. data/lib/active_ldap/ldap_error.rb +74 -0
  381. data/lib/active_ldap/ldif.rb +930 -0
  382. data/lib/active_ldap/object_class.rb +95 -0
  383. data/lib/active_ldap/operations.rb +610 -0
  384. data/lib/active_ldap/populate.rb +53 -0
  385. data/lib/active_ldap/railtie.rb +31 -0
  386. data/lib/active_ldap/schema.rb +699 -0
  387. data/lib/active_ldap/schema/syntaxes.rb +417 -0
  388. data/lib/active_ldap/timeout.rb +75 -0
  389. data/lib/active_ldap/timeout_stub.rb +17 -0
  390. data/lib/active_ldap/user_password.rb +92 -0
  391. data/lib/active_ldap/validations.rb +229 -0
  392. data/lib/active_ldap/xml.rb +122 -0
  393. data/po/en/active-ldap.po +4029 -0
  394. data/po/ja/active-ldap.po +4060 -0
  395. data/rails_generators/model_active_ldap/USAGE +17 -0
  396. data/rails_generators/model_active_ldap/model_active_ldap_generator.rb +69 -0
  397. data/rails_generators/model_active_ldap/templates/model_active_ldap.rb +3 -0
  398. data/rails_generators/model_active_ldap/templates/unit_test.rb +8 -0
  399. data/rails_generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb +7 -0
  400. data/rails_generators/scaffold_active_ldap/templates/ldap.yml +18 -0
  401. data/test/al-test-utils.rb +439 -0
  402. data/test/command.rb +112 -0
  403. data/test/config.yaml.sample +6 -0
  404. data/test/fixtures/lower_case_object_class_schema.rb +802 -0
  405. data/test/run-test.rb +44 -0
  406. data/test/test_acts_as_tree.rb +60 -0
  407. data/test/test_adapter.rb +121 -0
  408. data/test/test_associations.rb +664 -0
  409. data/test/test_attributes.rb +117 -0
  410. data/test/test_base.rb +1177 -0
  411. data/test/test_base_per_instance.rb +61 -0
  412. data/test/test_bind.rb +62 -0
  413. data/test/test_callback.rb +37 -0
  414. data/test/test_configuration.rb +40 -0
  415. data/test/test_connection.rb +82 -0
  416. data/test/test_connection_per_class.rb +112 -0
  417. data/test/test_connection_per_dn.rb +112 -0
  418. data/test/test_dn.rb +172 -0
  419. data/test/test_find.rb +176 -0
  420. data/test/test_groupadd.rb +50 -0
  421. data/test/test_groupdel.rb +46 -0
  422. data/test/test_groupls.rb +107 -0
  423. data/test/test_groupmod.rb +51 -0
  424. data/test/test_ldif.rb +1891 -0
  425. data/test/test_load.rb +133 -0
  426. data/test/test_lpasswd.rb +75 -0
  427. data/test/test_object_class.rb +74 -0
  428. data/test/test_reflection.rb +182 -0
  429. data/test/test_schema.rb +559 -0
  430. data/test/test_syntax.rb +383 -0
  431. data/test/test_user.rb +217 -0
  432. data/test/test_user_password.rb +101 -0
  433. data/test/test_useradd-binary.rb +62 -0
  434. data/test/test_useradd.rb +57 -0
  435. data/test/test_userdel.rb +48 -0
  436. data/test/test_userls.rb +91 -0
  437. data/test/test_usermod-binary-add-time.rb +65 -0
  438. data/test/test_usermod-binary-add.rb +64 -0
  439. data/test/test_usermod-binary-del.rb +66 -0
  440. data/test/test_usermod-lang-add.rb +60 -0
  441. data/test/test_usermod.rb +58 -0
  442. data/test/test_validation.rb +274 -0
  443. metadata +502 -0
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/ruby
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.setup_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
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.setup_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,105 @@
1
+ require_gem_if_need = Proc.new do |library_name, gem_name, *gem_args|
2
+ gem_name ||= library_name
3
+ begin
4
+ if !gem_args.empty? and Object.const_defined?(:Gem)
5
+ gem gem_name, *gem_args
6
+ end
7
+ require library_name
8
+ rescue LoadError
9
+ require 'rubygems'
10
+ gem gem_name, *gem_args
11
+ require library_name
12
+ end
13
+ end
14
+
15
+ require_gem_if_need.call("active_support", "activesupport", ">= 3.0.0")
16
+
17
+ if ActiveSupport
18
+ require 'active_support/dependencies'
19
+ require 'active_support/all'
20
+ end
21
+
22
+ if ActiveSupport.const_defined?(:Dependencies)
23
+ dependencies = ActiveSupport::Dependencies
24
+ else
25
+ dependencies = Dependencies
26
+ end
27
+
28
+ if dependencies.respond_to?(:load_paths)
29
+ dependencies.load_paths << File.expand_path(File.dirname(__FILE__))
30
+ end
31
+
32
+ module ActiveLdap
33
+ VERSION = "1.2.3"
34
+ end
35
+
36
+ if RUBY_PLATFORM.match('linux')
37
+ require 'active_ldap/timeout'
38
+ else
39
+ require 'active_ldap/timeout_stub'
40
+ end
41
+
42
+ require_gem_if_need.call("active_record", "activerecord", ">= 3.0.0")
43
+ begin
44
+ require_gem_if_need.call("locale", nil, "= 2.0.5")
45
+ require_gem_if_need.call("fast_gettext", nil, "= 0.5.8")
46
+ rescue LoadError
47
+ end
48
+ require 'active_ldap/get_text'
49
+
50
+ require 'active_ldap/compatible'
51
+
52
+ require 'active_ldap/base'
53
+
54
+ require 'active_ldap/distinguished_name'
55
+ require 'active_ldap/ldif'
56
+ require 'active_ldap/xml'
57
+
58
+ require 'active_ldap/associations'
59
+ require 'active_ldap/attributes'
60
+ require 'active_ldap/configuration'
61
+ require 'active_ldap/connection'
62
+ require 'active_ldap/operations'
63
+ require 'active_ldap/object_class'
64
+ require 'active_ldap/human_readable'
65
+
66
+ require 'active_ldap/acts/tree'
67
+
68
+ require 'active_ldap/populate'
69
+ require 'active_ldap/escape'
70
+ require 'active_ldap/user_password'
71
+ require 'active_ldap/helper'
72
+
73
+ require 'active_ldap/validations'
74
+ require 'active_ldap/callbacks'
75
+
76
+ require 'active_ldap/command'
77
+
78
+
79
+ ActiveLdap::Base.class_eval do
80
+ include ActiveLdap::Associations
81
+ include ActiveLdap::Attributes
82
+ include ActiveLdap::Configuration
83
+ include ActiveLdap::Connection
84
+ include ActiveLdap::Operations
85
+ include ActiveLdap::ObjectClass
86
+ include ActiveLdap::HumanReadable
87
+
88
+ include ActiveLdap::Acts::Tree
89
+
90
+ include ActiveLdap::Validations
91
+ include ActiveLdap::Callbacks
92
+ end
93
+
94
+ unless defined?(ACTIVE_LDAP_CONNECTION_ADAPTERS)
95
+ ACTIVE_LDAP_CONNECTION_ADAPTERS = %w(ldap net_ldap jndi)
96
+ end
97
+
98
+ ACTIVE_LDAP_CONNECTION_ADAPTERS.each do |adapter|
99
+ require "active_ldap/adapter/#{adapter}"
100
+ end
101
+
102
+
103
+ if defined?(Rails)
104
+ require 'active_ldap/railtie'
105
+ end
@@ -0,0 +1,55 @@
1
+ module ActiveLdap
2
+ module ActionController
3
+ module LdapBenchmarking
4
+ def self.included(base)
5
+ base.class_eval do
6
+ alias_method_chain :render_with_benchmark, :active_ldap
7
+ if private_method_defined?(:view_runtime)
8
+ alias_method_chain :view_runtime, :active_ldap
9
+ else
10
+ alias_method_chain :rendering_runtime, :active_ldap
11
+ end
12
+ end
13
+ end
14
+
15
+ protected
16
+ def render_with_benchmark_with_active_ldap(*args, &block)
17
+ if logger
18
+ ldap_runtime_before_render = ActiveLdap::Base.reset_runtime
19
+ end
20
+ result = render_with_benchmark_without_active_ldap(*args, &block)
21
+ if logger
22
+ @ldap_runtime_before_render = ldap_runtime_before_render
23
+ @ldap_runtime_after_render = ActiveLdap::Base.reset_runtime
24
+ if defined?(@rendering_runtime)
25
+ @rendering_runtime -= @ldap_runtime_after_render
26
+ else
27
+ @view_runtime -= @ldap_runtime_after_render
28
+ end
29
+ end
30
+ result
31
+ end
32
+
33
+ private
34
+ def rendering_runtime_with_active_ldap(runtime)
35
+ result = rendering_runtime_without_active_ldap(runtime)
36
+ ldap_runtime = ActiveLdap::Base.reset_runtime
37
+ ldap_runtime += @ldap_runtime_before_render || 0
38
+ ldap_runtime += @ldap_runtime_after_render || 0
39
+ ldap_percentage = ldap_runtime * 100 / runtime
40
+ result + (" | LDAP: %.5f (%d%%)" % [ldap_runtime, ldap_percentage])
41
+ end
42
+
43
+ def view_runtime_with_active_ldap
44
+ result = view_runtime_without_active_ldap
45
+ ldap_runtime = ActiveLdap::Base.reset_runtime
46
+ @ldap_runtime_before_render ||= 0
47
+ @ldap_runtime_after_render ||= 0
48
+ ldap_runtime += @ldap_runtime_before_render
49
+ ldap_runtime += @ldap_runtime_after_render
50
+ result + (", LDAP: %.0f" % (ldap_runtime * 1000))
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,75 @@
1
+ module ActiveLdap
2
+ module Acts
3
+ module Tree
4
+ def self.included(base)
5
+ base.class_eval do
6
+ extend(ClassMethods)
7
+ association_accessor(:children) do |target|
8
+ Association::Children.new(target, {})
9
+ end
10
+ end
11
+ end
12
+
13
+ module ClassMethods
14
+ def root(options={})
15
+ find(:first, options.merge(:scope => :base))
16
+ end
17
+ end
18
+
19
+ # Returns list of ancestors, starting from parent until root.
20
+ #
21
+ # subchild1.ancestors # => [child1, root]
22
+ def ancestors
23
+ node, nodes = self, []
24
+ nodes << node = node.parent while node.parent
25
+ nodes
26
+ end
27
+
28
+ # Returns the root node of the tree.
29
+ def root
30
+ node = self
31
+ node = node.parent while node.parent
32
+ node
33
+ end
34
+
35
+ # Returns all siblings of the current node.
36
+ #
37
+ # subchild1.siblings # => [subchild2]
38
+ def siblings
39
+ self_and_siblings - [self]
40
+ end
41
+
42
+ # Returns all siblings and a reference to the current node.
43
+ #
44
+ # subchild1.self_and_siblings # => [subchild1, subchild2]
45
+ def self_and_siblings
46
+ parent ? parent.children : [self]
47
+ end
48
+
49
+ def parent
50
+ if base == self.class.base
51
+ nil
52
+ else
53
+ find(:first, :base => base, :scope => :base)
54
+ end
55
+ end
56
+
57
+ def parent=(entry)
58
+ if entry.is_a?(String) or entry.is_a?(DN)
59
+ base = entry
60
+ elsif entry.respond_to?(:dn)
61
+ base = entry.dn
62
+ if entry.respond_to?(:clear_association_cache)
63
+ entry.clear_association_cache
64
+ end
65
+ else
66
+ message = _("parent must be an entry or parent DN: %s") % entry.inspect
67
+ raise ArgumentError, message
68
+ end
69
+ destroy unless new_entry?
70
+ self.dn = "#{dn_attribute}=#{id},#{base}"
71
+ save
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,705 @@
1
+ require 'benchmark'
2
+
3
+ require 'active_ldap/schema'
4
+ require 'active_ldap/entry_attribute'
5
+ require 'active_ldap/ldap_error'
6
+
7
+ module ActiveLdap
8
+ module Adapter
9
+ class Base
10
+ include GetTextSupport
11
+
12
+ VALID_ADAPTER_CONFIGURATION_KEYS = [:host, :port, :method, :timeout,
13
+ :retry_on_timeout, :retry_limit,
14
+ :retry_wait, :bind_dn, :password,
15
+ :password_block, :try_sasl,
16
+ :sasl_mechanisms, :sasl_quiet,
17
+ :allow_anonymous, :store_password,
18
+ :scope, :sasl_options]
19
+
20
+ @@row_even = true
21
+
22
+ attr_reader :runtime
23
+ def initialize(configuration={})
24
+ @runtime = 0
25
+ @connection = nil
26
+ @disconnected = false
27
+ @bound = false
28
+ @bind_tried = false
29
+ @entry_attributes = {}
30
+ @configuration = configuration.dup
31
+ @logger = @configuration.delete(:logger)
32
+ @configuration.assert_valid_keys(VALID_ADAPTER_CONFIGURATION_KEYS)
33
+ VALID_ADAPTER_CONFIGURATION_KEYS.each do |name|
34
+ instance_variable_set("@#{name}", configuration[name])
35
+ end
36
+ end
37
+
38
+ def reset_runtime
39
+ runtime, @runtime = @runtime, 0
40
+ runtime
41
+ end
42
+
43
+ def connect(options={})
44
+ host = options[:host] || @host
45
+ method = options[:method] || @method || :plain
46
+ port = options[:port] || @port || ensure_port(method)
47
+ method = ensure_method(method)
48
+ @disconnected = false
49
+ @bound = false
50
+ @bind_tried = false
51
+ @connection, @uri, @with_start_tls = yield(host, port, method)
52
+ prepare_connection(options)
53
+ bind(options)
54
+ end
55
+
56
+ def disconnect!(options={})
57
+ unbind(options)
58
+ @connection = @uri = @with_start_tls = nil
59
+ @disconnected = true
60
+ end
61
+
62
+ def rebind(options={})
63
+ unbind(options) if bound?
64
+ connect(options)
65
+ end
66
+
67
+ def bind(options={})
68
+ @bind_tried = true
69
+
70
+ bind_dn = ensure_dn_string(options[:bind_dn] || @bind_dn)
71
+ try_sasl = options.has_key?(:try_sasl) ? options[:try_sasl] : @try_sasl
72
+ if options.has_key?(:allow_anonymous)
73
+ allow_anonymous = options[:allow_anonymous]
74
+ else
75
+ allow_anonymous = @allow_anonymous
76
+ end
77
+ options = options.merge(:allow_anonymous => allow_anonymous)
78
+
79
+ # Rough bind loop:
80
+ # Attempt 1: SASL if available
81
+ # Attempt 2: SIMPLE with credentials if password block
82
+ # Attempt 3: SIMPLE ANONYMOUS if 1 and 2 fail (or pwblock returns '')
83
+ if try_sasl and sasl_bind(bind_dn, options)
84
+ @logger.info {_('Bound to %s by SASL as %s') % [target, bind_dn]}
85
+ elsif simple_bind(bind_dn, options)
86
+ @logger.info {_('Bound to %s by simple as %s') % [target, bind_dn]}
87
+ elsif allow_anonymous and bind_as_anonymous(options)
88
+ @logger.info {_('Bound to %s as anonymous') % target}
89
+ else
90
+ message = yield if block_given?
91
+ message ||= _('All authentication methods for %s exhausted.') % target
92
+ raise AuthenticationError, message
93
+ end
94
+
95
+ @bound = true
96
+ @bound
97
+ end
98
+
99
+ def unbind(options={})
100
+ yield if @connection and (@bind_tried or bound?)
101
+ @bind_tried = @bound = false
102
+ end
103
+
104
+ def bind_as_anonymous(options={})
105
+ yield
106
+ end
107
+
108
+ def connecting?
109
+ !@connection.nil? and !@disconnected
110
+ end
111
+
112
+ def bound?
113
+ connecting? and @bound
114
+ end
115
+
116
+ def schema(options={})
117
+ @schema ||= operation(options) do
118
+ base = options[:base]
119
+ attrs = options[:attributes]
120
+
121
+ attrs ||= [
122
+ 'objectClasses',
123
+ 'attributeTypes',
124
+ 'matchingRules',
125
+ 'matchingRuleUse',
126
+ 'dITStructureRules',
127
+ 'dITContentRules',
128
+ 'nameForms',
129
+ 'ldapSyntaxes',
130
+ #'extendedAttributeInfo', # if we need RANGE-LOWER/UPPER.
131
+ ]
132
+ base ||= root_dse_values('subschemaSubentry', options)[0]
133
+ base ||= 'cn=schema'
134
+ schema = nil
135
+ search(:base => base,
136
+ :scope => :base,
137
+ :filter => '(objectClass=subschema)',
138
+ :attributes => attrs,
139
+ :limit => 1) do |dn, attributes|
140
+ schema = Schema.new(attributes)
141
+ end
142
+ schema || Schema.new([])
143
+ end
144
+ end
145
+
146
+ def naming_contexts
147
+ root_dse_values('namingContexts')
148
+ end
149
+
150
+ def entry_attribute(object_classes)
151
+ @entry_attributes[object_classes.uniq.sort] ||=
152
+ EntryAttribute.new(schema, object_classes)
153
+ end
154
+
155
+ def search(options={})
156
+ filter = parse_filter(options[:filter]) || 'objectClass=*'
157
+ attrs = options[:attributes] || []
158
+ scope = ensure_scope(options[:scope] || @scope)
159
+ base = options[:base]
160
+ limit = options[:limit] || 0
161
+ limit = nil if limit <= 0
162
+
163
+ attrs = attrs.to_a # just in case
164
+ base = ensure_dn_string(base)
165
+ begin
166
+ operation(options) do
167
+ yield(base, scope, filter, attrs, limit)
168
+ end
169
+ rescue LdapError::NoSuchObject, LdapError::InvalidDnSyntax
170
+ # Do nothing on failure
171
+ @logger.info do
172
+ args = [$!.class, $!.message, filter, attrs.inspect]
173
+ _("Ignore error %s(%s): filter %s: attributes: %s") % args
174
+ end
175
+ end
176
+ end
177
+
178
+ def delete(targets, options={})
179
+ targets = [targets] unless targets.is_a?(Array)
180
+ return if targets.empty?
181
+ begin
182
+ operation(options) do
183
+ targets.each do |target|
184
+ target = ensure_dn_string(target)
185
+ begin
186
+ yield(target)
187
+ rescue LdapError::UnwillingToPerform, LdapError::InsufficientAccess
188
+ raise OperationNotPermitted, _("%s: %s") % [$!.message, target]
189
+ end
190
+ end
191
+ end
192
+ rescue LdapError::NoSuchObject
193
+ raise EntryNotFound, _("No such entry: %s") % target
194
+ end
195
+ end
196
+
197
+ def add(dn, entries, options={})
198
+ dn = ensure_dn_string(dn)
199
+ begin
200
+ operation(options) do
201
+ yield(dn, entries)
202
+ end
203
+ rescue LdapError::NoSuchObject
204
+ raise EntryNotFound, _("No such entry: %s") % dn
205
+ rescue LdapError::InvalidDnSyntax
206
+ raise DistinguishedNameInvalid.new(dn)
207
+ rescue LdapError::AlreadyExists
208
+ raise EntryAlreadyExist, _("%s: %s") % [$!.message, dn]
209
+ rescue LdapError::StrongAuthRequired
210
+ raise StrongAuthenticationRequired, _("%s: %s") % [$!.message, dn]
211
+ rescue LdapError::ObjectClassViolation
212
+ raise RequiredAttributeMissed, _("%s: %s") % [$!.message, dn]
213
+ rescue LdapError::UnwillingToPerform
214
+ raise OperationNotPermitted, _("%s: %s") % [$!.message, dn]
215
+ end
216
+ end
217
+
218
+ def modify(dn, entries, options={})
219
+ dn = ensure_dn_string(dn)
220
+ begin
221
+ operation(options) do
222
+ begin
223
+ yield(dn, entries)
224
+ rescue LdapError::UnwillingToPerform, LdapError::InsufficientAccess
225
+ raise OperationNotPermitted, _("%s: %s") % [$!.message, target]
226
+ end
227
+ end
228
+ rescue LdapError::UndefinedType
229
+ raise
230
+ rescue LdapError::ObjectClassViolation
231
+ raise RequiredAttributeMissed, _("%s: %s") % [$!.message, dn]
232
+ end
233
+ end
234
+
235
+ def modify_rdn(dn, new_rdn, delete_old_rdn, new_superior, options={})
236
+ dn = ensure_dn_string(dn)
237
+ operation(options) do
238
+ yield(dn, new_rdn, delete_old_rdn, new_superior)
239
+ end
240
+ end
241
+
242
+ def log_info(name, runtime_in_seconds, info=nil)
243
+ return unless @logger
244
+ return unless @logger.debug?
245
+ message = "LDAP: #{name} (#{'%.1f' % (runtime_in_seconds * 1000)}ms)"
246
+ @logger.debug(format_log_entry(message, info))
247
+ end
248
+
249
+ private
250
+ def ensure_port(method)
251
+ if method == :ssl
252
+ URI::LDAPS::DEFAULT_PORT
253
+ else
254
+ URI::LDAP::DEFAULT_PORT
255
+ end
256
+ end
257
+
258
+ def prepare_connection(options)
259
+ end
260
+
261
+ def operation(options)
262
+ retried = false
263
+ options = options.dup
264
+ options[:try_reconnect] = true unless options.has_key?(:try_reconnect)
265
+ try_reconnect = false
266
+ begin
267
+ reconnect_if_need(options)
268
+ try_reconnect = options[:try_reconnect]
269
+ with_timeout(try_reconnect, options) do
270
+ yield
271
+ end
272
+ rescue ConnectionError
273
+ if try_reconnect and !retried
274
+ retried = true
275
+ @disconnected = true
276
+ retry
277
+ else
278
+ raise
279
+ end
280
+ end
281
+ end
282
+
283
+ def need_credential_sasl_mechanism?(mechanism)
284
+ not %(GSSAPI EXTERNAL ANONYMOUS).include?(mechanism)
285
+ end
286
+
287
+ def password(bind_dn, options={})
288
+ passwd = options[:password] || @password
289
+ return passwd if passwd
290
+
291
+ password_block = options[:password_block] || @password_block
292
+ # TODO: Give a warning to reconnect users with password clearing
293
+ # Get the passphrase for the first time, or anew if we aren't storing
294
+ if password_block.respond_to?(:call)
295
+ passwd = password_block.call(bind_dn)
296
+ else
297
+ @logger.error {_('password_block not nil or Proc object. Ignoring.')}
298
+ return nil
299
+ end
300
+
301
+ # Store the password for quick reference later
302
+ if options.has_key?(:store_password)
303
+ store_password = options[:store_password]
304
+ else
305
+ store_password = @store_password
306
+ end
307
+ @password = store_password ? passwd : nil
308
+
309
+ passwd
310
+ end
311
+
312
+ def with_timeout(try_reconnect=true, options={}, &block)
313
+ n_retries = 0
314
+ retry_limit = options[:retry_limit] || @retry_limit
315
+ begin
316
+ do_in_timeout(@timeout, &block)
317
+ rescue Timeout::Error => e
318
+ @logger.error {_('Requested action timed out.')}
319
+ if @retry_on_timeout and retry_limit < 0 and n_retries <= retry_limit
320
+ if connecting?
321
+ retry
322
+ elsif try_reconnect
323
+ retry if with_timeout(false, options) {reconnect(options)}
324
+ end
325
+ end
326
+ @logger.error {e.message}
327
+ raise TimeoutError, e.message
328
+ end
329
+ end
330
+
331
+ def do_in_timeout(timeout, &block)
332
+ Timeout.alarm(timeout, &block)
333
+ end
334
+
335
+ def sasl_bind(bind_dn, options={})
336
+ # Get all SASL mechanisms
337
+ mechanisms = operation(options) do
338
+ root_dse_values("supportedSASLMechanisms")
339
+ end
340
+
341
+ if options.has_key?(:sasl_quiet)
342
+ sasl_quiet = options[:sasl_quiet]
343
+ else
344
+ sasl_quiet = @sasl_quiet
345
+ end
346
+
347
+ sasl_mechanisms = options[:sasl_mechanisms] || @sasl_mechanisms
348
+ sasl_mechanisms.each do |mechanism|
349
+ next unless mechanisms.include?(mechanism)
350
+ return true if yield(bind_dn, mechanism, sasl_quiet)
351
+ end
352
+ false
353
+ end
354
+
355
+ def simple_bind(bind_dn, options={})
356
+ return false unless bind_dn
357
+
358
+ passwd = password(bind_dn, options)
359
+ return false unless passwd
360
+
361
+ if passwd.empty?
362
+ if options[:allow_anonymous]
363
+ @logger.info {_("Skip simple bind with empty password.")}
364
+ return false
365
+ else
366
+ raise AuthenticationError,
367
+ _("Can't use empty password for simple bind.")
368
+ end
369
+ end
370
+
371
+ begin
372
+ yield(bind_dn, passwd)
373
+ rescue LdapError::InvalidDnSyntax
374
+ raise DistinguishedNameInvalid.new(bind_dn)
375
+ rescue LdapError::InvalidCredentials
376
+ false
377
+ end
378
+ end
379
+
380
+ def parse_filter(filter, operator=nil)
381
+ return nil if filter.nil?
382
+ if !filter.is_a?(String) and !filter.respond_to?(:collect)
383
+ filter = filter.to_s
384
+ end
385
+
386
+ case filter
387
+ when String
388
+ parse_filter_string(filter)
389
+ when Hash
390
+ components = filter.sort_by {|k, v| k.to_s}.collect do |key, value|
391
+ construct_component(key, value, operator)
392
+ end
393
+ construct_filter(components, operator)
394
+ else
395
+ operator, components = normalize_array_filter(filter, operator)
396
+ components = construct_components(components, operator)
397
+ construct_filter(components, operator)
398
+ end
399
+ end
400
+
401
+ def parse_filter_string(filter)
402
+ if /\A\s*\z/.match(filter)
403
+ nil
404
+ else
405
+ if filter[0, 1] == "("
406
+ filter
407
+ else
408
+ "(#{filter})"
409
+ end
410
+ end
411
+ end
412
+
413
+ def normalize_array_filter(filter, operator=nil)
414
+ filter_operator, *components = filter
415
+ if filter_logical_operator?(filter_operator)
416
+ operator = filter_operator
417
+ else
418
+ components.unshift(filter_operator)
419
+ components = [components] unless filter_operator.is_a?(Array)
420
+ end
421
+ [operator, components]
422
+ end
423
+
424
+ def extract_filter_value_options(value)
425
+ options = {}
426
+ if value.is_a?(Array)
427
+ case value[0]
428
+ when Hash
429
+ options = value[0]
430
+ value = value[1]
431
+ when "=", "~=", "<=", ">="
432
+ options[:operator] = value[0]
433
+ if value.size > 2
434
+ value = value[1..-1]
435
+ else
436
+ value = value[1]
437
+ end
438
+ end
439
+ end
440
+ [value, options]
441
+ end
442
+
443
+ def construct_components(components, operator)
444
+ components.collect do |component|
445
+ if component.is_a?(Array)
446
+ if filter_logical_operator?(component[0])
447
+ parse_filter(component)
448
+ elsif component.size == 2
449
+ key, value = component
450
+ if value.is_a?(Hash)
451
+ parse_filter(value, key)
452
+ else
453
+ construct_component(key, value, operator)
454
+ end
455
+ else
456
+ construct_component(component[0], component[1..-1], operator)
457
+ end
458
+ elsif component.is_a?(Symbol)
459
+ assert_filter_logical_operator(component)
460
+ nil
461
+ else
462
+ parse_filter(component, operator)
463
+ end
464
+ end
465
+ end
466
+
467
+ def construct_component(key, value, operator=nil)
468
+ value, options = extract_filter_value_options(value)
469
+ comparison_operator = options[:operator] || "="
470
+ if collection?(value)
471
+ return nil if value.empty?
472
+ operator, value = normalize_array_filter(value, operator)
473
+ values = []
474
+ value.each do |val|
475
+ if collection?(val)
476
+ values.concat(val.collect {|v| [key, comparison_operator, v]})
477
+ else
478
+ values << [key, comparison_operator, val]
479
+ end
480
+ end
481
+ values[0] = values[0][1] if filter_logical_operator?(values[0][1])
482
+ parse_filter(values, operator)
483
+ else
484
+ [
485
+ "(",
486
+ escape_filter_key(key),
487
+ comparison_operator,
488
+ escape_filter_value(value, options),
489
+ ")"
490
+ ].join
491
+ end
492
+ end
493
+
494
+ def escape_filter_key(key)
495
+ escape_filter_value(key.to_s)
496
+ end
497
+
498
+ def escape_filter_value(value, options={})
499
+ case value
500
+ when Numeric, DN
501
+ value = value.to_s
502
+ when Time
503
+ value = Schema::GeneralizedTime.new.normalize_value(value)
504
+ end
505
+ value.gsub(/(?:[:()\\\0]|\*\*?)/) do |s|
506
+ if s == "*"
507
+ s
508
+ else
509
+ s = "*" if s == "**"
510
+ if s.respond_to?(:getbyte)
511
+ "\\%02X" % s.getbyte(0)
512
+ else
513
+ "\\%02X" % s[0]
514
+ end
515
+ end
516
+ end
517
+ end
518
+
519
+ def construct_filter(components, operator=nil)
520
+ operator = normalize_filter_logical_operator(operator)
521
+ components = components.compact
522
+ case components.size
523
+ when 0
524
+ nil
525
+ when 1
526
+ filter = components[0]
527
+ filter = "(!#{filter})" if operator == :not
528
+ filter
529
+ else
530
+ "(#{operator == :and ? '&' : '|'}#{components.join})"
531
+ end
532
+ end
533
+
534
+ def collection?(object)
535
+ !object.is_a?(String) and object.respond_to?(:each)
536
+ end
537
+
538
+ LOGICAL_OPERATORS = [:and, :or, :not, :&, :|]
539
+ def filter_logical_operator?(operator)
540
+ LOGICAL_OPERATORS.include?(operator)
541
+ end
542
+
543
+ def normalize_filter_logical_operator(operator)
544
+ assert_filter_logical_operator(operator)
545
+ case (operator || :and)
546
+ when :and, :&
547
+ :and
548
+ when :or, :|
549
+ :or
550
+ else
551
+ :not
552
+ end
553
+ end
554
+
555
+ def assert_filter_logical_operator(operator)
556
+ return if operator.nil?
557
+ unless filter_logical_operator?(operator)
558
+ raise ArgumentError,
559
+ _("invalid logical operator: %s: available operators: %s") %
560
+ [operator.inspect, LOGICAL_OPERATORS.inspect]
561
+ end
562
+ end
563
+
564
+ # Attempts to reconnect up to the number of times allowed
565
+ # If forced, try once then fail with ConnectionError if not connected.
566
+ def reconnect(options={})
567
+ options = options.dup
568
+ force = options[:force]
569
+ retry_limit = options[:retry_limit] || @retry_limit
570
+ retry_wait = options[:retry_wait] || @retry_wait
571
+ options[:reconnect_attempts] ||= 0
572
+
573
+ loop do
574
+ @logger.debug {_('Attempting to reconnect')}
575
+ disconnect!
576
+
577
+ # Reset the attempts if this was forced.
578
+ options[:reconnect_attempts] = 0 if force
579
+ options[:reconnect_attempts] += 1 if retry_limit >= 0
580
+ begin
581
+ connect(options)
582
+ break
583
+ rescue AuthenticationError
584
+ raise
585
+ rescue => detail
586
+ @logger.error do
587
+ _("Reconnect to server failed: %s\n" \
588
+ "Reconnect to server failed backtrace:\n" \
589
+ "%s") % [detail.exception, detail.backtrace.join("\n")]
590
+ end
591
+ # Do not loop if forced
592
+ raise ConnectionError, detail.message if force
593
+ end
594
+
595
+ unless can_reconnect?(options)
596
+ raise ConnectionError,
597
+ _('Giving up trying to reconnect to LDAP server.')
598
+ end
599
+
600
+ # Sleep before looping
601
+ sleep retry_wait
602
+ end
603
+
604
+ true
605
+ end
606
+
607
+ def reconnect_if_need(options={})
608
+ return if connecting?
609
+ with_timeout(false, options) do
610
+ reconnect(options)
611
+ end
612
+ end
613
+
614
+ # Determine if we have exceed the retry limit or not.
615
+ # True is reconnecting is allowed - False if not.
616
+ def can_reconnect?(options={})
617
+ retry_limit = options[:retry_limit] || @retry_limit
618
+ reconnect_attempts = options[:reconnect_attempts] || 0
619
+
620
+ retry_limit < 0 or reconnect_attempts <= retry_limit
621
+ end
622
+
623
+ def root_dse_values(key, options={})
624
+ dse = root_dse([key], options)
625
+ return [] if dse.nil?
626
+ normalized_key = key.downcase
627
+ dse.each do |_key, _value|
628
+ return _value if _key.downcase == normalized_key
629
+ end
630
+ []
631
+ end
632
+
633
+ def root_dse(attrs, options={})
634
+ found_attributes = nil
635
+ search(:base => "",
636
+ :scope => :base,
637
+ :attributes => attrs,
638
+ :limit => 1) do |dn, attributes|
639
+ found_attributes = attributes
640
+ end
641
+ found_attributes
642
+ end
643
+
644
+ def construct_uri(host, port, ssl)
645
+ protocol = ssl ? "ldaps" : "ldap"
646
+ URI.parse("#{protocol}://#{host}:#{port}").to_s
647
+ end
648
+
649
+ def target
650
+ return nil if @uri.nil?
651
+ if @with_start_tls
652
+ "#{@uri}(StartTLS)"
653
+ else
654
+ @uri
655
+ end
656
+ end
657
+
658
+ def log(name, info=nil)
659
+ if block_given?
660
+ result = nil
661
+ seconds = Benchmark.realtime {result = yield}
662
+ @runtime += seconds
663
+ log_info(name, seconds, info)
664
+ result
665
+ else
666
+ log_info(name, 0, info)
667
+ nil
668
+ end
669
+ rescue Exception
670
+ log_info("#{name}: FAILED", 0,
671
+ (info || {}).merge(:error => $!.class.name,
672
+ :error_message => $!.message))
673
+ raise
674
+ end
675
+
676
+ def format_log_entry(message, info=nil)
677
+ if ActiveLdap::Base.colorize_logging
678
+ if @@row_even
679
+ message_color, dump_color = "4;36;1", "0;1"
680
+ else
681
+ @@row_even = true
682
+ message_color, dump_color = "4;35;1", "0"
683
+ end
684
+ @@row_even = !@@row_even
685
+
686
+ log_entry = " \e[#{message_color}m#{message}\e[0m"
687
+ log_entry << ": \e[#{dump_color}m#{info.inspect}\e[0m" if info
688
+ log_entry
689
+ else
690
+ log_entry = message
691
+ log_entry += ": #{info.inspect}" if info
692
+ log_entry
693
+ end
694
+ end
695
+
696
+ def ensure_dn_string(dn)
697
+ if dn.is_a?(DN)
698
+ dn.to_s
699
+ else
700
+ dn
701
+ end
702
+ end
703
+ end
704
+ end
705
+ end