devise_ldap_multiple 0.9.0
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/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: []
|