xn_devise_ldap_authenticatable 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/CHANGELOG.md +7 -0
  4. data/Gemfile +8 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +143 -0
  7. data/Rakefile +16 -0
  8. data/lib/devise_ldap_authenticatable.rb +49 -0
  9. data/lib/devise_ldap_authenticatable/exception.rb +6 -0
  10. data/lib/devise_ldap_authenticatable/ldap/adapter.rb +87 -0
  11. data/lib/devise_ldap_authenticatable/ldap/connection.rb +243 -0
  12. data/lib/devise_ldap_authenticatable/logger.rb +11 -0
  13. data/lib/devise_ldap_authenticatable/model.rb +120 -0
  14. data/lib/devise_ldap_authenticatable/strategy.rb +39 -0
  15. data/lib/devise_ldap_authenticatable/version.rb +3 -0
  16. data/lib/generators/devise_ldap_authenticatable/install_generator.rb +63 -0
  17. data/lib/generators/devise_ldap_authenticatable/templates/ldap.yml +55 -0
  18. data/spec/ldap/.gitignore +2 -0
  19. data/spec/ldap/base.ldif +73 -0
  20. data/spec/ldap/clear.ldif +26 -0
  21. data/spec/ldap/local.schema +6 -0
  22. data/spec/ldap/openldap-data/.gitignore +2 -0
  23. data/spec/ldap/openldap-data/run/.gitignore +2 -0
  24. data/spec/ldap/openldap-data/run/.gitkeep +0 -0
  25. data/spec/ldap/run-server +31 -0
  26. data/spec/ldap/server.pem +38 -0
  27. data/spec/ldap/slapd-test.conf.erb +107 -0
  28. data/spec/rails_app/Rakefile +7 -0
  29. data/spec/rails_app/app/controllers/application_controller.rb +7 -0
  30. data/spec/rails_app/app/controllers/posts_controller.rb +15 -0
  31. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  32. data/spec/rails_app/app/helpers/posts_helper.rb +2 -0
  33. data/spec/rails_app/app/models/post.rb +2 -0
  34. data/spec/rails_app/app/models/user.rb +7 -0
  35. data/spec/rails_app/app/views/layouts/application.html.erb +26 -0
  36. data/spec/rails_app/app/views/posts/index.html.erb +2 -0
  37. data/spec/rails_app/config.ru +4 -0
  38. data/spec/rails_app/config/application.rb +46 -0
  39. data/spec/rails_app/config/boot.rb +13 -0
  40. data/spec/rails_app/config/cucumber.yml +8 -0
  41. data/spec/rails_app/config/database.yml +25 -0
  42. data/spec/rails_app/config/environment.rb +5 -0
  43. data/spec/rails_app/config/environments/development.rb +21 -0
  44. data/spec/rails_app/config/environments/production.rb +46 -0
  45. data/spec/rails_app/config/environments/test.rb +34 -0
  46. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  47. data/spec/rails_app/config/initializers/devise.rb +247 -0
  48. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  49. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  50. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  51. data/spec/rails_app/config/initializers/session_store.rb +8 -0
  52. data/spec/rails_app/config/ldap.yml +22 -0
  53. data/spec/rails_app/config/ldap_with_boolean_ssl.yml +22 -0
  54. data/spec/rails_app/config/ldap_with_erb.yml +23 -0
  55. data/spec/rails_app/config/ldap_with_uid.yml +18 -0
  56. data/spec/rails_app/config/locales/devise.en.yml +59 -0
  57. data/spec/rails_app/config/locales/en.yml +5 -0
  58. data/spec/rails_app/config/routes.rb +64 -0
  59. data/spec/rails_app/config/ssl_ldap.yml +21 -0
  60. data/spec/rails_app/config/ssl_ldap_with_erb.yml +23 -0
  61. data/spec/rails_app/config/ssl_ldap_with_uid.yml +18 -0
  62. data/spec/rails_app/db/migrate/20100708120448_devise_create_users.rb +40 -0
  63. data/spec/rails_app/db/schema.rb +35 -0
  64. data/spec/rails_app/features/manage_logins.feature +35 -0
  65. data/spec/rails_app/features/step_definitions/login_steps.rb +21 -0
  66. data/spec/rails_app/features/step_definitions/web_steps.rb +219 -0
  67. data/spec/rails_app/features/support/env.rb +58 -0
  68. data/spec/rails_app/features/support/paths.rb +38 -0
  69. data/spec/rails_app/lib/tasks/.gitkeep +0 -0
  70. data/spec/rails_app/lib/tasks/cucumber.rake +53 -0
  71. data/spec/rails_app/public/404.html +26 -0
  72. data/spec/rails_app/public/422.html +26 -0
  73. data/spec/rails_app/public/500.html +26 -0
  74. data/spec/rails_app/public/images/rails.png +0 -0
  75. data/spec/rails_app/public/javascripts/application.js +2 -0
  76. data/spec/rails_app/public/javascripts/controls.js +965 -0
  77. data/spec/rails_app/public/javascripts/dragdrop.js +974 -0
  78. data/spec/rails_app/public/javascripts/effects.js +1123 -0
  79. data/spec/rails_app/public/javascripts/prototype.js +4874 -0
  80. data/spec/rails_app/public/javascripts/rails.js +118 -0
  81. data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
  82. data/spec/rails_app/script/cucumber +10 -0
  83. data/spec/rails_app/script/rails +6 -0
  84. data/spec/spec_helper.rb +55 -0
  85. data/spec/support/factories.rb +16 -0
  86. data/spec/unit/connection_spec.rb +14 -0
  87. data/spec/unit/user_spec.rb +331 -0
  88. data/xn_devise_ldap_authenticatable.gemspec +36 -0
  89. metadata +363 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6c423ee2965e7ef62c4949e422b167f11fec92d2
