xn_devise_ldap_authenticatable 0.8.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +8 -0
- data/MIT-LICENSE +20 -0
- data/README.md +143 -0
- data/Rakefile +16 -0
- data/lib/devise_ldap_authenticatable.rb +49 -0
- data/lib/devise_ldap_authenticatable/exception.rb +6 -0
- data/lib/devise_ldap_authenticatable/ldap/adapter.rb +87 -0
- data/lib/devise_ldap_authenticatable/ldap/connection.rb +243 -0
- data/lib/devise_ldap_authenticatable/logger.rb +11 -0
- data/lib/devise_ldap_authenticatable/model.rb +120 -0
- data/lib/devise_ldap_authenticatable/strategy.rb +39 -0
- data/lib/devise_ldap_authenticatable/version.rb +3 -0
- data/lib/generators/devise_ldap_authenticatable/install_generator.rb +63 -0
- data/lib/generators/devise_ldap_authenticatable/templates/ldap.yml +55 -0
- data/spec/ldap/.gitignore +2 -0
- data/spec/ldap/base.ldif +73 -0
- data/spec/ldap/clear.ldif +26 -0
- data/spec/ldap/local.schema +6 -0
- data/spec/ldap/openldap-data/.gitignore +2 -0
- data/spec/ldap/openldap-data/run/.gitignore +2 -0
- data/spec/ldap/openldap-data/run/.gitkeep +0 -0
- data/spec/ldap/run-server +31 -0
- data/spec/ldap/server.pem +38 -0
- data/spec/ldap/slapd-test.conf.erb +107 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/controllers/application_controller.rb +7 -0
- data/spec/rails_app/app/controllers/posts_controller.rb +15 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/helpers/posts_helper.rb +2 -0
- data/spec/rails_app/app/models/post.rb +2 -0
- data/spec/rails_app/app/models/user.rb +7 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +26 -0
- data/spec/rails_app/app/views/posts/index.html.erb +2 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +46 -0
- data/spec/rails_app/config/boot.rb +13 -0
- data/spec/rails_app/config/cucumber.yml +8 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +21 -0
- data/spec/rails_app/config/environments/production.rb +46 -0
- data/spec/rails_app/config/environments/test.rb +34 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/devise.rb +247 -0
- data/spec/rails_app/config/initializers/inflections.rb +10 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +8 -0
- data/spec/rails_app/config/ldap.yml +22 -0
- data/spec/rails_app/config/ldap_with_boolean_ssl.yml +22 -0
- data/spec/rails_app/config/ldap_with_erb.yml +23 -0
- data/spec/rails_app/config/ldap_with_uid.yml +18 -0
- data/spec/rails_app/config/locales/devise.en.yml +59 -0
- data/spec/rails_app/config/locales/en.yml +5 -0
- data/spec/rails_app/config/routes.rb +64 -0
- data/spec/rails_app/config/ssl_ldap.yml +21 -0
- data/spec/rails_app/config/ssl_ldap_with_erb.yml +23 -0
- data/spec/rails_app/config/ssl_ldap_with_uid.yml +18 -0
- data/spec/rails_app/db/migrate/20100708120448_devise_create_users.rb +40 -0
- data/spec/rails_app/db/schema.rb +35 -0
- data/spec/rails_app/features/manage_logins.feature +35 -0
- data/spec/rails_app/features/step_definitions/login_steps.rb +21 -0
- data/spec/rails_app/features/step_definitions/web_steps.rb +219 -0
- data/spec/rails_app/features/support/env.rb +58 -0
- data/spec/rails_app/features/support/paths.rb +38 -0
- data/spec/rails_app/lib/tasks/.gitkeep +0 -0
- data/spec/rails_app/lib/tasks/cucumber.rake +53 -0
- data/spec/rails_app/public/404.html +26 -0
- data/spec/rails_app/public/422.html +26 -0
- data/spec/rails_app/public/500.html +26 -0
- data/spec/rails_app/public/images/rails.png +0 -0
- data/spec/rails_app/public/javascripts/application.js +2 -0
- data/spec/rails_app/public/javascripts/controls.js +965 -0
- data/spec/rails_app/public/javascripts/dragdrop.js +974 -0
- data/spec/rails_app/public/javascripts/effects.js +1123 -0
- data/spec/rails_app/public/javascripts/prototype.js +4874 -0
- data/spec/rails_app/public/javascripts/rails.js +118 -0
- data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
- data/spec/rails_app/script/cucumber +10 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/support/factories.rb +16 -0
- data/spec/unit/connection_spec.rb +14 -0
- data/spec/unit/user_spec.rb +331 -0
- data/xn_devise_ldap_authenticatable.gemspec +36 -0
- metadata +363 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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)
|
data/Rakefile
ADDED
@@ -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,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
|