houston-devise_ldap_authenticatable 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/CHANGELOG.md +7 -0
  4. data/Gemfile +8 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +131 -0
  7. data/Rakefile +16 -0
  8. data/devise_ldap_authenticatable.gemspec +34 -0
  9. data/lib/devise_ldap_authenticatable.rb +50 -0
  10. data/lib/devise_ldap_authenticatable/exception.rb +6 -0
  11. data/lib/devise_ldap_authenticatable/ldap_adapter.rb +292 -0
  12. data/lib/devise_ldap_authenticatable/logger.rb +11 -0
  13. data/lib/devise_ldap_authenticatable/model.rb +95 -0
  14. data/lib/devise_ldap_authenticatable/routes.rb +8 -0
  15. data/lib/devise_ldap_authenticatable/schema.rb +14 -0
  16. data/lib/devise_ldap_authenticatable/strategy.rb +19 -0
  17. data/lib/devise_ldap_authenticatable/version.rb +3 -0
  18. data/lib/generators/devise_ldap_authenticatable/install_generator.rb +62 -0
  19. data/lib/generators/devise_ldap_authenticatable/templates/ldap.yml +51 -0
  20. data/spec/ldap/.gitignore +2 -0
  21. data/spec/ldap/base.ldif +73 -0
  22. data/spec/ldap/clear.ldif +26 -0
  23. data/spec/ldap/local.schema +6 -0
  24. data/spec/ldap/openldap-data/.gitignore +2 -0
  25. data/spec/ldap/openldap-data/run/.gitignore +2 -0
  26. data/spec/ldap/openldap-data/run/.gitkeep +0 -0
  27. data/spec/ldap/run-server +31 -0
  28. data/spec/ldap/server.pem +38 -0
  29. data/spec/ldap/slapd-test.conf.erb +107 -0
  30. data/spec/rails_app/Rakefile +7 -0
  31. data/spec/rails_app/app/controllers/application_controller.rb +7 -0
  32. data/spec/rails_app/app/controllers/posts_controller.rb +15 -0
  33. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  34. data/spec/rails_app/app/helpers/posts_helper.rb +2 -0
  35. data/spec/rails_app/app/models/post.rb +2 -0
  36. data/spec/rails_app/app/models/user.rb +10 -0
  37. data/spec/rails_app/app/views/layouts/application.html.erb +26 -0
  38. data/spec/rails_app/app/views/posts/index.html.erb +2 -0
  39. data/spec/rails_app/config.ru +4 -0
  40. data/spec/rails_app/config/application.rb +46 -0
  41. data/spec/rails_app/config/boot.rb +13 -0
  42. data/spec/rails_app/config/cucumber.yml +8 -0
  43. data/spec/rails_app/config/database.yml +25 -0
  44. data/spec/rails_app/config/environment.rb +5 -0
  45. data/spec/rails_app/config/environments/development.rb +21 -0
  46. data/spec/rails_app/config/environments/production.rb +46 -0
  47. data/spec/rails_app/config/environments/test.rb +34 -0
  48. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  49. data/spec/rails_app/config/initializers/devise.rb +242 -0
  50. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  51. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  52. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  53. data/spec/rails_app/config/initializers/session_store.rb +8 -0
  54. data/spec/rails_app/config/ldap.yml +22 -0
  55. data/spec/rails_app/config/ldap_with_boolean_ssl.yml +22 -0
  56. data/spec/rails_app/config/ldap_with_erb.yml +23 -0
  57. data/spec/rails_app/config/ldap_with_uid.yml +18 -0
  58. data/spec/rails_app/config/locales/devise.en.yml +58 -0
  59. data/spec/rails_app/config/locales/en.yml +5 -0
  60. data/spec/rails_app/config/routes.rb +64 -0
  61. data/spec/rails_app/config/ssl_ldap.yml +21 -0
  62. data/spec/rails_app/config/ssl_ldap_with_erb.yml +23 -0
  63. data/spec/rails_app/config/ssl_ldap_with_uid.yml +18 -0
  64. data/spec/rails_app/db/migrate/20100708120448_devise_create_users.rb +40 -0
  65. data/spec/rails_app/db/schema.rb +35 -0
  66. data/spec/rails_app/features/manage_logins.feature +35 -0
  67. data/spec/rails_app/features/step_definitions/login_steps.rb +21 -0
  68. data/spec/rails_app/features/step_definitions/web_steps.rb +219 -0
  69. data/spec/rails_app/features/support/env.rb +58 -0
  70. data/spec/rails_app/features/support/paths.rb +38 -0
  71. data/spec/rails_app/lib/tasks/.gitkeep +0 -0
  72. data/spec/rails_app/lib/tasks/cucumber.rake +53 -0
  73. data/spec/rails_app/public/404.html +26 -0
  74. data/spec/rails_app/public/422.html +26 -0
  75. data/spec/rails_app/public/500.html +26 -0
  76. data/spec/rails_app/public/images/rails.png +0 -0
  77. data/spec/rails_app/public/javascripts/application.js +2 -0
  78. data/spec/rails_app/public/javascripts/controls.js +965 -0
  79. data/spec/rails_app/public/javascripts/dragdrop.js +974 -0
  80. data/spec/rails_app/public/javascripts/effects.js +1123 -0
  81. data/spec/rails_app/public/javascripts/prototype.js +4874 -0
  82. data/spec/rails_app/public/javascripts/rails.js +118 -0
  83. data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
  84. data/spec/rails_app/script/cucumber +10 -0
  85. data/spec/rails_app/script/rails +6 -0
  86. data/spec/spec_helper.rb +47 -0
  87. data/spec/support/factories.rb +16 -0
  88. data/spec/unit/user_spec.rb +298 -0
  89. metadata +411 -0
