devise_ldap_multiple 0.9.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/Gemfile +8 -0
- data/MIT-LICENSE +20 -0
- data/README.md +60 -0
- data/Rakefile +16 -0
- data/devise_ldap_multiple.gemspec +35 -0
- data/lib/devise_ldap_multiple.rb +25 -0
- data/lib/devise_ldap_multiple/exception.rb +6 -0
- data/lib/devise_ldap_multiple/ldap/adapter.rb +111 -0
- data/lib/devise_ldap_multiple/ldap/connection.rb +326 -0
- data/lib/devise_ldap_multiple/logger.rb +9 -0
- data/lib/devise_ldap_multiple/model.rb +131 -0
- data/lib/devise_ldap_multiple/strategy.rb +48 -0
- data/lib/devise_ldap_multiple/version.rb +3 -0
- data/lib/generators/devise_ldap_multiple/devise_ldap_multiple_generator.rb +17 -0
- data/lib/generators/devise_ldap_multiple/install_generator.rb +39 -0
- data/lib/generators/devise_ldap_multiple/templates/default.yml +99 -0
- metadata +239 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 76c06c80d33a10a9a5d8b456c11922d628ca15bd
|
4
|
+
data.tar.gz: 1064d2b788a02aa146001923e9ca9476db08c818
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f5041d2f9b051e019d5e4377578f79490bb4bf47211278572038b1730d8a4d18373177712d34f0095dec52b488e1c97e19e1e31d4a64d99fcc30d6fda0b0931a
|
7
|
+
data.tar.gz: a66484274528ae0a72dac12292dc8e87aaa3fa00864ed3b9e6159902c5351c3fae53be7d1a755c13e949bcd7cea389575668b63d7807cdd791f10e8e8643b87e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2016 Scott Willett
|
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,60 @@
|
|
1
|
+
Devise LDAP Multiple
|
2
|
+
====================
|
3
|
+
|
4
|
+
This project is a fork of the brilliant project devise_ldap_authenticatable here: (https://github.com/cschiewek/devise_ldap_authenticatable).
|
5
|
+
|
6
|
+
The difference is that this project allows you to use multiple LDAP databases in a single app, and the code was refactored significantly while adding this feature.
|
7
|
+
|
8
|
+
Devise LDAP Multiple is a LDAP based authentication strategy for the [Devise](http://github.com/plataformatec/devise) authentication framework.
|
9
|
+
|
10
|
+
If you are building applications for use within your organization which require authentication and you want to use LDAP, this plugin is for you.
|
11
|
+
|
12
|
+
Devise LDAP Multiple 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.
|
13
|
+
|
14
|
+
Prerequisites
|
15
|
+
-------------
|
16
|
+
|
17
|
+
* devise ~> 3.0.0 (which requires rails ~> 4.0)
|
18
|
+
* net-ldap ~> 0.6.0
|
19
|
+
|
20
|
+
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.
|
21
|
+
|
22
|
+
Usage
|
23
|
+
-----
|
24
|
+
In the Gemfile for your application:
|
25
|
+
|
26
|
+
gem "devise_ldap_multiple"
|
27
|
+
|
28
|
+
To get the latest version, pull directly from github instead of the gem:
|
29
|
+
|
30
|
+
gem "devise_ldap_multiple", :git => "https://github.com/xarael/devise_ldap_multiple"
|
31
|
+
|
32
|
+
Setup
|
33
|
+
-----
|
34
|
+
|
35
|
+
Run the rails generators for devise (please check the [devise](http://github.com/plataformatec/devise) documents for further instructions)
|
36
|
+
|
37
|
+
rails generate devise:install
|
38
|
+
rails generate devise MODEL_NAME
|
39
|
+
|
40
|
+
Run the rails generator for `devise_ldap_multiple`
|
41
|
+
|
42
|
+
rails generate devise_ldap_multiple:install
|
43
|
+
rails generate devise_ldap_multiple [MODEL_NAME]
|
44
|
+
|
45
|
+
MODEL_NAME defaults to: user
|
46
|
+
|
47
|
+
This will install [MODEL_NAME].yml file to the config/ldap/ directory, update the devise.rb initializer with a default scope (default), and update your model.
|
48
|
+
|
49
|
+
All configuration is set within these .yml files for each model. There's comments in the files to describe the various settings.
|
50
|
+
|
51
|
+
References
|
52
|
+
----------
|
53
|
+
* [Devise LDAP Authenticatable](https://github.com/cschiewek/devise_ldap_authenticatable)
|
54
|
+
* [OpenLDAP](http://www.openldap.org/)
|
55
|
+
* [Devise](http://github.com/plataformatec/devise)
|
56
|
+
* [Warden](http://github.com/hassox/warden)
|
57
|
+
|
58
|
+
Released under the MIT license
|
59
|
+
|
60
|
+
Copyright (c) 2016 [Scott Willett](https://github.com/xarael)
|
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_multiple plugin.'
|
8
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
9
|
+
rdoc.rdoc_dir = 'rdoc'
|
10
|
+
rdoc.title = 'DeviseLDAPMultiple'
|
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,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "devise_ldap_multiple/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'devise_ldap_multiple'
|
7
|
+
s.version = DeviseLdapMultiple::VERSION.dup
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.summary = 'Devise extension to allow authentication to multiple LDAPs. Fork of the devise_ldap_authenticatable project.'
|
10
|
+
s.email = 'swillett@outlook.com'
|
11
|
+
s.homepage = 'https://github.com/xarael/devise_ldap_multiple'
|
12
|
+
s.description = s.summary
|
13
|
+
s.authors = ['Curtis Schiewek', 'Daniel McNevin', 'Steven Xu', 'Scott Willett']
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
# s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency 'devise', '>= 3.4.1'
|
22
|
+
s.add_dependency 'net-ldap', '>= 0.6', '!= 0.12'
|
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'
|
31
|
+
|
32
|
+
%w{database_cleaner capybara launchy}.each do |dep|
|
33
|
+
s.add_development_dependency(dep)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'devise'
|
3
|
+
require 'net/ldap'
|
4
|
+
|
5
|
+
require 'devise_ldap_multiple/exception'
|
6
|
+
require 'devise_ldap_multiple/logger'
|
7
|
+
require 'devise_ldap_multiple/ldap/adapter'
|
8
|
+
require 'devise_ldap_multiple/ldap/connection'
|
9
|
+
|
10
|
+
# Nearly all configuration is in each scope.yml file under config/ldap/ for each scope.
|
11
|
+
module Devise
|
12
|
+
|
13
|
+
# The default scope to use if devise doesn't map to a scope and a scope isn't manually specified
|
14
|
+
# Can be overwritten by setting in file config/initializers/devise.rb
|
15
|
+
mattr_accessor :ldap_default_scope
|
16
|
+
@@ldap_default_scope = 'default'
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add ldap_authenticatable strategy to defaults.
|
21
|
+
Devise.add_module(:ldap_authenticatable,
|
22
|
+
:route => :session, ## This will add the routes, rather than in the routes.rb
|
23
|
+
:strategy => true,
|
24
|
+
:controller => :sessions,
|
25
|
+
:model => 'devise_ldap_multiple/model')
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require "net/ldap"
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
|
5
|
+
module LDAP
|
6
|
+
|
7
|
+
DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY = 'uniqueMember'
|
8
|
+
|
9
|
+
# Establishes connections and interacts with LDAP. Uses Connection objects to do this.
|
10
|
+
# Can interact with these methods in rails
|
11
|
+
module Adapter
|
12
|
+
|
13
|
+
# Returns all attributes for an account from LDAP
|
14
|
+
def self.get_ldap_entry(login, scope = default_scope)
|
15
|
+
self.ldap_connect(login, scope).search_for_login
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get the value of an attribute for an account from LDAP
|
19
|
+
def self.get_ldap_param(login, param, scope = default_scope)
|
20
|
+
resource = self.ldap_connect(login, scope)
|
21
|
+
resource.ldap_param_value(param)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the DistinguishedName of an account (regardless of if it exists or not)
|
25
|
+
def self.get_dn(login, scope = default_scope)
|
26
|
+
self.ldap_connect(login, scope).dn
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.password_updatable? (login, scope = default_scope)
|
30
|
+
options = { login: login, scope: scope }
|
31
|
+
resource = Devise::LDAP::Connection.new(options)
|
32
|
+
resource.password_updatable?
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.user_creatable? (login, scope = default_scope)
|
36
|
+
options = { login: login, scope: scope }
|
37
|
+
resource = Devise::LDAP::Connection.new(options)
|
38
|
+
resource.user_creatable?
|
39
|
+
end
|
40
|
+
|
41
|
+
# Boolean returned for if an account in the LDAP exists (doesn't check authentication / authorization): false if a valid match can't be obtained from ldap.
|
42
|
+
def self.valid_login?(login, scope = default_scope)
|
43
|
+
self.ldap_connect(login, scope).valid_login?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Tries to authenticate credentails to LDAP. Returns true or false appropriately.
|
47
|
+
def self.valid_credentials?(login, password_plaintext, scope = default_scope)
|
48
|
+
options = { login: login, password: password_plaintext, scope: scope }
|
49
|
+
resource = Devise::LDAP::Connection.new(options)
|
50
|
+
resource.authorized?
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns true or false depending on if the users credentials have expired or not
|
54
|
+
def self.expired_valid_credentials?(login, password_plaintext, scope = default_scope)
|
55
|
+
options = { login: login, password: password_plaintext, scope: scope }
|
56
|
+
resource = Devise::LDAP::Connection.new(options)
|
57
|
+
resource.expired_valid_credentials?
|
58
|
+
end
|
59
|
+
|
60
|
+
# Updates a users password in LDAP
|
61
|
+
def self.update_password(login, new_password, scope = default_scope)
|
62
|
+
options = { login: login, new_password: new_password, scope: scope }
|
63
|
+
resource = Devise::LDAP::Connection.new(options)
|
64
|
+
resource.change_password! if new_password.present?
|
65
|
+
end
|
66
|
+
|
67
|
+
# Also updates the password. Unsure what differentiates this from update_password currently.
|
68
|
+
def self.update_own_password(login, new_password, current_password)
|
69
|
+
set_ldap_param(login, :userPassword, new_password, current_password, true)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns a list of group memberships for a user
|
73
|
+
def self.get_groups(login, scope = default_scope)
|
74
|
+
self.ldap_connect(login, scope).user_groups
|
75
|
+
end
|
76
|
+
|
77
|
+
# Checks if a user is a member of a specific group
|
78
|
+
def self.in_ldap_group?(login, group_name, group_attribute = nil, scope = default_scope)
|
79
|
+
self.ldap_connect(login, scope).in_group?(group_name, group_attribute)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Sets an LDAP attribute for an account to a new value
|
83
|
+
def self.set_ldap_param(login, param, new_value, password = nil, scope = default_scope)
|
84
|
+
options = { login: login, password: password, scope: scope }
|
85
|
+
resource = Devise::LDAP::Connection.new(options)
|
86
|
+
resource.set_param(param, new_value)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Deletes the LDAP attribute for an account
|
90
|
+
def self.delete_ldap_param(login, param, password = nil, scope = default_scope)
|
91
|
+
options = { login: login, password: password, scope: scope }
|
92
|
+
resource = Devise::LDAP::Connection.new(options)
|
93
|
+
resource.delete_param(param)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Creates a new connection to an LDAP database and returns the connection object to run methods against
|
97
|
+
def self.ldap_connect(login, scope = default_scope)
|
98
|
+
options = { login: login, scope: scope }
|
99
|
+
Devise::LDAP::Connection.new(options)
|
100
|
+
end
|
101
|
+
|
102
|
+
# The default scope to use if none is specified
|
103
|
+
def self.default_scope
|
104
|
+
::Devise.ldap_default_scope
|
105
|
+
end
|
106
|
+
|
107
|
+
end # module Adapter
|
108
|
+
|
109
|
+
end # module LDAP
|
110
|
+
|
111
|
+
end # module Devise
|
@@ -0,0 +1,326 @@
|
|
1
|
+
module Devise
|
2
|
+
|
3
|
+
module LDAP
|
4
|
+
|
5
|
+
class Connection
|
6
|
+
|
7
|
+
attr_reader :ldap, :login
|
8
|
+
|
9
|
+
def initialize(params = {})
|
10
|
+
|
11
|
+
# Option scope determines the mapping_file to use
|
12
|
+
@scope = params[:scope]
|
13
|
+
config_file_path = "#{Rails.root}/config/ldap/#{@scope}.yml"
|
14
|
+
|
15
|
+
# Read the config file depending on the scope
|
16
|
+
ldap_config = YAML.load(ERB.new(File.read(config_file_path)).result)
|
17
|
+
|
18
|
+
# Alter the ssl option in the configuration
|
19
|
+
ldap_config[Rails.env]["ssl"] = :simple_tls if ldap_config[Rails.env]["ssl"] === true
|
20
|
+
|
21
|
+
# Determines if logging happens
|
22
|
+
@logging_enabled = ldap_config['logging_enabled']
|
23
|
+
|
24
|
+
# Evaluated into Proc objects
|
25
|
+
@auth_username_builder = eval ldap_config['auth_username_builder']
|
26
|
+
@auth_password_builder = eval ldap_config['auth_password_builder']
|
27
|
+
|
28
|
+
# Attributes and groups required for authorisation of an account
|
29
|
+
@group_base = ldap_config["group_base"]
|
30
|
+
@required_groups = ldap_config["required_groups"]
|
31
|
+
@group_membership_attribute = ldap_config.has_key?("group_membership_attribute") ? ldap_config["group_membership_attribute"] : "uniqueMember"
|
32
|
+
@required_attributes = ldap_config["require_attribute"]
|
33
|
+
@required_attributes_presence = ldap_config["require_attribute_presence"]
|
34
|
+
|
35
|
+
# Various Flags
|
36
|
+
@allow_unauthenticated_bind = ["allow_unauthenticated_bind"]
|
37
|
+
@check_attributes = ldap_config['check_attributes']
|
38
|
+
@check_attributes_presence = ldap_config['check_attributes_presence']
|
39
|
+
@use_admin_to_bind = ldap_config['use_admin_to_bind']
|
40
|
+
@check_group_membership = ldap_config["check_group_membership"]
|
41
|
+
@check_group_membership_without_admin = ldap_config["check_group_membership_without_admin"]
|
42
|
+
@update_passwords = ldap_config['update_passwords']
|
43
|
+
@create_user = ldap_config['create_user']
|
44
|
+
|
45
|
+
# Other params referencing credentails not part of the config file
|
46
|
+
@login = params[:login]
|
47
|
+
@password = params[:password]
|
48
|
+
@new_password = params[:new_password]
|
49
|
+
|
50
|
+
# Build up the options used to establish an LDAP connection
|
51
|
+
ldap_options = {}
|
52
|
+
ldap_options[:login] = params[:login] if params[:login]
|
53
|
+
ldap_options[:password] = params[:password] if params[:password]
|
54
|
+
ldap_options[:new_password] = params[:new_password] if params[:new_password]
|
55
|
+
ldap_options[:ldap_auth_username_builder] = @auth_username_builder
|
56
|
+
ldap_options[:admin] = @use_admin_to_bind
|
57
|
+
ldap_options[:encryption] = ldap_config[Rails.env]["ssl"].to_sym if ldap_config[Rails.env]["ssl"]
|
58
|
+
|
59
|
+
# LDAP server to connect to depending on the current Rails environment in use
|
60
|
+
@ldap = Net::LDAP.new(ldap_options)
|
61
|
+
@ldap.host = ldap_config[Rails.env]["host"]
|
62
|
+
@ldap.port = ldap_config[Rails.env]["port"]
|
63
|
+
@ldap.base = ldap_config[Rails.env]["base"]
|
64
|
+
@attribute = ldap_config[Rails.env]["attribute"]
|
65
|
+
|
66
|
+
# Admin credentials to use if an admin is set to bind to LDAP (Rails environment dependent)
|
67
|
+
@ldap.auth ldap_config[Rails.env]["admin_user"], ldap_config[Rails.env]["admin_password"] if @use_admin_to_bind
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
# Logs a message to the console and the environment log file
|
72
|
+
def log (message)
|
73
|
+
DeviseLdapMultiple::Logger.send(message) if @logging_enabled
|
74
|
+
end
|
75
|
+
|
76
|
+
def password_updatable?
|
77
|
+
@update_passwords
|
78
|
+
end
|
79
|
+
|
80
|
+
def user_creatable?
|
81
|
+
@create_user
|
82
|
+
end
|
83
|
+
|
84
|
+
# Deletes a parameter from LDAP for an account
|
85
|
+
def delete_param(param)
|
86
|
+
update_ldap [[:delete, param.to_sym, nil]]
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_param(param, new_value, is_password = false)
|
90
|
+
new_value = @auth_password_builder .call(new_value) if is_password
|
91
|
+
update_ldap( { param.to_sym => new_value } )
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the DistinguishedName for an account, regardless of if it exists or not (calls a proc to determine the dn if it doesn't exists - proc defined in the config file)
|
95
|
+
def dn
|
96
|
+
@dn ||= begin
|
97
|
+
log("LDAP dn lookup: #{@attribute}=#{@login}")
|
98
|
+
log("LDAP dn lookup asdf: #{@attribute}=#{@login}")
|
99
|
+
ldap_entry = search_for_login
|
100
|
+
if ldap_entry.nil?
|
101
|
+
@auth_username_builder .call(@attribute,@login,@ldap)
|
102
|
+
else
|
103
|
+
ldap_entry.dn
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def ldap_param_value(param)
|
109
|
+
ldap_entry = search_for_login
|
110
|
+
|
111
|
+
if ldap_entry
|
112
|
+
unless ldap_entry[param].empty?
|
113
|
+
value = ldap_entry.send(param)
|
114
|
+
log("Requested param #{param} has value #{value}")
|
115
|
+
value
|
116
|
+
else
|
117
|
+
log("Requested param #{param} does not exist")
|
118
|
+
value = nil
|
119
|
+
end
|
120
|
+
else
|
121
|
+
log("Requested ldap entry does not exist")
|
122
|
+
value = nil
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def authenticate!
|
127
|
+
return false unless (@password.present? || @allow_unauthenticated_bind)
|
128
|
+
@ldap.auth(dn, @password)
|
129
|
+
@ldap.bind
|
130
|
+
end
|
131
|
+
|
132
|
+
def authenticated?
|
133
|
+
authenticate!
|
134
|
+
end
|
135
|
+
|
136
|
+
def last_message_bad_credentials?
|
137
|
+
@ldap.get_operation_result.error_message.to_s.include? 'AcceptSecurityContext error, data 52e'
|
138
|
+
end
|
139
|
+
|
140
|
+
def last_message_expired_credentials?
|
141
|
+
@ldap.get_operation_result.error_message.to_s.include? 'AcceptSecurityContext error, data 773'
|
142
|
+
end
|
143
|
+
|
144
|
+
def authorized?
|
145
|
+
log("Authorizing user #{dn}")
|
146
|
+
if !authenticated?
|
147
|
+
if last_message_bad_credentials?
|
148
|
+
log("Not authorized because of invalid credentials.")
|
149
|
+
elsif last_message_expired_credentials?
|
150
|
+
log("Not authorized because of expired credentials.")
|
151
|
+
else
|
152
|
+
log("Not authorized because not authenticated.")
|
153
|
+
end
|
154
|
+
return false
|
155
|
+
elsif !in_required_groups?
|
156
|
+
log("Not authorized because not in required groups.")
|
157
|
+
return false
|
158
|
+
elsif !has_required_attribute?
|
159
|
+
log("Not authorized because does not have required attribute.")
|
160
|
+
return false
|
161
|
+
elsif !has_required_attribute_presence?
|
162
|
+
log("Not authorized because does not have required attribute present.")
|
163
|
+
return false
|
164
|
+
else
|
165
|
+
return true
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def expired_valid_credentials?
|
170
|
+
log("Authorizing user #{dn}")
|
171
|
+
!authenticated? && last_message_expired_credentials?
|
172
|
+
end
|
173
|
+
|
174
|
+
def change_password!
|
175
|
+
update_ldap(:userPassword => @auth_password_builder .call(@new_password))
|
176
|
+
end
|
177
|
+
|
178
|
+
def in_required_groups?
|
179
|
+
return true unless @check_group_membership || @check_group_membership_without_admin
|
180
|
+
## FIXME set errors here, the ldap.yml isn't set properly.
|
181
|
+
return false if @required_groups.nil?
|
182
|
+
for group in @required_groups
|
183
|
+
if group.is_a?(Array)
|
184
|
+
return false unless in_group?(group[1], group[0])
|
185
|
+
else
|
186
|
+
return false unless in_group?(group)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
return true
|
190
|
+
end
|
191
|
+
|
192
|
+
def in_group?(group_name, group_attribute = LDAP::DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY)
|
193
|
+
in_group = false
|
194
|
+
if @check_group_membership_without_admin
|
195
|
+
group_checking_ldap = @ldap
|
196
|
+
else
|
197
|
+
group_checking_ldap = Connection.admin
|
198
|
+
end
|
199
|
+
unless @ldap_check_group_membership
|
200
|
+
group_checking_ldap.search(:base => group_name, :scope => Net::LDAP::SearchScope_BaseObject) do |entry|
|
201
|
+
if entry[group_attribute].include? dn
|
202
|
+
in_group = true
|
203
|
+
log("User #{dn} IS included in group: #{group_name}")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
else
|
207
|
+
# AD optimization - extension will recursively check sub-groups with one query
|
208
|
+
# "(memberof:1.2.840.113556.1.4.1941:=group_name)"
|
209
|
+
search_result = group_checking_ldap.search(:base => dn,
|
210
|
+
:filter => Net::LDAP::Filter.ex("memberof:1.2.840.113556.1.4.1941", group_name),
|
211
|
+
:scope => Net::LDAP::SearchScope_BaseObject)
|
212
|
+
# Will return the user entry if belongs to group otherwise nothing
|
213
|
+
if search_result.length == 1 && search_result[0].dn.eql?(dn)
|
214
|
+
in_group = true
|
215
|
+
log("User #{dn} IS included in group: #{group_name}")
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
unless in_group
|
220
|
+
log("User #{dn} is not in group: #{group_name}")
|
221
|
+
end
|
222
|
+
|
223
|
+
return in_group
|
224
|
+
end
|
225
|
+
|
226
|
+
def has_required_attribute?
|
227
|
+
return true unless @check_attributes
|
228
|
+
admin_ldap = Connection.admin
|
229
|
+
user = find_ldap_user(admin_ldap)
|
230
|
+
@required_attributes.each do |key,val|
|
231
|
+
matching_attributes = user[key] & Array(val)
|
232
|
+
unless (matching_attributes).any?
|
233
|
+
log("User #{dn} did not match attribute #{key}:#{val}")
|
234
|
+
return false
|
235
|
+
end
|
236
|
+
end
|
237
|
+
return true
|
238
|
+
end
|
239
|
+
|
240
|
+
def has_required_attribute_presence?
|
241
|
+
return true unless @check_attributes_presence
|
242
|
+
user = search_for_login
|
243
|
+
@required_attributes_presence.each do |key,val|
|
244
|
+
if val && !user.attribute_names.include?(key.to_sym)
|
245
|
+
log("User #{dn} doesn't include attribute #{key}")
|
246
|
+
return false
|
247
|
+
elsif !val && user.attribute_names.include?(key.to_sym)
|
248
|
+
log("User #{dn} includes attribute #{key}")
|
249
|
+
return false
|
250
|
+
end
|
251
|
+
end
|
252
|
+
return true
|
253
|
+
end
|
254
|
+
|
255
|
+
def user_groups
|
256
|
+
admin_ldap = Connection.admin
|
257
|
+
log("Getting groups for #{dn}")
|
258
|
+
filter = Net::LDAP::Filter.eq(@group_membership_attribute, dn)
|
259
|
+
admin_ldap.search(:filter => filter, :base => @group_base).collect(&:dn)
|
260
|
+
end
|
261
|
+
def valid_login?
|
262
|
+
!search_for_login.nil?
|
263
|
+
end
|
264
|
+
|
265
|
+
# Searches the LDAP for the login
|
266
|
+
#
|
267
|
+
# @return [Object] the LDAP entry found; nil if not found
|
268
|
+
def search_for_login
|
269
|
+
@login_ldap_entry ||= begin
|
270
|
+
log("LDAP search for login: #{@attribute}=#{@login}")
|
271
|
+
log("Attribute: #{@attribute.to_s}, Login: #{@login.to_s}")
|
272
|
+
log("Scope is: #{@scope}")
|
273
|
+
filter = Net::LDAP::Filter.eq(@attribute.to_s, @login.to_s)
|
274
|
+
ldap_entry = nil
|
275
|
+
match_count = 0
|
276
|
+
@ldap.search(:filter => filter) { |entry| ldap_entry = entry; match_count+=1}
|
277
|
+
op_result= @ldap.get_operation_result
|
278
|
+
if op_result.code!=0 then
|
279
|
+
log("LDAP Error #{op_result.code}: #{op_result.message}")
|
280
|
+
end
|
281
|
+
log("LDAP search yielded #{match_count} matches")
|
282
|
+
ldap_entry
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
private
|
287
|
+
|
288
|
+
def self.admin
|
289
|
+
ldap = Connection.new(:admin => true).ldap
|
290
|
+
unless ldap.bind
|
291
|
+
log("Cannot bind to admin LDAP user")
|
292
|
+
raise DeviseLdapAuthenticatable::LdapException, "Cannot connect to admin LDAP user"
|
293
|
+
end
|
294
|
+
|
295
|
+
return ldap
|
296
|
+
end
|
297
|
+
|
298
|
+
def find_ldap_user(ldap)
|
299
|
+
log("Finding user: #{dn}")
|
300
|
+
ldap.search(:base => dn, :scope => Net::LDAP::SearchScope_BaseObject).try(:first)
|
301
|
+
end
|
302
|
+
|
303
|
+
def update_ldap(ops)
|
304
|
+
operations = []
|
305
|
+
if ops.is_a? Hash
|
306
|
+
ops.each do |key,value|
|
307
|
+
operations << [:replace,key,value]
|
308
|
+
end
|
309
|
+
elsif ops.is_a? Array
|
310
|
+
operations = ops
|
311
|
+
end
|
312
|
+
if @use_admin_to_bind
|
313
|
+
privileged_ldap = Connection.admin
|
314
|
+
else
|
315
|
+
authenticate!
|
316
|
+
privileged_ldap = self.ldap
|
317
|
+
end
|
318
|
+
log("Modifying user #{dn}")
|
319
|
+
privileged_ldap.modify(:dn => dn, :operations => operations)
|
320
|
+
end
|
321
|
+
|
322
|
+
end # class Connection
|
323
|
+
|
324
|
+
end # module LDAP
|
325
|
+
|
326
|
+
end # module Devise
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'devise_ldap_multiple/strategy'
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
|
5
|
+
module Models
|
6
|
+
|
7
|
+
# LDAP Module, responsible for validating the user credentials via LDAP.
|
8
|
+
#
|
9
|
+
# Examples:
|
10
|
+
#
|
11
|
+
# User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
|
12
|
+
# User.find(1).valid_password?('password123') # returns true/false
|
13
|
+
#
|
14
|
+
module LdapAuthenticatable
|
15
|
+
|
16
|
+
extend ActiveSupport::Concern
|
17
|
+
|
18
|
+
# Returns the current scope / mapping from devise (eg: 'admin', 'user', 'staff')
|
19
|
+
def current_scope
|
20
|
+
Devise.mappings.find {|k,v| v.class_name == self.class.name}.last.name.downcase
|
21
|
+
end
|
22
|
+
|
23
|
+
included do
|
24
|
+
attr_reader :current_password, :password
|
25
|
+
attr_accessor :password_confirmation
|
26
|
+
end
|
27
|
+
|
28
|
+
def login_with
|
29
|
+
@login_with ||= Devise.mappings.find {|k,v| v.class_name == self.class.name}.last.to.authentication_keys.first
|
30
|
+
self[@login_with]
|
31
|
+
end
|
32
|
+
|
33
|
+
def change_password!(current_password)
|
34
|
+
raise "Need to set new password first" if @password.blank?
|
35
|
+
Devise::LDAP::Adapter.update_own_password(login_with, @password, current_password, current_scope)
|
36
|
+
end
|
37
|
+
|
38
|
+
def reset_password!(new_password, new_password_confirmation)
|
39
|
+
if new_password == new_password_confirmation && Devise::LDAP::Adapter.password_updatable?(login_with, current_scope)
|
40
|
+
Devise::LDAP::Adapter.update_password(login_with, new_password, current_scope)
|
41
|
+
end
|
42
|
+
clear_reset_password_token if valid?
|
43
|
+
save
|
44
|
+
end
|
45
|
+
|
46
|
+
def password=(new_password)
|
47
|
+
@password = new_password
|
48
|
+
if defined?(password_digest) && @password.present? && respond_to?(:encrypted_password=)
|
49
|
+
self.encrypted_password = password_digest(@password)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Checks if a resource is valid upon authentication.
|
54
|
+
def valid_ldap_authentication?(password)
|
55
|
+
Devise::LDAP::Adapter.valid_credentials?(login_with, password, current_scope)
|
56
|
+
end
|
57
|
+
|
58
|
+
def ldap_entry
|
59
|
+
@ldap_entry ||= Devise::LDAP::Adapter.get_ldap_entry(login_with, current_scope)
|
60
|
+
end
|
61
|
+
|
62
|
+
def ldap_groups
|
63
|
+
Devise::LDAP::Adapter.get_groups(current_scope, login_with)
|
64
|
+
end
|
65
|
+
|
66
|
+
def in_ldap_group?(group_name, group_attribute = LDAP::DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY)
|
67
|
+
Devise::LDAP::Adapter.in_ldap_group?(login_with, group_name, group_attribute, current_scope)
|
68
|
+
end
|
69
|
+
|
70
|
+
def ldap_dn
|
71
|
+
ldap_entry ? ldap_entry.dn : nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def ldap_get_param(param)
|
75
|
+
if ldap_entry && !ldap_entry[param].empty?
|
76
|
+
value = ldap_entry.send(param)
|
77
|
+
else
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# callbacks
|
84
|
+
#
|
85
|
+
|
86
|
+
# # Called before the ldap record is saved automatically
|
87
|
+
# def ldap_before_save
|
88
|
+
# end
|
89
|
+
|
90
|
+
# Called after a successful LDAP authentication
|
91
|
+
def after_ldap_authentication
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
module ClassMethods
|
96
|
+
|
97
|
+
# Find a user for ldap authentication.
|
98
|
+
def find_for_ldap_authentication(attributes={})
|
99
|
+
auth_key = self.authentication_keys.first
|
100
|
+
return nil unless attributes[auth_key].present?
|
101
|
+
|
102
|
+
auth_key_value = (self.case_insensitive_keys || []).include?(auth_key) ? attributes[auth_key].downcase : attributes[auth_key]
|
103
|
+
auth_key_value = (self.strip_whitespace_keys || []).include?(auth_key) ? auth_key_value.strip : auth_key_value
|
104
|
+
|
105
|
+
resource = where(auth_key => auth_key_value).first
|
106
|
+
|
107
|
+
if resource.blank?
|
108
|
+
resource = new
|
109
|
+
resource[auth_key] = auth_key_value
|
110
|
+
resource.password = attributes[:password]
|
111
|
+
end
|
112
|
+
|
113
|
+
if Devise::LDAP::Adapter.user_creatable?(self.authentication_keys.first, self.name.downcase) && resource.new_record? && resource.valid_ldap_authentication?(attributes[:password])
|
114
|
+
resource.ldap_before_save if resource.respond_to?(:ldap_before_save)
|
115
|
+
resource.save!
|
116
|
+
end
|
117
|
+
|
118
|
+
resource
|
119
|
+
end
|
120
|
+
|
121
|
+
def update_with_password(resource)
|
122
|
+
puts "UPDATE_WITH_PASSWORD: #{resource.inspect}"
|
123
|
+
end
|
124
|
+
|
125
|
+
end # module ClassMethods
|
126
|
+
|
127
|
+
end # module LdapAuthenticatable
|
128
|
+
|
129
|
+
end # module Models
|
130
|
+
|
131
|
+
end # module Devise
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'devise/strategies/authenticatable'
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
|
5
|
+
module Strategies
|
6
|
+
|
7
|
+
# Defines an authentication strategy to be used with Warden
|
8
|
+
# Some more information about this here: http://www.rubydoc.info/github/hassox/warden/Warden/Strategies/Base
|
9
|
+
class LdapAuthenticatable < Authenticatable
|
10
|
+
|
11
|
+
# Tests whether the returned resource exists in the database and the
|
12
|
+
# credentials are valid. If the resource is in the database and the credentials
|
13
|
+
# are valid, the user is authenticated. Otherwise failure messages are returned
|
14
|
+
# indicating whether the resource is not found in the database or the credentials
|
15
|
+
# are invalid.
|
16
|
+
def authenticate!
|
17
|
+
|
18
|
+
resource = mapping.to.find_for_ldap_authentication(authentication_hash.merge(:password => password))
|
19
|
+
return fail(:invalid) unless resource
|
20
|
+
|
21
|
+
if resource.persisted?
|
22
|
+
if validate(resource) { resource.valid_ldap_authentication?(password) }
|
23
|
+
remember_me(resource)
|
24
|
+
resource.after_ldap_authentication
|
25
|
+
success!(resource)
|
26
|
+
else
|
27
|
+
return fail(:invalid) # Invalid credentials
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if resource.new_record?
|
32
|
+
if validate(resource) { resource.valid_ldap_authentication?(password) }
|
33
|
+
return fail(:not_found_in_database) # Valid credentials
|
34
|
+
else
|
35
|
+
return fail(:invalid) # Invalid credentials
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end # def authenticate!
|
40
|
+
|
41
|
+
end # LdapAuthenticatable < Authenticatable
|
42
|
+
|
43
|
+
end # module Strategies
|
44
|
+
|
45
|
+
end # module Devise
|
46
|
+
|
47
|
+
# Add the strategy to warden
|
48
|
+
Warden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
class DeviseLdapMultipleGenerator < Rails::Generators::Base
|
3
|
+
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
argument :user_model, :type => :string, :default => "user", :desc => "Model to update"
|
7
|
+
|
8
|
+
# ToDo: Request user input to use a scope that already exists, or make it a parameter to pass into the generator
|
9
|
+
def create_ldap_config
|
10
|
+
copy_file "default.yml", "config/ldap/#{user_model}.yml"
|
11
|
+
end
|
12
|
+
|
13
|
+
def update_user_model
|
14
|
+
gsub_file "app/models/#{options.user_model}.rb", /:database_authenticatable/, ":ldap_authenticatable" if options.update_model?
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module DeviseLdapMultiple
|
2
|
+
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
source_root File.expand_path("../templates", __FILE__)
|
6
|
+
|
7
|
+
# ToDo: Request user input to use a scope that already exists, or make it a parameter to pass into the generator
|
8
|
+
def create_ldap_config
|
9
|
+
copy_file "default.yml", "config/ldap/default.yml"
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_default_devise_settings
|
13
|
+
inject_into_file "config/initializers/devise.rb", default_devise_settings, :after => "Devise.setup do |config|\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
def update_application_controller
|
17
|
+
inject_into_class "app/controllers/application_controller.rb", ApplicationController, rescue_from_exception if options.add_rescue?
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def default_devise_settings
|
23
|
+
settings = <<-eof
|
24
|
+
# ==> Devise LDAP Multiple configuration
|
25
|
+
config.ldap_default_scope = 'default'
|
26
|
+
eof
|
27
|
+
settings
|
28
|
+
end
|
29
|
+
|
30
|
+
def rescue_from_exception
|
31
|
+
<<-eof
|
32
|
+
rescue_from DeviseLdapMultiple::LdapException do |exception|
|
33
|
+
render :text => exception, :status => 500
|
34
|
+
end
|
35
|
+
eof
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
### Configuration options ###
|
2
|
+
|
3
|
+
# (These used to reside in config/initializers/devise.rb)
|
4
|
+
|
5
|
+
# If set to true, will log LDAP queries to the Rails logger
|
6
|
+
logging: true
|
7
|
+
|
8
|
+
# If set to true, all valid LDAP users will be allowed to login and an appropriate user record will be created.
|
9
|
+
# If set to false, you will have to create the user record before they will be allowed to login.
|
10
|
+
create_user: true
|
11
|
+
|
12
|
+
# When doing password resets, if true will update the LDAP server. Requires admin password.
|
13
|
+
update_passwords: true
|
14
|
+
|
15
|
+
# When set to true, the user trying to login will be checked to make sure they are in all of groups specified
|
16
|
+
check_group_membership: false
|
17
|
+
|
18
|
+
# When set to true, the user trying to login will be checked to make sure their attributes match those specified
|
19
|
+
check_attributes: false
|
20
|
+
|
21
|
+
# When set to true, the user trying to login will be checked against all require_attribute_presence attributes
|
22
|
+
check_attributes_presence: false
|
23
|
+
|
24
|
+
# When set to true, the admin user will be used to bind to the LDAP server during authentication.
|
25
|
+
use_admin_to_bind: true
|
26
|
+
|
27
|
+
# When set to true, the group membership check is done with the user's own credentials rather than with admin credentials.
|
28
|
+
# Since these credentials are only available to the Devise user model during the login flow, the group check function will
|
29
|
+
# not work if a group check is performed when this option is true outside of the login flow (e.g., before particular actions).
|
30
|
+
check_group_membership_without_admin: false
|
31
|
+
|
32
|
+
# 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.
|
33
|
+
auth_username_builder: Proc.new() {|attribute, login, ldap| "#{attribute}=#{login},#{ldap.base}" }
|
34
|
+
|
35
|
+
# Optionally you can define a proc to create custom password encrption when user reset password
|
36
|
+
auth_password_builder: Proc.new() {|new_password| Net::LDAP::Password.generate(:sha, new_password) }
|
37
|
+
|
38
|
+
### Authorizations ###
|
39
|
+
|
40
|
+
# Uncomment out the merging for each environment that you'd like to include.
|
41
|
+
# You can also just copy and paste the tree (do not include the "authorizations") to each
|
42
|
+
# environment if you need something different per environment.
|
43
|
+
|
44
|
+
authorizations: &AUTHORIZATIONS
|
45
|
+
allow_unauthenticated_bind: false
|
46
|
+
group_base: ou=groups,dc=test,dc=com
|
47
|
+
# Requires check_group_membership to be true
|
48
|
+
# Can have multiple values, must match all to be authorized
|
49
|
+
|
50
|
+
required_groups:
|
51
|
+
# If only a group name is given, membership will be checked against "uniqueMember"
|
52
|
+
- cn=admins,ou=groups,dc=test,dc=com
|
53
|
+
- cn=users,ou=groups,dc=test,dc=com
|
54
|
+
# If an array is given, the first element will be the attribute to check against, the second the group name
|
55
|
+
- ["moreMembers", "cn=users,ou=groups,dc=test,dc=com"]
|
56
|
+
# Requires check_attributes to be true
|
57
|
+
# Can have multiple attributes and values, must match all to be authorized
|
58
|
+
require_attribute:
|
59
|
+
objectClass: inetOrgPerson
|
60
|
+
authorizationRole: postsAdmin
|
61
|
+
|
62
|
+
# Requires check_attributes_presence to be true
|
63
|
+
# Can have multiple attributes set to true or false to check presence, all must match all to be authorized
|
64
|
+
require_attribute_presence:
|
65
|
+
mail: true
|
66
|
+
telephoneNumber: true
|
67
|
+
serviceAccount: false
|
68
|
+
|
69
|
+
### Environment ###
|
70
|
+
|
71
|
+
development:
|
72
|
+
host: localhost
|
73
|
+
port: 389
|
74
|
+
attribute: userPrincipalName
|
75
|
+
base: ou=people,dc=test,dc=com
|
76
|
+
admin_user: cn=admin,dc=test,dc=com
|
77
|
+
admin_password: admin_password
|
78
|
+
ssl: false
|
79
|
+
# <<: *AUTHORIZATIONS
|
80
|
+
|
81
|
+
test:
|
82
|
+
host: localhost
|
83
|
+
port: 3389
|
84
|
+
attribute: userPrincipalName
|
85
|
+
base: ou=people,dc=test,dc=com
|
86
|
+
admin_user: cn=admin,dc=test,dc=com
|
87
|
+
admin_password: admin_password
|
88
|
+
ssl: simple_tls
|
89
|
+
# <<: *AUTHORIZATIONS
|
90
|
+
|
91
|
+
production:
|
92
|
+
host: localhost
|
93
|
+
port: 636
|
94
|
+
attribute: userPrincipalName
|
95
|
+
base: ou=people,dc=test,dc=com
|
96
|
+
admin_user: cn=admin,dc=test,dc=com
|
97
|
+
admin_password: admin_password
|
98
|
+
ssl: start_tls
|
99
|
+
# <<: *AUTHORIZATIONS
|
metadata
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: devise_ldap_multiple
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Curtis Schiewek
|
8
|
+
- Daniel McNevin
|
9
|
+
- Steven Xu
|
10
|
+
- Scott Willett
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2016-11-11 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: devise
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.4.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.4.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: net-ldap
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0.6'
|
37
|
+
- - "!="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.12'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0.6'
|
47
|
+
- - "!="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0.12'
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rake
|
52
|
+
requirement: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0.9'
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.9'
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: rdoc
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '3'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '3'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rails
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '4.0'
|
85
|
+
type: :development
|
86
|
+
prerelease: false
|
87
|
+
version_requirements: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '4.0'
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: sqlite3
|
94
|
+
requirement: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
- !ruby/object:Gem::Dependency
|
107
|
+
name: factory_girl_rails
|
108
|
+
requirement: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - "~>"
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '1.0'
|
113
|
+
type: :development
|
114
|
+
prerelease: false
|
115
|
+
version_requirements: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - "~>"
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '1.0'
|
120
|
+
- !ruby/object:Gem::Dependency
|
121
|
+
name: factory_girl
|
122
|
+
requirement: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - "~>"
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '2.0'
|
127
|
+
type: :development
|
128
|
+
prerelease: false
|
129
|
+
version_requirements: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '2.0'
|
134
|
+
- !ruby/object:Gem::Dependency
|
135
|
+
name: rspec-rails
|
136
|
+
requirement: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
type: :development
|
142
|
+
prerelease: false
|
143
|
+
version_requirements: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
- !ruby/object:Gem::Dependency
|
149
|
+
name: database_cleaner
|
150
|
+
requirement: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
type: :development
|
156
|
+
prerelease: false
|
157
|
+
version_requirements: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
- !ruby/object:Gem::Dependency
|
163
|
+
name: capybara
|
164
|
+
requirement: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
type: :development
|
170
|
+
prerelease: false
|
171
|
+
version_requirements: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
- !ruby/object:Gem::Dependency
|
177
|
+
name: launchy
|
178
|
+
requirement: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
type: :development
|
184
|
+
prerelease: false
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
description: Devise extension to allow authentication to multiple LDAPs. Fork of the
|
191
|
+
devise_ldap_authenticatable project.
|
192
|
+
email: swillett@outlook.com
|
193
|
+
executables: []
|
194
|
+
extensions: []
|
195
|
+
extra_rdoc_files: []
|
196
|
+
files:
|
197
|
+
- ".gitignore"
|
198
|
+
- Gemfile
|
199
|
+
- MIT-LICENSE
|
200
|
+
- README.md
|
201
|
+
- Rakefile
|
202
|
+
- devise_ldap_multiple.gemspec
|
203
|
+
- lib/devise_ldap_multiple.rb
|
204
|
+
- lib/devise_ldap_multiple/exception.rb
|
205
|
+
- lib/devise_ldap_multiple/ldap/adapter.rb
|
206
|
+
- lib/devise_ldap_multiple/ldap/connection.rb
|
207
|
+
- lib/devise_ldap_multiple/logger.rb
|
208
|
+
- lib/devise_ldap_multiple/model.rb
|
209
|
+
- lib/devise_ldap_multiple/strategy.rb
|
210
|
+
- lib/devise_ldap_multiple/version.rb
|
211
|
+
- lib/generators/devise_ldap_multiple/devise_ldap_multiple_generator.rb
|
212
|
+
- lib/generators/devise_ldap_multiple/install_generator.rb
|
213
|
+
- lib/generators/devise_ldap_multiple/templates/default.yml
|
214
|
+
homepage: https://github.com/xarael/devise_ldap_multiple
|
215
|
+
licenses:
|
216
|
+
- MIT
|
217
|
+
metadata: {}
|
218
|
+
post_install_message:
|
219
|
+
rdoc_options: []
|
220
|
+
require_paths:
|
221
|
+
- lib
|
222
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
223
|
+
requirements:
|
224
|
+
- - ">="
|
225
|
+
- !ruby/object:Gem::Version
|
226
|
+
version: '0'
|
227
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
228
|
+
requirements:
|
229
|
+
- - ">="
|
230
|
+
- !ruby/object:Gem::Version
|
231
|
+
version: '0'
|
232
|
+
requirements: []
|
233
|
+
rubyforge_project:
|
234
|
+
rubygems_version: 2.5.1
|
235
|
+
signing_key:
|
236
|
+
specification_version: 4
|
237
|
+
summary: Devise extension to allow authentication to multiple LDAPs. Fork of the devise_ldap_authenticatable
|
238
|
+
project.
|
239
|
+
test_files: []
|