activeldap3 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
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