@@ -0,0 +1,118 @@
1
+ document.observe("dom:loaded", function() {
2
+ function handleRemote(element) {
3
+ var method, url, params;
4
+
5
+ if (element.tagName.toLowerCase() === 'form') {
6
+ method = element.readAttribute('method') || 'post';
7
+ url = element.readAttribute('action');
8
+ params = element.serialize(true);
9
+ } else {
10
+ method = element.readAttribute('data-method') || 'get';
11
+ url = element.readAttribute('href');
12
+ params = {};
13
+ }
14
+
15
+ var event = element.fire("ajax:before");
16
+ if (event.stopped) return false;
17
+
18
+ new Ajax.Request(url, {
19
+ method: method,
20
+ parameters: params,
21
+ asynchronous: true,
22
+ evalScripts: true,
23
+
24
+ onLoading: function(request) { element.fire("ajax:loading", {request: request}); },
25
+ onLoaded: function(request) { element.fire("ajax:loaded", {request: request}); },
26
+ onInteractive: function(request) { element.fire("ajax:interactive", {request: request}); },
27
+ onComplete: function(request) { element.fire("ajax:complete", {request: request}); },
28
+ onSuccess: function(request) { element.fire("ajax:success", {request: request}); },
29
+ onFailure: function(request) { element.fire("ajax:failure", {request: request}); }
30
+ });
31
+
32
+ element.fire("ajax:after");
33
+ }
34
+
35
+ function handleMethod(element) {
36
+ var method, url, token_name, token;
37
+
38
+ method = element.readAttribute('data-method');
39
+ url = element.readAttribute('href');
40
+ csrf_param = $$('meta[name=csrf-param]').first();
41
+ csrf_token = $$('meta[name=csrf-token]').first();
42
+
43
+ var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
44
+ element.parentNode.appendChild(form);
45
+
46
+ if (method != 'post') {
47
+ var field = new Element('input', { type: 'hidden', name: '_method', value: method });
48
+ form.appendChild(field);
49
+ }
50
+
51
+ if (csrf_param) {
52
+ var param = csrf_param.readAttribute('content');
53
+ var token = csrf_token.readAttribute('content');
54
+ var field = new Element('input', { type: 'hidden', name: param, value: token });
55
+ form.appendChild(field);
56
+ }
57
+
58
+ form.submit();
59
+ }
60
+
61
+ $(document.body).observe("click", function(event) {
62
+ var message = event.findElement().readAttribute('data-confirm');
63
+ if (message && !confirm(message)) {
64
+ event.stop();
65
+ return false;
66
+ }
67
+
68
+ var element = event.findElement("a[data-remote]");
69
+ if (element) {
70
+ handleRemote(element);
71
+ event.stop();
72
+ return true;
73
+ }
74
+
75
+ var element = event.findElement("a[data-method]");
76
+ if (element) {
77
+ handleMethod(element);
78
+ event.stop();
79
+ return true;
80
+ }
81
+ });
82
+
83
+ // TODO: I don't think submit bubbles in IE
84
+ $(document.body).observe("submit", function(event) {
85
+ var element = event.findElement(),
86
+ message = element.readAttribute('data-confirm');
87
+ if (message && !confirm(message)) {
88
+ event.stop();
89
+ return false;
90
+ }
91
+
92
+ var inputs = element.select("input[type=submit][data-disable-with]");
93
+ inputs.each(function(input) {
94
+ input.disabled = true;
95
+ input.writeAttribute('data-original-value', input.value);
96
+ input.value = input.readAttribute('data-disable-with');
97
+ });
98
+
99
+ var element = event.findElement("form[data-remote]");
100
+ if (element) {
101
+ handleRemote(element);
102
+ event.stop();
103
+ }
104
+ });
105
+
106
+ $(document.body).observe("ajax:after", function(event) {
107
+ var element = event.findElement();
108
+
109
+ if (element.tagName.toLowerCase() === 'form') {
110
+ var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
111
+ inputs.each(function(input) {
112
+ input.value = input.readAttribute('data-original-value');
113
+ input.writeAttribute('data-original-value', null);
114
+ input.disabled = false;
115
+ });
116
+ }
117
+ });
118
+ });
File without changes
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
4
+ if vendored_cucumber_bin
5
+ load File.expand_path(vendored_cucumber_bin)
6
+ else
7
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
8
+ require 'cucumber'
9
+ load Cucumber::BINARY
10
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,47 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+
3
+ require File.expand_path("rails_app/config/environment.rb", File.dirname(__FILE__))
4
+ require 'rspec/rails'
5
+ require 'rspec/autorun'
6
+ require 'factory_girl' # not sure why this is not already required
7
+
8
+ Dir[File.expand_path("support/**/*.rb", File.dirname(__FILE__))].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ config.mock_with :rspec
12
+ config.use_transactional_fixtures = true
13
+ config.infer_base_class_for_anonymous_controllers = false
14
+ end
15
+
16
+ def ldap_root
17
+ File.expand_path('ldap', File.dirname(__FILE__))
18
+ end
19
+
20
+ def ldap_connect_string
21
+ if ENV["LDAP_SSL"]
22
+ "-x -H ldaps://localhost:3389 -D 'cn=admin,dc=test,dc=com' -w secret"
23
+ else
24
+ "-x -h localhost -p 3389 -D 'cn=admin,dc=test,dc=com' -w secret"
25
+ end
26
+ end
27
+
28
+ def reset_ldap_server!
29
+ if ENV["LDAP_SSL"]
30
+ `ldapmodify #{ldap_connect_string} -f #{File.join(ldap_root, 'clear.ldif')}`
31
+ `ldapadd #{ldap_connect_string} -f #{File.join(ldap_root, 'base.ldif')}`
32
+ else
33
+ `ldapmodify #{ldap_connect_string} -f #{File.join(ldap_root, 'clear.ldif')}`
34
+ `ldapadd #{ldap_connect_string} -f #{File.join(ldap_root, 'base.ldif')}`
35
+ end
36
+ end
37
+
38
+ def default_devise_settings!
39
+ ::Devise.ldap_logger = true
40
+ ::Devise.ldap_create_user = false
41
+ ::Devise.ldap_update_password = true
42
+ ::Devise.ldap_config = "#{Rails.root}/config/#{"ssl_" if ENV["LDAP_SSL"]}ldap.yml"
43
+ ::Devise.ldap_check_group_membership = false
44
+ ::Devise.ldap_check_attributes = false
45
+ ::Devise.ldap_auth_username_builder = Proc.new() {|attribute, login, ldap| "#{attribute}=#{login},#{ldap.base}" }
46
+ ::Devise.authentication_keys = [:email]
47
+ end
@@ -0,0 +1,16 @@
1
+ FactoryGirl.define do
2
+ factory :user do
3
+ email "example.user@test.com"
4
+ password "secret"
5
+ end
6
+
7
+ factory :admin, :class => User do
8
+ email "example.admin@test.com"
9
+ password "admin_secret"
10
+ end
11
+
12
+ factory :other, :class => User do
13
+ email "other.user@test.com"
14
+ password "other_secret"
15
+ end
16
+ end
@@ -0,0 +1,298 @@
1
+ require File.expand_path('../spec_helper', File.dirname(__FILE__))
2
+
3
+ describe 'Users' do
4
+
5
+ def should_be_validated(user, password, message = "Password is invalid")
6
+ assert(user.valid_ldap_authentication?(password), message)
7
+ end
8
+
9
+ def should_not_be_validated(user, password, message = "Password is not properly set")
10
+ assert(!user.valid_ldap_authentication?(password), message)
11
+ end
12
+
13
+ describe "With default settings" do
14
+ before do
15
+ default_devise_settings!
16
+ reset_ldap_server!
17
+ end
18
+
19
+ describe "look up and ldap user" do
20
+ it "should return true for a user that does exist in LDAP" do
21
+ assert_equal true, ::Devise::LdapAdapter.valid_login?('example.user@test.com')
22
+ end
23
+
24
+ it "should return false for a user that doesn't exist in LDAP" do
25
+ assert_equal false, ::Devise::LdapAdapter.valid_login?('barneystinson')
26
+ end
27
+ end
28
+
29
+ describe "create a basic user" do
30
+ before do
31
+ @user = Factory.create(:user)
32
+ end
33
+
34
+ it "should check for password validation" do
35
+ assert_equal(@user.email, "example.user@test.com")
36
+ should_be_validated @user, "secret"
37
+ should_not_be_validated @user, "wrong_secret"
38
+ should_not_be_validated @user, "Secret"
39
+ end
40
+ end
41
+
42
+ describe "change a LDAP password" do
43
+ before do
44
+ @user = Factory.create(:user)
45
+ end
46
+
47
+ it "should change password" do
48
+ should_be_validated @user, "secret"
49
+ @user.reset_password!("changed","changed")
50
+ should_be_validated @user, "changed", "password was not changed properly on the LDAP sevrer"
51
+ end
52
+
53
+ it "should not allow to change password if setting is false" do
54
+ should_be_validated @user, "secret"
55
+ ::Devise.ldap_update_password = false
56
+ @user.reset_password!("wrong_secret", "wrong_secret")
57
+ should_not_be_validated @user, "wrong_secret"
58
+ should_be_validated @user, "secret"
59
+ end
60
+ end
61
+
62
+ describe "create new local user if user is in LDAP" do
63
+
64
+ before do
65
+ assert(User.all.blank?, "There shouldn't be any users in the database")
66
+ end
67
+
68
+ it "should don't create user in the database" do
69
+ @user = User.authenticate_with_ldap(:email => "example.user@test.com", :password => "secret")
70
+ assert(User.all.blank?)
71
+ end
72
+
73
+ describe "creating users is enabled" do
74
+ before do
75
+ ::Devise.ldap_create_user = true
76
+ end
77
+
78
+ it "should create a user in the database" do
79
+ @user = User.authenticate_with_ldap(:email => "example.user@test.com", :password => "secret")
80
+ assert_equal(User.all.size, 1)
81
+ User.all.collect(&:email).should include("example.user@test.com")
82
+ end
83
+
84
+ it "should not create a user in the database if the password is wrong_secret" do
85
+ @user = User.authenticate_with_ldap(:email => "example.user", :password => "wrong_secret")
86
+ assert(User.all.blank?, "There's users in the database")
87
+ end
88
+
89
+ it "should create a user if the user is not in LDAP" do
90
+ @user = User.authenticate_with_ldap(:email => "wrong_secret.user@test.com", :password => "wrong_secret")
91
+ assert(User.all.blank?, "There's users in the database")
92
+ end
93
+
94
+ it "should create a user in the database if case insensitivity does not matter" do
95
+ ::Devise.case_insensitive_keys = []
96
+ @user = Factory.create(:user)
97
+
98
+ expect do
99
+ User.authenticate_with_ldap(:email => "EXAMPLE.user@test.com", :password => "secret")
100
+ end.to change { User.count }.by(1)
101
+ end
102
+
103
+ it "should not create a user in the database if case insensitivity matters" do
104
+ ::Devise.case_insensitive_keys = [:email]
105
+ @user = Factory.create(:user)
106
+
107
+ expect do
108
+ User.authenticate_with_ldap(:email => "EXAMPLE.user@test.com", :password => "secret")
109
+ end.to_not change { User.count }
110
+ end
111
+
112
+ it "should create a user with downcased email in the database if case insensitivity matters" do
113
+ ::Devise.case_insensitive_keys = [:email]
114
+
115
+ @user = User.authenticate_with_ldap(:email => "EXAMPLE.user@test.com", :password => "secret")
116
+ User.all.collect(&:email).should include("example.user@test.com")
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ describe "use groups for authorization" do
123
+ before do
124
+ @admin = Factory.create(:admin)
125
+ @user = Factory.create(:user)
126
+ ::Devise.authentication_keys = [:email]
127
+ ::Devise.ldap_check_group_membership = true
128
+ end
129
+
130
+ it "should admin should be allowed in" do
131
+ should_be_validated @admin, "admin_secret"
132
+ end
133
+
134
+ it "should admin should have the proper groups set" do
135
+ @admin.ldap_groups.should include('cn=admins,ou=groups,dc=test,dc=com')
136
+ end
137
+
138
+ it "should user should not be allowed in" do
139
+ should_not_be_validated @user, "secret"
140
+ end
141
+ end
142
+
143
+ describe "check group membership" do
144
+ before do
145
+ @admin = Factory.create(:admin)
146
+ @user = Factory.create(:user)
147
+ end
148
+
149
+ it "should return true for admin being in the admins group" do
150
+ assert_equal true, @admin.in_ldap_group?('cn=admins,ou=groups,dc=test,dc=com')
151
+ end
152
+
153
+ it "should return false for admin being in the admins group using the 'foobar' group attribute" do
154
+ assert_equal false, @admin.in_ldap_group?('cn=admins,ou=groups,dc=test,dc=com', 'foobar')
155
+ end
156
+
157
+ it "should return true for user being in the users group" do
158
+ assert_equal true, @user.in_ldap_group?('cn=users,ou=groups,dc=test,dc=com')
159
+ end
160
+
161
+ it "should return false for user being in the admins group" do
162
+ assert_equal false, @user.in_ldap_group?('cn=admins,ou=groups,dc=test,dc=com')
163
+ end
164
+ end
165
+
166
+
167
+ describe "use role attribute for authorization" do
168
+ before do
169
+ @admin = Factory.create(:admin)
170
+ @user = Factory.create(:user)
171
+ ::Devise.ldap_check_attributes = true
172
+ end
173
+
174
+ it "should admin should be allowed in" do
175
+ should_be_validated @admin, "admin_secret"
176
+ end
177
+
178
+ it "should user should not be allowed in" do
179
+ should_not_be_validated @user, "secret"
180
+ end
181
+ end
182
+
183
+ describe "use admin setting to bind" do
184
+ before do
185
+ @admin = Factory.create(:admin)
186
+ @user = Factory.create(:user)
187
+ ::Devise.ldap_use_admin_to_bind = true
188
+ end
189
+
190
+ it "should description" do
191
+ should_be_validated @admin, "admin_secret"
192
+ end
193
+ end
194
+
195
+ end
196
+
197
+ describe "use uid for login" do
198
+ before do
199
+ default_devise_settings!
200
+ reset_ldap_server!
201
+ ::Devise.ldap_config = "#{Rails.root}/config/#{"ssl_" if ENV["LDAP_SSL"]}ldap_with_uid.yml"
202
+ ::Devise.authentication_keys = [:uid]
203
+ end
204
+
205
+ describe "description" do
206
+ before do
207
+ @admin = Factory.create(:admin)
208
+ @user = Factory.create(:user, :uid => "example_user")
209
+ end
210
+
211
+ it "should be able to authenticate using uid" do
212
+ should_be_validated @user, "secret"
213
+ should_not_be_validated @admin, "admin_secret"
214
+ end
215
+ end
216
+
217
+ describe "create user" do
218
+ before do
219
+ ::Devise.ldap_create_user = true
220
+ end
221
+
222
+ it "should create a user in the database" do
223
+ @user = User.authenticate_with_ldap(:uid => "example_user", :password => "secret")
224
+ assert_equal(User.all.size, 1)
225
+ User.all.collect(&:uid).should include("example_user")
226
+ end
227
+
228
+ it "should call ldap_before_save hooks" do
229
+ User.class_eval do
230
+ def ldap_before_save
231
+ @foobar = 'foobar'
232
+ end
233
+ end
234
+ user = User.authenticate_with_ldap(:uid => "example_user", :password => "secret")
235
+ assert_equal 'foobar', user.instance_variable_get(:"@foobar")
236
+ User.class_eval do
237
+ undef ldap_before_save
238
+ end
239
+ end
240
+
241
+ it "should not call ldap_before_save hook if not defined" do
242
+ assert_nothing_raised do
243
+ should_be_validated Factory.create(:user, :uid => "example_user"), "secret"
244
+ end
245
+ end
246
+ end
247
+ end
248
+
249
+ describe "using ERB in the config file" do
250
+ before do
251
+ default_devise_settings!
252
+ reset_ldap_server!
253
+ ::Devise.ldap_config = "#{Rails.root}/config/#{"ssl_" if ENV["LDAP_SSL"]}ldap_with_erb.yml"
254
+ end
255
+
256
+ describe "authenticate" do
257
+ before do
258
+ @admin = Factory.create(:admin)
259
+ @user = Factory.create(:user)
260
+ end
261
+
262
+ it "should be able to authenticate" do
263
+ should_be_validated @user, "secret"
264
+ should_be_validated @admin, "admin_secret"
265
+ end
266
+ end
267
+ end
268
+
269
+ describe "using variants in the config file" do
270
+ before do
271
+ default_devise_settings!
272
+ reset_ldap_server!
273
+ ::Devise.ldap_config = Rails.root.join 'config', 'ldap_with_boolean_ssl.yml'
274
+ end
275
+
276
+ it "should not fail if config file has ssl: true" do
277
+ assert_nothing_raised do
278
+ Devise::LdapAdapter::LdapConnect.new
279
+ end
280
+ end
281
+ end
282
+
283
+ describe "use username builder" do
284
+ before do
285
+ default_devise_settings!
286
+ reset_ldap_server!
287
+ ::Devise.ldap_auth_username_builder = Proc.new() do |attribute, login, ldap|
288
+ "#{attribute}=#{login},ou=others,dc=test,dc=com"
289
+ end
290
+ @other = Factory.create(:other)
291
+ end
292
+
293
+ it "should be able to authenticate" do
294
+ should_be_validated @other, "other_secret"
295
+ end
296
+ end
297
+
298
+ end