devise_ldap_authenticatable 0.8.1 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 83f8abeb23a6a4f7ba011a20858268cc9bc1b0f8
4
- data.tar.gz: dca093640944a95c13037086cc74c94a39f9af02
2
+ SHA256:
3
+ metadata.gz: 7044550949ddebd6ea7cc11cf8ed2256b892f2c27dd2fc316a7c5a2b4bdcf685
4
+ data.tar.gz: ba36af309f585a37a6e2775810b62bc95a4c5d4203e9b2f7d174418c20a39e07
5
5
  SHA512:
6
- metadata.gz: 65d9174c9f3d1231a895da94b731662a1fc5f4b3018b7626c95e71c94d739520d2737dd3ce27a999e60d9f64503b95fb3c68224fcdcb3da842570ec18fd43af6
7
- data.tar.gz: 7cf26b625215614e7527745d3a32f449e592b56f7957cbad0a40cc253de4ccd63f6ef419d6854dcf8be28a555d25dd03c5de38eccef1e8279a56d9ece833099a
6
+ metadata.gz: d076e9ed84c61fc77dfd9f7006b594a2c841a600491d3b0c92d5bde42832b4df3324ebbb6df447221078f3d0dd5b91540d2882cec2c1e9d41bc5c84117a019e6
7
+ data.tar.gz: 9f2f642e37bf8a51db04a01aa58d93f96ceea8daf91ef7b0af3e0357c5289962c4e583aef57fb10a1f496b55d54012176b42086a3e417e482932733ace47b40f
data/.gitignore CHANGED
@@ -7,4 +7,5 @@ test/ldap/openldap-data/*
7
7
  test/ldap/openldap-data/run/slapd.*
8
8
  test/rails_app/tmp
9
9
  pkg/*
10
- *.gem
10
+ *.gem
11
+ .vscode
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  Devise LDAP Authenticatable
2
2
  ===========================
3
- [![Gem Version](https://badge.fury.io/rb/devise_ldap_authenticatable.png)](http://badge.fury.io/rb/devise_ldap_authenticatable)
4
- [![Code Climate](https://codeclimate.com/github/cschiewek/devise_ldap_authenticatable.png)](https://codeclimate.com/github/cschiewek/devise_ldap_authenticatable)
5
- [![Dependency Status](https://gemnasium.com/cschiewek/devise_ldap_authenticatable.png)](https://gemnasium.com/cschiewek/devise_ldap_authenticatable)
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/devise_ldap_authenticatable.svg)](http://badge.fury.io/rb/devise_ldap_authenticatable)
5
+ [![Code Climate](https://codeclimate.com/github/cschiewek/devise_ldap_authenticatable.svg)](https://codeclimate.com/github/cschiewek/devise_ldap_authenticatable)
6
6
 
7
7
  Devise LDAP Authenticatable is a LDAP based authentication strategy for the [Devise](http://github.com/plataformatec/devise) authentication framework.
8
8
 
@@ -10,25 +10,29 @@ If you are building applications for use within your organization which require
10
10
 
11
11
  Devise LDAP Authenticatable works in replacement of Database Authenticatable. This devise plugin has not been tested with DatabaseAuthenticatable enabled at the same time. This is meant as a drop in replacement for DatabaseAuthenticatable allowing for a semi single sign on approach.
12
12
 
13
- For a screencast with an example application, please visit: [http://random-rails.blogspot.com/2010/07/ldap-authentication-with-devise.html](http://random-rails.blogspot.com/2010/07/ldap-authentication-with-devise.html)
13
+ For a screencast with an example application, please visit: [http://corrupt.net/2010/07/05/LDAP-Authentication-With-Devise/](http://corrupt.net/2010/07/05/LDAP-Authentication-With-Devise/)
14
14
 
15
15
  Prerequisites
16
16
  -------------
17
17
  * devise ~> 3.0.0 (which requires rails ~> 4.0)
18
- * net-ldap ~> 0.3.1
18
+ * net-ldap ~> 0.6.0
19
19
 
20
20
  Note: Rails 3.x / Devise 2.x has been moved to the 0.7 branch. All 0.7.x gems will support Rails 3, where as 0.8.x will support Rails 4.
21
21
 
22
+ If you are transitioning from having Devise manage your users' passwords in the database to using LDAP auth, you may have to update your `users` table to make `encrypted_password` nullable, or else the LDAP user insert will fail.
23
+
22
24
  Usage
23
25
  -----
24
26
  In the Gemfile for your application:
25
27
 
26
- gem "devise_ldap_authenticatable"
27
-
28
+ ```ruby
29
+ gem "devise_ldap_authenticatable"
30
+ ```
28
31
  To get the latest version, pull directly from github instead of the gem:
29
32
 
30
- gem "devise_ldap_authenticatable", :git => "git://github.com/cschiewek/devise_ldap_authenticatable.git"
31
-
33
+ ```ruby
34
+ gem "devise_ldap_authenticatable", :git => "git://github.com/cschiewek/devise_ldap_authenticatable.git"
35
+ ```
32
36
 
33
37
  Setup
34
38
  -----
@@ -41,7 +45,7 @@ Run the rails generator for `devise_ldap_authenticatable`
41
45
 
42
46
  rails generate devise_ldap_authenticatable:install [options]
43
47
 
44
- This will install the sample.yml, update the devise.rb initializer, and update your user model. There are some options you can pass to it:
48
+ This will install the ldap.yml, update the devise.rb initializer, and update your user model. There are some options you can pass to it:
45
49
 
46
50
  Options:
47
51
 
@@ -57,13 +61,13 @@ Querying LDAP
57
61
  -------------
58
62
  Given that `ldap_create_user` is set to true and you are authenticating with username, you can query an LDAP server for other attributes.
59
63
 
60
- in your user model:
61
-
62
- before_save :get_ldap_email
64
+ in your user model you have to simply define `ldap_before_save` method:
63
65
 
64
- def get_ldap_email
65
- self.email = Devise::LdapAdapter.get_ldap_param(self.username,"mail")
66
- end
66
+ ```ruby
67
+ def ldap_before_save
68
+ self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first
69
+ end
70
+ ```
67
71
 
68
72
  Configuration
69
73
  -------------
@@ -71,25 +75,22 @@ In initializer `config/initializers/devise.rb` :
71
75
 
72
76
  * `ldap_logger` _(default: true)_
73
77
  * If set to true, will log LDAP queries to the Rails logger.
74
-
75
78
  * `ldap_create_user` _(default: false)_
76
- * If set to true, all valid LDAP users will be allowed to login and an appropriate user record will be created.
77
- If set to false, you will have to create the user record before they will be allowed to login.
78
-
79
+ * If set to true, all valid LDAP users will be allowed to login and an appropriate user record will be created. If set to false, you will have to create the user record before they will be allowed to login.
79
80
  * `ldap_config` _(default: #{Rails.root}/config/ldap.yml)_
80
- * Where to find the LDAP config file. Commented out to use the default, change if needed.
81
-
81
+ * Where to find the LDAP config file. Commented out to use the default, change if needed.
82
82
  * `ldap_update_password` _(default: true)_
83
83
  * When doing password resets, if true will update the LDAP server. Requires admin password in the ldap.yml
84
-
85
84
  * `ldap_check_group_membership` _(default: false)_
86
85
  * When set to true, the user trying to login will be checked to make sure they are in all of groups specified in the ldap.yml file.
87
-
88
86
  * `ldap_check_attributes` _(default: false)_
89
- * When set to true, the user trying to login will be checked to make sure they have all of the attributes in the ldap.yml file.
90
-
87
+ * When set to true, the user trying to login will be checked to make sure their attributes match those specified in the ldap.yml file.
88
+ * `ldap_check_attributes_presence` _(default: false)_
89
+ * When set to true, the user trying to login will be checked against all `require_attribute_presence` attributes in the ldap.yml file, either present _(attr: true)_,or not present _(attr: false)_.
91
90
  * `ldap_use_admin_to_bind` _(default: false)_
92
91
  * When set to true, the admin user will be used to bind to the LDAP server during authentication.
92
+ * `ldap_check_group_membership_without_admin` _(default: false)_
93
+ * When set to true, the group membership check is done with the user's own credentials rather than with admin credentials. Since these credentials are only available to the Devise user model during the login flow, the group check function will not work if a group check is performed when this option is true outside of the login flow (e.g., before particular actions).
93
94
 
94
95
  Advanced Configuration
95
96
  ----------------------
@@ -97,10 +98,12 @@ These parameters will be added to `config/initializers/devise.rb` when you pass
97
98
 
98
99
  * `ldap_auth_username_builder` _(default: `Proc.new() {|attribute, login, ldap| "#{attribute}=#{login},#{ldap.base}" }`)_
99
100
  * You can pass a proc to the username option to explicitly specify the format that you search for a users' DN on your LDAP server.
101
+ * `ldap_auth_password_build` _(default: `Proc.new() {|new_password| Net::LDAP::Password.generate(:sha, new_password) }`)_
102
+ * Optionally you can define a proc to create custom password encrption when user reset password
100
103
 
101
104
  Troubleshooting
102
105
  --------------
103
- **Using a "username" instead of an "email":** The field that is used for logins is the first key that's configured in the `config/devise.rb` file under `config.authentication_keys`, which by default is email. For help changing this, please see the [Railscast](http://railscasts.com/episodes/210-customizing-devise) that goes through how to customize Devise.
106
+ **Using a "username" instead of an "email":** The field that is used for logins is the first key that's configured in the `config/initializers/devise.rb` file under `config.authentication_keys`, which by default is email. For help changing this, please see the [Railscast](http://railscasts.com/episodes/210-customizing-devise) that goes through how to customize Devise. Also, this [documentation](https://github.com/plataformatec/devise/wiki/How-To%3a-Allow-users-to-sign-in-using-their-username-or-email-address) from Devise can be very helpful.
104
107
 
105
108
  **SSL certificate invalid:** If you're using a test LDAP server running a self-signed SSL certificate, make sure the appropriate root certificate is installed on your system. Alternately, you may temporarily disable certificate checking for SSL by modifying your system LDAP configuration (e.g., `/etc/openldap/ldap.conf` or `/etc/ldap/ldap.conf`) to read `TLS_REQCERT never`.
106
109
 
@@ -111,13 +114,14 @@ For additional support, questions or discussions, please see the discussion foru
111
114
 
112
115
  Development guide
113
116
  ------------
114
- To contribute to `devise_ldap_authentication`, you should be able to run a test OpenLDAP server. Specifically, you need the `slapd`, `ldapadd`, and `ldapmodify` binaries.
115
117
 
116
- This seems to come out of the box with Mac OS X 10.6.
118
+ Devise LDAP Authenticatable uses a running OpenLDAP server to do automated acceptance tests. You'll need the executables `slapd`, `ldapadd`, and `ldapmodify`.
119
+
120
+ On OS X, this is available out of the box.
117
121
 
118
- On Ubuntu (tested on 12.04 and 12.10), you can run `sudo apt-get install slapd ldap-utils`. You will also likely have to add the `spec/ldap` directory of your local git clone to the slapd [apparmor](https://wiki.ubuntu.com/DebuggingApparmor) profile `/etc/apparmor.d/usr.sbin.slapd` if you get permissions errors. Something like this should do:
122
+ On Ubuntu, you can install OpenLDAP with `sudo apt-get install slapd ldap-utils`. If slapd runs under AppArmor, add an exception like this to `/etc/apparmor.d/local/usr.sbin.slapd` to let slapd read our configs (reload using `sudo service apparmor reload` afterwards).
119
123
 
120
- /path/to/devise_ldap_authenticatable/spec/ldap/** rw,$
124
+ /path/to/devise_ldap_authenticatable/spec/ldap/** rw,
121
125
 
122
126
  To start hacking on `devise_ldap_authentication`, clone the github repository, start the test LDAP server, and run the rake test task:
123
127
 
@@ -128,7 +132,7 @@ To start hacking on `devise_ldap_authentication`, clone the github repository, s
128
132
  # in a separate console or backgrounded
129
133
  ./spec/ldap/run-server
130
134
 
131
- bundle exec rake db:migrate # first time only
135
+ RAILS_ENV=test bundle exec rake db:migrate # first time only
132
136
  bundle exec rake spec
133
137
 
134
138
  References
@@ -18,16 +18,16 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_dependency('devise', '>= 3.0')
22
- s.add_dependency('net-ldap', '>= 0.3.1', '< 0.6.0')
21
+ s.add_dependency 'devise', '>= 3.4.1'
22
+ s.add_dependency 'net-ldap', '>= 0.16.0'
23
23
 
24
- s.add_development_dependency('rake', '>= 0.9')
25
- s.add_development_dependency('rdoc', '>= 3')
26
- s.add_development_dependency('rails', '>= 4.0')
27
- s.add_development_dependency('sqlite3')
28
- s.add_development_dependency('factory_girl_rails', '~> 1.0')
29
- s.add_development_dependency('factory_girl', '~> 2.0')
30
- s.add_development_dependency('rspec-rails')
24
+ s.add_development_dependency 'rake', '>= 0.9'
25
+ s.add_development_dependency 'rdoc', '>= 3'
26
+ s.add_development_dependency 'rails', '>= 4.0'
27
+ s.add_development_dependency 'sqlite3'
28
+ s.add_development_dependency 'factory_girl_rails', '~> 1.0'
29
+ s.add_development_dependency 'factory_girl', '~> 2.0'
30
+ s.add_development_dependency 'rspec-rails'
31
31
 
32
32
  %w{database_cleaner capybara launchy}.each do |dep|
33
33
  s.add_development_dependency(dep)
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require 'devise'
3
+ require 'net/ldap'
3
4
 
4
5
  require 'devise_ldap_authenticatable/exception'
5
6
  require 'devise_ldap_authenticatable/logger'
@@ -11,29 +12,40 @@ module Devise
11
12
  # Allow logging
12
13
  mattr_accessor :ldap_logger
13
14
  @@ldap_logger = true
14
-
15
+
15
16
  # Add valid users to database
16
17
  mattr_accessor :ldap_create_user
17
18
  @@ldap_create_user = false
18
-
19
+
20
+ # A path to YAML config file or a Proc that returns a
21
+ # configuration hash
19
22
  mattr_accessor :ldap_config
20
23
  # @@ldap_config = "#{Rails.root}/config/ldap.yml"
21
-
24
+
22
25
  mattr_accessor :ldap_update_password
23
26
  @@ldap_update_password = true
24
-
27
+
25
28
  mattr_accessor :ldap_check_group_membership
26
29
  @@ldap_check_group_membership = false
27
-
30
+
31
+ mattr_accessor :ldap_check_group_membership_without_admin
32
+ @@ldap_check_group_membership_without_admin = false
33
+
28
34
  mattr_accessor :ldap_check_attributes
29
35
  @@ldap_check_role_attribute = false
30
-
36
+
37
+ mattr_accessor :ldap_check_attributes_presence
38
+ @@ldap_check_attributes_presence = false
39
+
31
40
  mattr_accessor :ldap_use_admin_to_bind
32
41
  @@ldap_use_admin_to_bind = false
33
-
42
+
34
43
  mattr_accessor :ldap_auth_username_builder
35
44
  @@ldap_auth_username_builder = Proc.new() {|attribute, login, ldap| "#{attribute}=#{login},#{ldap.base}" }
36
45
 
46
+ mattr_accessor :ldap_auth_password_builder
47
+ @@ldap_auth_password_builder = Proc.new() {|new_password| Net::LDAP::Password.generate(:sha, new_password) }
48
+
37
49
  mattr_accessor :ldap_ad_group_check
38
50
  @@ldap_ad_group_check = false
39
51
  end
@@ -44,4 +56,4 @@ Devise.add_module(:ldap_authenticatable,
44
56
  :route => :session, ## This will add the routes, rather than in the routes.rb
45
57
  :strategy => true,
46
58
  :controller => :sessions,
47
- :model => 'devise_ldap_authenticatable/model')
59
+ :model => 'devise_ldap_authenticatable/model')
@@ -15,6 +15,16 @@ module Devise
15
15
  resource.authorized?
16
16
  end
17
17
 
18
+ def self.expired_valid_credentials?(login, password_plaintext)
19
+ options = {:login => login,
20
+ :password => password_plaintext,
21
+ :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder,
22
+ :admin => ::Devise.ldap_use_admin_to_bind}
23
+
24
+ resource = Devise::LDAP::Connection.new(options)
25
+ resource.expired_valid_credentials?
26
+ end
27
+
18
28
  def self.update_password(login, new_password)
19
29
  options = {:login => login,
20
30
  :new_password => new_password,
@@ -26,7 +36,7 @@ module Devise
26
36
  end
27
37
 
28
38
  def self.update_own_password(login, new_password, current_password)
29
- set_ldap_param(login, :userpassword, Net::LDAP::Password.generate(:sha, new_password), current_password)
39
+ set_ldap_param(login, :userPassword, ::Devise.ldap_auth_password_builder.call(new_password), current_password)
30
40
  end
31
41
 
32
42
  def self.ldap_connect(login)
@@ -34,7 +44,7 @@ module Devise
34
44
  :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder,
35
45
  :admin => ::Devise.ldap_use_admin_to_bind}
36
46
 
37
- resource = Devise::LDAP::Connection.new(options)
47
+ Devise::LDAP::Connection.new(options)
38
48
  end
39
49
 
40
50
  def self.valid_login?(login)
@@ -54,18 +64,18 @@ module Devise
54
64
  end
55
65
 
56
66
  def self.set_ldap_param(login, param, new_value, password = nil)
57
- options = { :login => login,
58
- :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder,
59
- :password => password }
67
+ options = {:login => login,
68
+ :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder,
69
+ :password => password }
60
70
 
61
71
  resource = Devise::LDAP::Connection.new(options)
62
72
  resource.set_param(param, new_value)
63
73
  end
64
74
 
65
75
  def self.delete_ldap_param(login, param, password = nil)
66
- options = { :login => login,
67
- :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder,
68
- :password => password }
76
+ options = {:login => login,
77
+ :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder,
78
+ :password => password }
69
79
 
70
80
  resource = Devise::LDAP::Connection.new(options)
71
81
  resource.delete_param(param)
@@ -79,9 +89,6 @@ module Devise
79
89
  def self.get_ldap_entry(login)
80
90
  self.ldap_connect(login).search_for_login
81
91
  end
82
-
83
92
  end
84
-
85
93
  end
86
-
87
- end
94
+ end
@@ -4,22 +4,34 @@ module Devise
4
4
  attr_reader :ldap, :login
5
5
 
6
6
  def initialize(params = {})
7
- ldap_config = YAML.load(ERB.new(File.read(::Devise.ldap_config || "#{Rails.root}/config/ldap.yml")).result)[Rails.env]
7
+ if ::Devise.ldap_config.is_a?(Proc)
8
+ ldap_config = ::Devise.ldap_config.call
9
+ else
10
+ ldap_config = YAML.load(ERB.new(File.read(::Devise.ldap_config || "#{Rails.root}/config/ldap.yml")).result)[Rails.env]
11
+ end
8
12
  ldap_options = params
13
+
14
+ # Allow `ssl: true` shorthand in YAML, but enable more control with `encryption`
9
15
  ldap_config["ssl"] = :simple_tls if ldap_config["ssl"] === true
10
16
  ldap_options[:encryption] = ldap_config["ssl"].to_sym if ldap_config["ssl"]
17
+ ldap_options[:encryption] = ldap_config["encryption"] if ldap_config["encryption"]
11
18
 
12
19
  @ldap = Net::LDAP.new(ldap_options)
13
20
  @ldap.host = ldap_config["host"]
14
21
  @ldap.port = ldap_config["port"]
15
22
  @ldap.base = ldap_config["base"]
16
23
  @attribute = ldap_config["attribute"]
24
+ @allow_unauthenticated_bind = ldap_config["allow_unauthenticated_bind"]
25
+
17
26
  @ldap_auth_username_builder = params[:ldap_auth_username_builder]
18
27
 
19
28
  @group_base = ldap_config["group_base"]
20
29
  @check_group_membership = ldap_config.has_key?("check_group_membership") ? ldap_config["check_group_membership"] : ::Devise.ldap_check_group_membership
30
+ @check_group_membership_without_admin = ldap_config.has_key?("check_group_membership_without_admin") ? ldap_config["check_group_membership_without_admin"] : ::Devise.ldap_check_group_membership_without_admin
21
31
  @required_groups = ldap_config["required_groups"]
32
+ @group_membership_attribute = ldap_config.has_key?("group_membership_attribute") ? ldap_config["group_membership_attribute"] : "uniqueMember"
22
33
  @required_attributes = ldap_config["require_attribute"]
34
+ @required_attributes_presence = ldap_config["require_attribute_presence"]
23
35
 
24
36
  @ldap.auth ldap_config["admin_user"], ldap_config["admin_password"] if params[:admin]
25
37
 
@@ -37,19 +49,19 @@ module Devise
37
49
  end
38
50
 
39
51
  def dn
40
- DeviseLdapAuthenticatable::Logger.send("LDAP dn lookup: #{@attribute}=#{@login}")
41
- ldap_entry = search_for_login
42
- if ldap_entry.nil?
43
- @ldap_auth_username_builder.call(@attribute,@login,@ldap)
44
- else
45
- ldap_entry.dn
52
+ @dn ||= begin
53
+ DeviseLdapAuthenticatable::Logger.send("LDAP dn lookup: #{@attribute}=#{@login}")
54
+ ldap_entry = search_for_login
55
+ if ldap_entry.nil?
56
+ @ldap_auth_username_builder.call(@attribute,@login,@ldap)
57
+ else
58
+ ldap_entry.dn
59
+ end
46
60
  end
47
61
  end
48
62
 
49
63
  def ldap_param_value(param)
50
- filter = Net::LDAP::Filter.eq(@attribute.to_s, @login.to_s)
51
- ldap_entry = nil
52
- @ldap.search(:filter => filter) {|entry| ldap_entry = entry}
64
+ ldap_entry = search_for_login
53
65
 
54
66
  if ldap_entry
55
67
  unless ldap_entry[param].empty?
@@ -67,6 +79,7 @@ module Devise
67
79
  end
68
80
 
69
81
  def authenticate!
82
+ return false unless (@password.present? || @allow_unauthenticated_bind)
70
83
  @ldap.auth(dn, @password)
71
84
  @ldap.bind
72
85
  end
@@ -75,10 +88,25 @@ module Devise
75
88
  authenticate!
76
89
  end
77
90
 
91
+ def last_message_bad_credentials?
92
+ @ldap.get_operation_result.error_message.to_s.include? 'AcceptSecurityContext error, data 52e'
93
+ end
94
+
95
+ def last_message_expired_credentials?
96
+ @ldap.get_operation_result.error_message.to_s.include? 'AcceptSecurityContext error, data 773'
97
+ end
98
+
78
99
  def authorized?
79
100
  DeviseLdapAuthenticatable::Logger.send("Authorizing user #{dn}")
80
101
  if !authenticated?
81
- DeviseLdapAuthenticatable::Logger.send("Not authorized because not authenticated.")
102
+ if last_message_bad_credentials?
103
+ DeviseLdapAuthenticatable::Logger.send("Not authorized because of invalid credentials.")
104
+ elsif last_message_expired_credentials?
105
+ DeviseLdapAuthenticatable::Logger.send("Not authorized because of expired credentials.")
106
+ else
107
+ DeviseLdapAuthenticatable::Logger.send("Not authorized because not authenticated.")
108
+ end
109
+
82
110
  return false
83
111
  elsif !in_required_groups?
84
112
  DeviseLdapAuthenticatable::Logger.send("Not authorized because not in required groups.")
@@ -86,17 +114,26 @@ module Devise
86
114
  elsif !has_required_attribute?
87
115
  DeviseLdapAuthenticatable::Logger.send("Not authorized because does not have required attribute.")
88
116
  return false
117
+ elsif !has_required_attribute_presence?
118
+ DeviseLdapAuthenticatable::Logger.send("Not authorized because does not have required attribute present.")
119
+ return false
89
120
  else
90
121
  return true
91
122
  end
92
123
  end
93
124
 
125
+ def expired_valid_credentials?
126
+ DeviseLdapAuthenticatable::Logger.send("Authorizing user #{dn}")
127
+
128
+ !authenticated? && last_message_expired_credentials?
129
+ end
130
+
94
131
  def change_password!
95
- update_ldap(:userpassword => Net::LDAP::Password.generate(:sha, @new_password))
132
+ update_ldap(:userPassword => ::Devise.ldap_auth_password_builder.call(@new_password))
96
133
  end
97
134
 
98
135
  def in_required_groups?
99
- return true unless @check_group_membership
136
+ return true unless @check_group_membership || @check_group_membership_without_admin
100
137
 
101
138
  ## FIXME set errors here, the ldap.yml isn't set properly.
102
139
  return false if @required_groups.nil?
@@ -114,23 +151,29 @@ module Devise
114
151
  def in_group?(group_name, group_attribute = LDAP::DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY)
115
152
  in_group = false
116
153
 
117
- admin_ldap = Connection.admin
154
+ if @check_group_membership_without_admin
155
+ group_checking_ldap = @ldap
156
+ else
157
+ group_checking_ldap = Connection.admin
158
+ end
118
159
 
119
160
  unless ::Devise.ldap_ad_group_check
120
- admin_ldap.search(:base => group_name, :scope => Net::LDAP::SearchScope_BaseObject) do |entry|
161
+ group_checking_ldap.search(:base => group_name, :scope => Net::LDAP::SearchScope_BaseObject) do |entry|
121
162
  if entry[group_attribute].include? dn
122
163
  in_group = true
164
+ DeviseLdapAuthenticatable::Logger.send("User #{dn} IS included in group: #{group_name}")
123
165
  end
124
166
  end
125
167
  else
126
168
  # AD optimization - extension will recursively check sub-groups with one query
127
169
  # "(memberof:1.2.840.113556.1.4.1941:=group_name)"
128
- search_result = admin_ldap.search(:base => dn,
170
+ search_result = group_checking_ldap.search(:base => dn,
129
171
  :filter => Net::LDAP::Filter.ex("memberof:1.2.840.113556.1.4.1941", group_name),
130
172
  :scope => Net::LDAP::SearchScope_BaseObject)
131
173
  # Will return the user entry if belongs to group otherwise nothing
132
174
  if search_result.length == 1 && search_result[0].dn.eql?(dn)
133
175
  in_group = true
176
+ DeviseLdapAuthenticatable::Logger.send("User #{dn} IS included in group: #{group_name}")
134
177
  end
135
178
  end
136
179
 
@@ -145,11 +188,11 @@ module Devise
145
188
  return true unless ::Devise.ldap_check_attributes
146
189
 
147
190
  admin_ldap = Connection.admin
148
-
149
191
  user = find_ldap_user(admin_ldap)
150
192
 
151
193
  @required_attributes.each do |key,val|
152
- unless user[key].include? val
194
+ matching_attributes = user[key] & Array(val)
195
+ unless (matching_attributes).any?
153
196
  DeviseLdapAuthenticatable::Logger.send("User #{dn} did not match attribute #{key}:#{val}")
154
197
  return false
155
198
  end
@@ -158,11 +201,28 @@ module Devise
158
201
  return true
159
202
  end
160
203
 
204
+ def has_required_attribute_presence?
205
+ return true unless ::Devise.ldap_check_attributes_presence
206
+
207
+ user = search_for_login
208
+
209
+ @required_attributes_presence.each do |key,val|
210
+ if val && !user.attribute_names.include?(key.to_sym)
211
+ DeviseLdapAuthenticatable::Logger.send("User #{dn} doesn't include attribute #{key}")
212
+ return false
213
+ elsif !val && user.attribute_names.include?(key.to_sym)
214
+ DeviseLdapAuthenticatable::Logger.send("User #{dn} includes attribute #{key}")
215
+ return false
216
+ end
217
+ end
218
+
219
+ return true
220
+ end
221
+
161
222
  def user_groups
162
223
  admin_ldap = Connection.admin
163
-
164
224
  DeviseLdapAuthenticatable::Logger.send("Getting groups for #{dn}")
165
- filter = Net::LDAP::Filter.eq("uniqueMember", dn)
225
+ filter = Net::LDAP::Filter.eq(@group_membership_attribute, dn)
166
226
  admin_ldap.search(:filter => filter, :base => @group_base).collect(&:dn)
167
227
  end
168
228
 
@@ -174,13 +234,19 @@ module Devise
174
234
  #
175
235
  # @return [Object] the LDAP entry found; nil if not found
176
236
  def search_for_login
177
- DeviseLdapAuthenticatable::Logger.send("LDAP search for login: #{@attribute}=#{@login}")
178
- filter = Net::LDAP::Filter.eq(@attribute.to_s, @login.to_s)
179
- ldap_entry = nil
180
- match_count = 0
181
- @ldap.search(:filter => filter) {|entry| ldap_entry = entry; match_count+=1}
182
- DeviseLdapAuthenticatable::Logger.send("LDAP search yielded #{match_count} matches")
183
- ldap_entry
237
+ @login_ldap_entry ||= begin
238
+ DeviseLdapAuthenticatable::Logger.send("LDAP search for login: #{@attribute}=#{@login}")
239
+ filter = Net::LDAP::Filter.eq(@attribute.to_s, @login.to_s)
240
+ ldap_entry = nil
241
+ match_count = 0
242
+ @ldap.search(:filter => filter) {|entry| ldap_entry = entry; match_count+=1}
243
+ op_result= @ldap.get_operation_result
244
+ if op_result.code!=0 then
245
+ DeviseLdapAuthenticatable::Logger.send("LDAP Error #{op_result.code}: #{op_result.message}")
246
+ end
247
+ DeviseLdapAuthenticatable::Logger.send("LDAP search yielded #{match_count} matches")
248
+ ldap_entry
249
+ end
184
250
  end
185
251
 
186
252
  private
@@ -223,4 +289,4 @@ module Devise
223
289
  end
224
290
  end
225
291
  end
226
- end
292
+ end