4
+ data.tar.gz: 76f8843e1f499aa515e046e386e446a04a4f1b7b
5
+ SHA512:
6
+ metadata.gz: a1e9ea3d87f9fff0eea4f803e25a14fad1ca29ee40588b8a002b065c8cb43975808f75791220a69cd3dc9fbe44d9242822f848d64486bd46aab669752635b29c
7
+ data.tar.gz: 63a8dc3a29ef30af5bf66aee4a3c20dcd05a4bc27882581034d8d4bc0a93b6936d879a487b5ea3d4b87e9c7997d5d70faea96a17065f3da27e9f8f3c12ed1733
@@ -0,0 +1,10 @@
1
+ .bundle
2
+ Gemfile.lock
3
+ log
4
+ *.sqlite3
5
+ test/ldap/openldap-data/*
6
+ !test/ldap/openldap-data/run
7
+ test/ldap/openldap-data/run/slapd.*
8
+ test/rails_app/tmp
9
+ pkg/*
10
+ *.gem
@@ -0,0 +1,7 @@
1
+ CHANGELOG
2
+ =========
3
+
4
+ v0.8
5
+ ----
6
+
7
+ [Issue #102](https://github.com/cschiewek/devise_ldap_authenticatable/pull/102): Extract method in_group? from in_required_groups? and expose it to the model
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem 'debugger', platform: :ruby_19
7
+ gem 'byebug', platform: :ruby_20
8
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Curtis Schiewek
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,143 @@
1
+ Devise LDAP Authenticatable
2
+ ===========================
3
+
4
+ Why this fork?
5
+ --------------
6
+ This fork changes a few lines to allow the admin binding to be set to the user trying to log in.
7
+
8
+ [![Gem Version](https://badge.fury.io/rb/devise_ldap_authenticatable.png)](http://badge.fury.io/rb/devise_ldap_authenticatable)
9
+ [![Code Climate](https://codeclimate.com/github/cschiewek/devise_ldap_authenticatable.png)](https://codeclimate.com/github/cschiewek/devise_ldap_authenticatable)
10
+ [![Dependency Status](https://gemnasium.com/cschiewek/devise_ldap_authenticatable.png)](https://gemnasium.com/cschiewek/devise_ldap_authenticatable)
11
+
12
+ Devise LDAP Authenticatable is a LDAP based authentication strategy for the [Devise](http://github.com/plataformatec/devise) authentication framework.
13
+
14
+ If you are building applications for use within your organization which require authentication and you want to use LDAP, this plugin is for you.
15
+
16
+ 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.
17
+
18
+ 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)
19
+
20
+ Prerequisites
21
+ -------------
22
+ * devise ~> 3.0.0 (which requires rails ~> 4.0)
23
+ * net-ldap ~> 0.3.1
24
+
25
+ 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.
26
+
27
+ Usage
28
+ -----
29
+ In the Gemfile for your application:
30
+
31
+ gem "devise_ldap_authenticatable"
32
+
33
+ To get the latest version, pull directly from github instead of the gem:
34
+
35
+ gem "devise_ldap_authenticatable", :git => "git://github.com/cschiewek/devise_ldap_authenticatable.git"
36
+
37
+
38
+ Setup
39
+ -----
40
+ Run the rails generators for devise (please check the [devise](http://github.com/plataformatec/devise) documents for further instructions)
41
+
42
+ rails generate devise:install
43
+ rails generate devise MODEL_NAME
44
+
45
+ Run the rails generator for `devise_ldap_authenticatable`
46
+
47
+ rails generate devise_ldap_authenticatable:install [options]
48
+
49
+ 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:
50
+
51
+ Options:
52
+
53
+ [--user-model=USER_MODEL] # Model to update
54
+ # Default: user
55
+ [--update-model] # Update model to change from database_authenticatable to ldap_authenticatable
56
+ # Default: true
57
+ [--add-rescue] # Update Application Controller with rescue_from for DeviseLdapAuthenticatable::LdapException
58
+ # Default: true
59
+ [--advanced] # Add advanced config options to the devise initializer
60
+
61
+ Querying LDAP
62
+ -------------
63
+ Given that `ldap_create_user` is set to true and you are authenticating with username, you can query an LDAP server for other attributes.
64
+
65
+ in your user model you have to simply define `ldap_before_save` method:
66
+
67
+ def ldap_before_save
68
+ self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first
69
+ end
70
+
71
+ Configuration
72
+ -------------
73
+ In initializer `config/initializers/devise.rb` :
74
+
75
+ * `ldap_logger` _(default: true)_
76
+ * If set to true, will log LDAP queries to the Rails logger.
77
+ * `ldap_create_user` _(default: false)_
78
+ * 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
+ * `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
+ * `ldap_update_password` _(default: true)_
82
+ * When doing password resets, if true will update the LDAP server. Requires admin password in the ldap.yml
83
+ * `ldap_check_group_membership` _(default: false)_
84
+ * 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.
85
+ * `ldap_check_attributes` _(default: false)_
86
+ * 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.
87
+ * `ldap_use_admin_to_bind` _(default: false)_
88
+ * When set to true, the admin user will be used to bind to the LDAP server during authentication.
89
+ * `ldap_check_group_membership_without_admin` _(default: false)_
90
+ * 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).
91
+
92
+ Advanced Configuration
93
+ ----------------------
94
+ These parameters will be added to `config/initializers/devise.rb` when you pass the `--advanced` switch to the generator:
95
+
96
+ * `ldap_auth_username_builder` _(default: `Proc.new() {|attribute, login, ldap| "#{attribute}=#{login},#{ldap.base}" }`)_
97
+ * 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.
98
+ * `ldap_auth_password_build` _(default: `Proc.new() {|new_password| Net::LDAP::Password.generate(:sha, new_password) }`)_
99
+ * Optionally you can define a proc to create custom password encrption when user reset password
100
+
101
+ Troubleshooting
102
+ --------------
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/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 very helpful.
104
+
105
+ **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
+
107
+ Discussion Group
108
+ ------------
109
+
110
+ For additional support, questions or discussions, please see the discussion forum on [Google Groups](https://groups.google.com/forum/#!forum/devise_ldap_authenticatable)
111
+
112
+ Development guide
113
+ ------------
114
+
115
+ Devise LDAP Authenticatable uses a running OpenLDAP server to do automated acceptance tests. You'll need the executables `slapd`, `ldapadd`, and `ldapmodify`.
116
+
117
+ On OS X, this is available out of the box.
118
+
119
+ 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.
120
+
121
+ /path/to/devise_ldap_authenticatable/spec/ldap/** rw,$
122
+
123
+ To start hacking on `devise_ldap_authentication`, clone the github repository, start the test LDAP server, and run the rake test task:
124
+
125
+ git clone https://github.com/cschiewek/devise_ldap_authenticatable.git
126
+ cd devise_ldap_authenticatable
127
+ bundle install
128
+
129
+ # in a separate console or backgrounded
130
+ ./spec/ldap/run-server
131
+
132
+ bundle exec rake db:migrate # first time only
133
+ bundle exec rake spec
134
+
135
+ References
136
+ ----------
137
+ * [OpenLDAP](http://www.openldap.org/)
138
+ * [Devise](http://github.com/plataformatec/devise)
139
+ * [Warden](http://github.com/hassox/warden)
140
+
141
+ Released under the MIT license
142
+
143
+ Copyright (c) 2012 [Curtis Schiewek](https://github.com/cschiewek), [Daniel McNevin](https://github.com/dpmcnevin), [Steven Xu](https://github.com/cairo140)
@@ -0,0 +1,16 @@
1
+ require File.expand_path('spec/rails_app/config/environment', File.dirname(__FILE__))
2
+ require 'rdoc/task'
3
+
4
+ desc 'Default: run test suite.'
5
+ task :default => :spec
6
+
7
+ desc 'Generate documentation for the devise_ldap_authenticatable plugin.'
8
+ Rake::RDocTask.new(:rdoc) do |rdoc|
9
+ rdoc.rdoc_dir = 'rdoc'
10
+ rdoc.title = 'DeviseLDAPAuthenticatable'
11
+ rdoc.options << '--line-numbers' << '--inline-source'
12
+ rdoc.rdoc_files.include('README.md')
13
+ rdoc.rdoc_files.include('lib/**/*.rb')
14
+ end
15
+
16
+ RailsApp::Application.load_tasks
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ require 'devise'
3
+
4
+ require 'devise_ldap_authenticatable/exception'
5
+ require 'devise_ldap_authenticatable/logger'
6
+ require 'devise_ldap_authenticatable/ldap/adapter'
7
+ require 'devise_ldap_authenticatable/ldap/connection'
8
+
9
+ # Get ldap information from config/ldap.yml now
10
+ module Devise
11
+ # Allow logging
12
+ mattr_accessor :ldap_logger
13
+ @@ldap_logger = true
14
+
15
+ # Add valid users to database
16
+ mattr_accessor :ldap_create_user
17
+ @@ldap_create_user = false
18
+
19
+ # A path to YAML config file or a Proc that returns a
20
+ # configuration hash
21
+ mattr_accessor :ldap_config
22
+ # @@ldap_config = "#{Rails.root}/config/ldap.yml"
23
+
24
+ mattr_accessor :ldap_update_password
25
+ @@ldap_update_password = true
26
+
27
+ mattr_accessor :ldap_check_group_membership
28
+ @@ldap_check_group_membership = false
29
+
30
+ mattr_accessor :ldap_check_attributes
31
+ @@ldap_check_role_attribute = false
32
+
33
+ mattr_accessor :ldap_use_admin_to_bind
34
+ @@ldap_use_admin_to_bind = false
35
+
36
+ mattr_accessor :ldap_auth_username_builder
37
+ @@ldap_auth_username_builder = Proc.new() {|attribute, login, ldap| "#{attribute}=#{login},#{ldap.base}" }
38
+
39
+ mattr_accessor :ldap_ad_group_check
40
+ @@ldap_ad_group_check = false
41
+ end
42
+
43
+ # Add ldap_authenticatable strategy to defaults.
44
+ #
45
+ Devise.add_module(:ldap_authenticatable,
46
+ :route => :session, ## This will add the routes, rather than in the routes.rb
47
+ :strategy => true,
48
+ :controller => :sessions,
49
+ :model => 'devise_ldap_authenticatable/model')
@@ -0,0 +1,6 @@
1
+ module DeviseLdapAuthenticatable
2
+
3
+ class LdapException < Exception
4
+ end
5
+
6
+ end
@@ -0,0 +1,87 @@
1
+ require "net/ldap"
2
+
3
+ module Devise
4
+ module LDAP
5
+ DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY = 'uniqueMember'
6
+
7
+ module Adapter
8
+ def self.valid_credentials?(login, password_plaintext)
9
+ options = {:login => login,
10
+ :password => password_plaintext,
11
+ :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder,
12
+ :admin => ::Devise.ldap_use_admin_to_bind}
13
+
14
+ resource = Devise::LDAP::Connection.new(options)
15
+ resource.authorized?
16
+ end
17
+
18
+ def self.update_password(login, new_password)
19
+ options = {:login => login,
20
+ :new_password => new_password,
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.change_password! if new_password.present?
26
+ end
27
+
28
+ def self.update_own_password(login, new_password, current_password)
29
+ set_ldap_param(login, :userPassword, ::Devise.ldap_auth_password_builder.call(new_password), current_password)
30
+ end
31
+
32
+ def self.ldap_connect(login)
33
+ options = {:login => login,
34
+ :ldap_auth_username_builder => ::Devise.ldap_auth_username_builder,
35
+ :admin => ::Devise.ldap_use_admin_to_bind}
36
+
37
+ resource = Devise::LDAP::Connection.new(options)
38
+ end
39
+
40
+ def self.valid_login?(login)
41
+ self.ldap_connect(login).valid_login?
42
+ end
43
+
44
+ def self.get_groups(login)
45
+ self.ldap_connect(login).user_groups
46
+ end
47
+
48
+ def self.in_ldap_group?(login, group_name, group_attribute = nil)
49
+ self.ldap_connect(login).in_group?(group_name, group_attribute)
50
+ end
51
+
52
+ def self.get_dn(login)
53
+ self.ldap_connect(login).dn
54
+ end
55
+
56
+ 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 }
60
+
61
+ resource = Devise::LDAP::Connection.new(options)
62
+ resource.set_param(param, new_value)
63
+ end
64
+
65
+ 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 }
69
+
70
+ resource = Devise::LDAP::Connection.new(options)
71
+ resource.delete_param(param)
72
+ end
73
+
74
+ def self.get_ldap_param(login,param)
75
+ resource = self.ldap_connect(login)
76
+ resource.ldap_param_value(param)
77
+ end
78
+
79
+ def self.get_ldap_entry(login)
80
+ self.ldap_connect(login).search_for_login
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,243 @@
1
+ module Devise
2
+ module LDAP
3
+ class Connection
4
+ attr_reader :ldap, :login
5
+
6
+ def initialize(params = {})
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
12
+ ldap_options = params
13
+ ldap_config["ssl"] = :simple_tls if ldap_config["ssl"] === true
14
+ ldap_options[:encryption] = ldap_config["ssl"].to_sym if ldap_config["ssl"]
15
+
16
+ @ldap = Net::LDAP.new(ldap_options)
17
+ @ldap.host = ldap_config["host"]
18
+ @ldap.port = ldap_config["port"]
19
+ @ldap.base = ldap_config["base"]
20
+ @attribute = ldap_config["attribute"]
21
+ @allow_unauthenticated_bind = ldap_config["allow_unauthenticated_bind"]
22
+
23
+ @ldap_auth_username_builder = params[:ldap_auth_username_builder]
24
+
25
+ @group_base = ldap_config["group_base"]
26
+ @check_group_membership = ldap_config.has_key?("check_group_membership") ? ldap_config["check_group_membership"] : ::Devise.ldap_check_group_membership
27
+ @required_groups = ldap_config["required_groups"]
28
+ @required_attributes = ldap_config["require_attribute"]
29
+
30
+ @additional_ldap_filter=ldap_config["additional_ldap_filter"]
31
+
32
+ @ldap.auth ldap_config["admin_user"], ldap_config["admin_password"] if params[:admin]
33
+ @ldap.auth params[:login], params[:password] if ldap_config["admin_as_user"]
34
+
35
+ @login = params[:login]
36
+ @password = params[:password]
37
+ @new_password = params[:new_password]
38
+ end
39
+
40
+ def delete_param(param)
41
+ update_ldap [[:delete, param.to_sym, nil]]
42
+ end
43
+
44
+ def set_param(param, new_value)
45
+ update_ldap( { param.to_sym => new_value } )
46
+ end
47
+
48
+ def dn
49
+ @dn ||= begin
50
+ DeviseLdapAuthenticatable::Logger.send("LDAP dn lookup: #{@attribute}=#{@login}")
51
+ ldap_entry = search_for_login
52
+ if ldap_entry.nil?
53
+ @ldap_auth_username_builder.call(@attribute,@login,@ldap)
54
+ else
55
+ ldap_entry.dn
56
+ end
57
+ end
58
+ end
59
+
60
+ def ldap_param_value(param)
61
+ ldap_entry = search_for_login
62
+
63
+ if ldap_entry
64
+ unless ldap_entry[param].empty?
65
+ value = ldap_entry.send(param)
66
+ DeviseLdapAuthenticatable::Logger.send("Requested param #{param} has value #{value}")
67
+ value
68
+ else
69
+ DeviseLdapAuthenticatable::Logger.send("Requested param #{param} does not exist")
70
+ value = nil
71
+ end
72
+ else
73
+ DeviseLdapAuthenticatable::Logger.send("Requested ldap entry does not exist")
74
+ value = nil
75
+ end
76
+ end
77
+
78
+ def authenticate!
79
+ return false unless (@password.present? || @allow_unauthenticated_bind)
80
+ @ldap.auth(dn, @password)
81
+ @ldap.bind
82
+ end
83
+
84
+ def authenticated?
85
+ authenticate!
86
+ end
87
+
88
+ def authorized?
89
+ DeviseLdapAuthenticatable::Logger.send("Authorizing user #{dn}")
90
+ if !authenticated?
91
+ DeviseLdapAuthenticatable::Logger.send("Not authorized because not authenticated.")
92
+ return false
93
+ elsif !in_required_groups?
94
+ DeviseLdapAuthenticatable::Logger.send("Not authorized because not in required groups.")
95
+ return false
96
+ elsif !has_required_attribute?
97
+ DeviseLdapAuthenticatable::Logger.send("Not authorized because does not have required attribute.")
98
+ return false
99
+ else
100
+ return true
101
+ end
102
+ end
103
+
104
+ def change_password!
105
+ update_ldap(:userpassword => Net::LDAP::Password.generate(:sha, @new_password))
106
+ end
107
+
108
+ def in_required_groups?
109
+ return true unless @check_group_membership
110
+
111
+ ## FIXME set errors here, the ldap.yml isn't set properly.
112
+ return false if @required_groups.nil?
113
+
114
+ for group in @required_groups
115
+ if group.is_a?(Array)
116
+ return false unless in_group?(group[1], group[0])
117
+ else
118
+ return false unless in_group?(group)
119
+ end
120
+ end
121
+ return true
122
+ end
123
+
124
+ def in_group?(group_name, group_attribute = LDAP::DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY)
125
+ in_group = false
126
+
127
+ admin_ldap = Connection.admin
128
+
129
+ unless ::Devise.ldap_ad_group_check
130
+ admin_ldap.search(:base => group_name, :scope => Net::LDAP::SearchScope_BaseObject) do |entry|
131
+ if entry[group_attribute].include? dn
132
+ in_group = true
133
+ end
134
+ end
135
+ else
136
+ # AD optimization - extension will recursively check sub-groups with one query
137
+ # "(memberof:1.2.840.113556.1.4.1941:=group_name)"
138
+ search_result = admin_ldap.search(:base => dn,
139
+ :filter => Net::LDAP::Filter.ex("memberof:1.2.840.113556.1.4.1941", group_name),
140
+ :scope => Net::LDAP::SearchScope_BaseObject)
141
+ # Will return the user entry if belongs to group otherwise nothing
142
+ if search_result.length == 1 && search_result[0].dn.eql?(dn)
143
+ in_group = true
144
+ end
145
+ end
146
+
147
+ unless in_group
148
+ DeviseLdapAuthenticatable::Logger.send("User #{dn} is not in group: #{group_name}")
149
+ end
150
+
151
+ return in_group
152
+ end
153
+
154
+ def has_required_attribute?
155
+ return true unless ::Devise.ldap_check_attributes
156
+
157
+ admin_ldap = Connection.admin
158
+
159
+ user = find_ldap_user(admin_ldap)
160
+
161
+ @required_attributes.each do |key,val|
162
+ unless user[key].include? val
163
+ DeviseLdapAuthenticatable::Logger.send("User #{dn} did not match attribute #{key}:#{val}")
164
+ return false
165
+ end
166
+ end
167
+
168
+ return true
169
+ end
170
+
171
+ def user_groups
172
+ admin_ldap = Connection.admin
173
+
174
+ DeviseLdapAuthenticatable::Logger.send("Getting groups for #{dn}")
175
+ filter = Net::LDAP::Filter.eq("uniqueMember", dn)
176
+ admin_ldap.search(:filter => filter, :base => @group_base).collect(&:dn)
177
+ end
178
+
179
+ def valid_login?
180
+ !search_for_login.nil?
181
+ end
182
+
183
+ # Searches the LDAP for the login
184
+ #
185
+ # @return [Object] the LDAP entry found; nil if not found
186
+ def search_for_login
187
+ @login_ldap_entry ||= begin
188
+ DeviseLdapAuthenticatable::Logger.send("LDAP search for login: #{@attribute}=#{@login}")
189
+ filter = Net::LDAP::Filter.eq(@attribute.to_s, @login.to_s)
190
+ if @additional_ldap_filter
191
+ DeviseLdapAuthenticatable::Logger.send("Adding Additional Filter #{@additional_ldap_filter}")
192
+ additional_filter = Net::LDAP::Filter.from_rfc2254(@additional_ldap_filter)
193
+ filter = filter & additional_filter
194
+ end
195
+ ldap_entry = nil
196
+ match_count = 0
197
+ @ldap.search(:filter => filter) {|entry| ldap_entry = entry; match_count+=1}
198
+ DeviseLdapAuthenticatable::Logger.send("LDAP search yielded #{match_count} matches")
199
+ ldap_entry
200
+ end
201
+ end
202
+
203
+ private
204
+
205
+ def self.admin
206
+ ldap = Connection.new(:admin => true).ldap
207
+
208
+ unless ldap.bind
209
+ DeviseLdapAuthenticatable::Logger.send("Cannot bind to admin LDAP user")
210
+ raise DeviseLdapAuthenticatable::LdapException, "Cannot connect to admin LDAP user"
211
+ end
212
+
213
+ return ldap
214
+ end
215
+
216
+ def find_ldap_user(ldap)
217
+ DeviseLdapAuthenticatable::Logger.send("Finding user: #{dn}")
218
+ ldap.search(:base => dn, :scope => Net::LDAP::SearchScope_BaseObject).try(:first)
219
+ end
220
+
221
+ def update_ldap(ops)
222
+ operations = []
223
+ if ops.is_a? Hash
224
+ ops.each do |key,value|
225
+ operations << [:replace,key,value]
226
+ end
227
+ elsif ops.is_a? Array
228
+ operations = ops
229
+ end
230
+
231
+ if ::Devise.ldap_use_admin_to_bind
232
+ privileged_ldap = Connection.admin
233
+ else
234
+ authenticate!
235
+ privileged_ldap = self.ldap
236
+ end
237
+
238
+ DeviseLdapAuthenticatable::Logger.send("Modifying user #{dn}")
239
+ privileged_ldap.modify(:dn => dn, :operations => operations)
240
+ end
241
+ end
242
+ end
243
+ end