github-ldap 1.10.0 → 1.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +7 -1
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/README.md +1 -0
- data/github-ldap.gemspec +2 -2
- data/lib/github/ldap.rb +46 -1
- data/lib/github/ldap/connection_cache.rb +26 -0
- data/lib/github/ldap/domain.rb +1 -4
- data/lib/github/ldap/membership_validators/active_directory.rb +10 -2
- data/lib/github/ldap/referral_chaser.rb +98 -0
- data/lib/github/ldap/url.rb +87 -0
- data/lib/github/ldap/user_search/active_directory.rb +51 -0
- data/lib/github/ldap/user_search/default.rb +40 -0
- data/test/connection_cache_test.rb +18 -0
- data/test/domain_test.rb +9 -0
- data/test/ldap_test.rb +26 -0
- data/test/referral_chaser_test.rb +102 -0
- data/test/test_helper.rb +2 -0
- data/test/url_test.rb +85 -0
- data/test/user_search/active_directory_test.rb +53 -0
- data/test/user_search/default_test.rb +19 -0
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ef4b9c90ff1e809834fe933d93ba5679dd19a1a
|
4
|
+
data.tar.gz: 107f31fc7a1b7d30de40ab06976ff2f4ae291adf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 606264ea40bdb144f2b13b2e15cf8bc07af9c291730efe9b0b3c4c0f39b318317e580937a7f23e21514553209e3e24591628900276347fed2d7a395b75bd39fa
|
7
|
+
data.tar.gz: 95c0822fdaf65f6c1c426ef2a2972c64e61a7e6a2655285e84ae4fd7cd43f795b5d5f1e8cf0929a7ae8e4be35a119170b814e0c01f892394f75e83e14413984d
|
data/.travis.yml
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
-
|
3
|
+
- 2.0.0
|
4
4
|
- 2.1.0
|
5
5
|
|
6
6
|
env:
|
7
7
|
- TESTENV=openldap
|
8
8
|
- TESTENV=apacheds
|
9
9
|
|
10
|
+
# https://docs.travis-ci.com/user/hosts/
|
11
|
+
addons:
|
12
|
+
hosts:
|
13
|
+
- ad1.ghe.dev
|
14
|
+
- ad2.ghe.dev
|
15
|
+
|
10
16
|
install:
|
11
17
|
- if [ "$TESTENV" = "openldap" ]; then ./script/install-openldap; fi
|
12
18
|
- bundle install
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -28,6 +28,7 @@ There are a few configuration options required to use this adapter:
|
|
28
28
|
|
29
29
|
* host: is the host address where the ldap server lives.
|
30
30
|
* port: is the port where the ldap server lives.
|
31
|
+
* hosts: (optional) an enumerable of pairs of hosts and corresponding ports with which to attempt opening connections (default [[host, port]]). Overrides host and port if set.
|
31
32
|
* encryption: is the encryption protocol, disabled by default. The valid options are `ssl` and `tls`.
|
32
33
|
* uid: is the field name in the ldap server used to authenticate your users, in ActiveDirectory this is `sAMAccountName`.
|
33
34
|
|
data/github-ldap.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "github-ldap"
|
5
|
-
spec.version = "1.10.
|
5
|
+
spec.version = "1.10.1"
|
6
6
|
spec.authors = ["David Calavera", "Matt Todd"]
|
7
7
|
spec.email = ["david.calavera@gmail.com", "chiology@gmail.com"]
|
8
8
|
spec.description = %q{LDAP authentication for humans}
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
16
|
spec.require_paths = ["lib"]
|
17
17
|
|
18
|
-
spec.add_dependency 'net-ldap', '~> 0.
|
18
|
+
spec.add_dependency 'net-ldap', '~> 0.16.0'
|
19
19
|
|
20
20
|
spec.add_development_dependency "bundler", "~> 1.3"
|
21
21
|
spec.add_development_dependency 'ladle'
|
data/lib/github/ldap.rb
CHANGED
@@ -10,6 +10,11 @@ require 'github/ldap/virtual_attributes'
|
|
10
10
|
require 'github/ldap/instrumentation'
|
11
11
|
require 'github/ldap/member_search'
|
12
12
|
require 'github/ldap/membership_validators'
|
13
|
+
require 'github/ldap/user_search/default'
|
14
|
+
require 'github/ldap/user_search/active_directory'
|
15
|
+
require 'github/ldap/connection_cache'
|
16
|
+
require 'github/ldap/referral_chaser'
|
17
|
+
require 'github/ldap/url'
|
13
18
|
|
14
19
|
module GitHub
|
15
20
|
class Ldap
|
@@ -38,11 +43,17 @@ module GitHub
|
|
38
43
|
#
|
39
44
|
# Returns the return value of the block.
|
40
45
|
def_delegator :@connection, :open
|
46
|
+
def_delegator :@connection, :host
|
41
47
|
|
42
48
|
attr_reader :uid, :search_domains, :virtual_attributes,
|
43
49
|
:membership_validator,
|
44
50
|
:member_search_strategy,
|
45
|
-
:instrumentation_service
|
51
|
+
:instrumentation_service,
|
52
|
+
:user_search_strategy,
|
53
|
+
:connection,
|
54
|
+
:admin_user,
|
55
|
+
:admin_password,
|
56
|
+
:port
|
46
57
|
|
47
58
|
# Build a new GitHub::Ldap instance
|
48
59
|
#
|
@@ -50,6 +61,9 @@ module GitHub
|
|
50
61
|
#
|
51
62
|
# host: required string ldap server host address
|
52
63
|
# port: required string or number ldap server port
|
64
|
+
# hosts: an enumerable of pairs of hosts and corresponding ports with
|
65
|
+
# which to attempt opening connections (default [[host, port]]). Overrides
|
66
|
+
# host and port if set.
|
53
67
|
# encryption: optional string. `ssl` or `tls`. nil by default
|
54
68
|
# admin_user: optional string ldap administrator user dn for authentication
|
55
69
|
# admin_password: optional string ldap administrator user password
|
@@ -69,9 +83,15 @@ module GitHub
|
|
69
83
|
def initialize(options = {})
|
70
84
|
@uid = options[:uid] || "sAMAccountName"
|
71
85
|
|
86
|
+
# Keep a reference to these as default auth for a Global Catalog if needed
|
87
|
+
@admin_user = options[:admin_user]
|
88
|
+
@admin_password = options[:admin_password]
|
89
|
+
@port = options[:port]
|
90
|
+
|
72
91
|
@connection = Net::LDAP.new({
|
73
92
|
host: options[:host],
|
74
93
|
port: options[:port],
|
94
|
+
hosts: options[:hosts],
|
75
95
|
instrumentation_service: options[:instrumentation_service]
|
76
96
|
})
|
77
97
|
|
@@ -98,6 +118,9 @@ module GitHub
|
|
98
118
|
# configure both the membership validator and the member search strategies
|
99
119
|
configure_search_strategy(options[:search_strategy])
|
100
120
|
|
121
|
+
# configure the strategy used by Domain#user? to look up a user entry for login
|
122
|
+
configure_user_search_strategy(options[:user_search_strategy])
|
123
|
+
|
101
124
|
# enables instrumenting queries
|
102
125
|
@instrumentation_service = options[:instrumentation_service]
|
103
126
|
end
|
@@ -281,6 +304,28 @@ module GitHub
|
|
281
304
|
end
|
282
305
|
end
|
283
306
|
|
307
|
+
# Internal: Set the user search strategy that will be used by
|
308
|
+
# Domain#user?.
|
309
|
+
#
|
310
|
+
# strategy - Can be either 'default' or 'global_catalog'.
|
311
|
+
# 'default' strategy will search the configured
|
312
|
+
# domain controller with a search base relative
|
313
|
+
# to the controller's domain context.
|
314
|
+
# 'global_catalog' will search the entire forest
|
315
|
+
# using Active Directory's Global Catalog
|
316
|
+
# functionality.
|
317
|
+
def configure_user_search_strategy(strategy)
|
318
|
+
@user_search_strategy =
|
319
|
+
case strategy.to_s
|
320
|
+
when "default"
|
321
|
+
GitHub::Ldap::UserSearch::Default.new(self)
|
322
|
+
when "global_catalog"
|
323
|
+
GitHub::Ldap::UserSearch::ActiveDirectory.new(self)
|
324
|
+
else
|
325
|
+
GitHub::Ldap::UserSearch::Default.new(self)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
284
329
|
# Internal: Configure the member search strategy.
|
285
330
|
#
|
286
331
|
#
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module GitHub
|
2
|
+
class Ldap
|
3
|
+
|
4
|
+
# A simple cache of GitHub::Ldap objects to prevent creating multiple
|
5
|
+
# instances of connections that point to the same URI/host.
|
6
|
+
class ConnectionCache
|
7
|
+
|
8
|
+
# Public - Create or return cached instance of GitHub::Ldap created with options,
|
9
|
+
# where the cache key is the value of options[:host].
|
10
|
+
#
|
11
|
+
# options - Initialization attributes suitable for creating a new connection with
|
12
|
+
# GitHub::Ldap.new(options)
|
13
|
+
#
|
14
|
+
# Returns true or false.
|
15
|
+
def self.get_connection(options={})
|
16
|
+
@cache ||= self.new
|
17
|
+
@cache.get_connection(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_connection(options)
|
21
|
+
@connections ||= {}
|
22
|
+
@connections[options[:host]] ||= GitHub::Ldap.new(options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/github/ldap/domain.rb
CHANGED
@@ -115,10 +115,7 @@ module GitHub
|
|
115
115
|
# Returns the user if the login matches any `uid`.
|
116
116
|
# Returns nil if there are no matches.
|
117
117
|
def user?(login, search_options = {})
|
118
|
-
|
119
|
-
filter: login_filter(@uid, login),
|
120
|
-
size: 1
|
121
|
-
search(options).first
|
118
|
+
@ldap.user_search_strategy.perform(login, @base_name, @uid, search_options).first
|
122
119
|
end
|
123
120
|
|
124
121
|
# Check if a user can be bound with a password.
|
@@ -24,15 +24,23 @@ module GitHub
|
|
24
24
|
# Sets the entry to the base and scopes the search to the base,
|
25
25
|
# according to the source documentation, found here:
|
26
26
|
# http://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx
|
27
|
-
|
27
|
+
#
|
28
|
+
# Use ReferralChaser to chase any potential referrals for an entry that may be owned by a different
|
29
|
+
# domain controller.
|
30
|
+
matched = referral_chaser.search \
|
28
31
|
filter: membership_in_chain_filter(entry),
|
29
32
|
base: entry.dn,
|
30
33
|
scope: Net::LDAP::SearchScope_BaseObject,
|
34
|
+
return_referrals: true,
|
31
35
|
attributes: ATTRS
|
32
36
|
|
33
37
|
# membership validated if entry was matched and returned as a result
|
34
38
|
# Active Directory DNs are case-insensitive
|
35
|
-
matched.map { |m| m.dn.downcase }.include?(entry.dn.downcase)
|
39
|
+
Array(matched).map { |m| m.dn.downcase }.include?(entry.dn.downcase)
|
40
|
+
end
|
41
|
+
|
42
|
+
def referral_chaser
|
43
|
+
@referral_chaser ||= GitHub::Ldap::ReferralChaser.new(@ldap)
|
36
44
|
end
|
37
45
|
|
38
46
|
# Internal: Constructs a membership filter using the "in chain"
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module GitHub
|
2
|
+
class Ldap
|
3
|
+
|
4
|
+
# This class adds referral chasing capability to a GitHub::Ldap connection.
|
5
|
+
#
|
6
|
+
# See: https://technet.microsoft.com/en-us/library/cc978014.aspx
|
7
|
+
# http://www.umich.edu/~dirsvcs/ldap/doc/other/ldap-ref.html
|
8
|
+
#
|
9
|
+
class ReferralChaser
|
10
|
+
|
11
|
+
# Public - Creates a ReferralChaser that decorates an instance of GitHub::Ldap
|
12
|
+
# with additional functionality to the #search method, allowing it to chase
|
13
|
+
# any referral entries and aggregate the results into a single response.
|
14
|
+
#
|
15
|
+
# connection - The instance of GitHub::Ldap to use for searching. Will use
|
16
|
+
# the connection's authentication, (admin_user and admin_password) as credentials
|
17
|
+
# for connecting to referred domain controllers.
|
18
|
+
def initialize(connection)
|
19
|
+
@connection = connection
|
20
|
+
@admin_user = connection.admin_user
|
21
|
+
@admin_password = connection.admin_password
|
22
|
+
@port = connection.port
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public - Search the domain controller represented by this instance's connection.
|
26
|
+
# If a referral is returned, search only one of the domain controllers indicated
|
27
|
+
# by the referral entries, per RFC 4511 (https://tools.ietf.org/html/rfc4511):
|
28
|
+
#
|
29
|
+
# "If the client wishes to progress the operation, it contacts one of
|
30
|
+
# the supported services found in the referral. If multiple URIs are
|
31
|
+
# present, the client assumes that any supported URI may be used to
|
32
|
+
# progress the operation."
|
33
|
+
#
|
34
|
+
# options - is a hash with the same options that Net::LDAP::Connection#search supports.
|
35
|
+
# Referral searches will use the given options, but will replace options[:base]
|
36
|
+
# with the referral URL's base search dn.
|
37
|
+
#
|
38
|
+
# Does not take a block argument as GitHub::Ldap and Net::LDAP::Connection#search do.
|
39
|
+
#
|
40
|
+
# Will not recursively follow any subsequent referrals.
|
41
|
+
#
|
42
|
+
# Returns an Array of Net::LDAP::Entry.
|
43
|
+
def search(options)
|
44
|
+
search_results = []
|
45
|
+
referral_entries = []
|
46
|
+
|
47
|
+
search_results = connection.search(options) do |entry|
|
48
|
+
if entry && entry[:search_referrals]
|
49
|
+
referral_entries << entry
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
unless referral_entries.empty?
|
54
|
+
entry = referral_entries.first
|
55
|
+
referral_string = entry[:search_referrals].first
|
56
|
+
if GitHub::Ldap::URL.valid?(referral_string)
|
57
|
+
referral = Referral.new(referral_string, admin_user, admin_password, port)
|
58
|
+
search_results = referral.search(options)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Array(search_results)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
attr_reader :connection, :admin_user, :admin_password, :port
|
68
|
+
|
69
|
+
# Represents a referral entry from an LDAP search result. Constructs a corresponding
|
70
|
+
# GitHub::Ldap object from the paramaters on the referral_url and provides a #search
|
71
|
+
# method to continue the search on the referred domain.
|
72
|
+
class Referral
|
73
|
+
def initialize(referral_url, admin_user, admin_password, port=nil)
|
74
|
+
url = GitHub::Ldap::URL.new(referral_url)
|
75
|
+
@search_base = url.dn
|
76
|
+
|
77
|
+
connection_options = {
|
78
|
+
host: url.host,
|
79
|
+
port: port || url.port,
|
80
|
+
scope: url.scope,
|
81
|
+
admin_user: admin_user,
|
82
|
+
admin_password: admin_password
|
83
|
+
}
|
84
|
+
|
85
|
+
@connection = GitHub::Ldap::ConnectionCache.get_connection(connection_options)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Search the referred domain controller with options, merging in the referred search
|
89
|
+
# base DN onto options[:base].
|
90
|
+
def search(options)
|
91
|
+
connection.search(options.merge(base: search_base))
|
92
|
+
end
|
93
|
+
|
94
|
+
attr_reader :search_base, :connection
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module GitHub
|
2
|
+
class Ldap
|
3
|
+
|
4
|
+
# This class represents an LDAP URL
|
5
|
+
#
|
6
|
+
# See: https://tools.ietf.org/html/rfc4516#section-2
|
7
|
+
# https://docs.oracle.com/cd/E19957-01/817-6707/urls.html
|
8
|
+
#
|
9
|
+
class URL
|
10
|
+
extend Forwardable
|
11
|
+
SCOPES = {
|
12
|
+
"base" => Net::LDAP::SearchScope_BaseObject,
|
13
|
+
"one" => Net::LDAP::SearchScope_SingleLevel,
|
14
|
+
"sub" => Net::LDAP::SearchScope_WholeSubtree
|
15
|
+
}
|
16
|
+
SCOPES.default = Net::LDAP::SearchScope_BaseObject
|
17
|
+
|
18
|
+
attr_reader :dn, :attributes, :scope, :filter
|
19
|
+
|
20
|
+
def_delegators :@uri, :port, :host, :scheme
|
21
|
+
|
22
|
+
# Public - Creates a new GitHub::Ldap::URL object with :port, :host and :scheme
|
23
|
+
# delegated to a URI object parsed from url_string, and then parses the
|
24
|
+
# query params according to the LDAP specification.
|
25
|
+
#
|
26
|
+
# url_string - An LDAP URL string.
|
27
|
+
# returns - a GitHub::Ldap::URL with the following attributes:
|
28
|
+
# host - Name or IP of the LDAP server.
|
29
|
+
# port - The given port, defaults to 389.
|
30
|
+
# dn - The base search DN.
|
31
|
+
# attributes - The comma-delimited list of attributes to be returned.
|
32
|
+
# scope - The scope of the search.
|
33
|
+
# filter - Search filter to apply to entries within the specified scope of the search.
|
34
|
+
#
|
35
|
+
# Supported LDAP URL strings look like this, where sections in brackets are optional:
|
36
|
+
#
|
37
|
+
# ldap[s]://[hostport][/[dn[?[attributes][?[scope][?[filter]]]]]]
|
38
|
+
#
|
39
|
+
# where:
|
40
|
+
#
|
41
|
+
# hostport is a host name with an optional ":portnumber"
|
42
|
+
# dn is the base DN to be used for an LDAP search operation
|
43
|
+
# attributes is a comma separated list of attributes to be retrieved
|
44
|
+
# scope is one of these three strings: base one sub (default=base)
|
45
|
+
# filter is LDAP search filter as used in a call to ldap_search
|
46
|
+
#
|
47
|
+
# For example:
|
48
|
+
#
|
49
|
+
# ldap://dc4.ghe.local:456/CN=Maggie,DC=dc4,DC=ghe,DC=local?cn,mail?base?(cn=Charlie)
|
50
|
+
#
|
51
|
+
def initialize(url_string)
|
52
|
+
if !self.class.valid?(url_string)
|
53
|
+
raise InvalidLdapURLException.new("Invalid LDAP URL: #{url_string}")
|
54
|
+
end
|
55
|
+
@uri = URI(url_string)
|
56
|
+
@dn = URI.unescape(@uri.path.sub(/^\//, ""))
|
57
|
+
if @uri.query
|
58
|
+
@attributes, @scope, @filter = @uri.query.split("?")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.valid?(url_string)
|
63
|
+
url_string =~ URI::regexp && ["ldap", "ldaps"].include?(URI(url_string).scheme)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Maps the returned scope value from the URL to one of Net::LDAP::Scopes
|
67
|
+
#
|
68
|
+
# The URL scope value can be one of:
|
69
|
+
# "base" - retrieves information only about the DN (base_dn) specified.
|
70
|
+
# "one" - retrieves information about entries one level below the DN (base_dn) specified. The base entry is not included in this scope.
|
71
|
+
# "sub" - retrieves information about entries at all levels below the DN (base_dn) specified. The base entry is included in this scope.
|
72
|
+
#
|
73
|
+
# Which will map to one of the following Net::LDAP::Scopes:
|
74
|
+
# SearchScope_BaseObject = 0
|
75
|
+
# SearchScope_SingleLevel = 1
|
76
|
+
# SearchScope_WholeSubtree = 2
|
77
|
+
#
|
78
|
+
# If no scope or an invalid scope is given, defaults to SearchScope_BaseObject
|
79
|
+
def net_ldap_scope
|
80
|
+
Net::LDAP::SearchScopes[SCOPES[scope]]
|
81
|
+
end
|
82
|
+
|
83
|
+
class InvalidLdapURLException < Exception; end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module GitHub
|
2
|
+
class Ldap
|
3
|
+
module UserSearch
|
4
|
+
class ActiveDirectory < Default
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
# Private - Overridden from base class to set the base to "", and use the
|
9
|
+
# Global Catalog to perform the user search.
|
10
|
+
def search(search_options)
|
11
|
+
Array(global_catalog_connection.search(search_options.merge(options)))
|
12
|
+
end
|
13
|
+
|
14
|
+
def global_catalog_connection
|
15
|
+
GlobalCatalog.connection(ldap)
|
16
|
+
end
|
17
|
+
|
18
|
+
# When doing a global search for a user's DN, set the search base to blank
|
19
|
+
def options
|
20
|
+
super.merge(base: "")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class GlobalCatalog < Net::LDAP
|
25
|
+
STANDARD_GC_PORT = 3268
|
26
|
+
LDAPS_GC_PORT = 3269
|
27
|
+
|
28
|
+
# Returns a connection to the Active Directory Global Catalog
|
29
|
+
#
|
30
|
+
# See: https://technet.microsoft.com/en-us/library/cc728188(v=ws.10).aspx
|
31
|
+
#
|
32
|
+
def self.connection(ldap)
|
33
|
+
@global_catalog_instance ||= begin
|
34
|
+
netldap = ldap.connection
|
35
|
+
# This is ugly, but Net::LDAP doesn't expose encryption or auth
|
36
|
+
encryption = netldap.instance_variable_get(:@encryption)
|
37
|
+
auth = netldap.instance_variable_get(:@auth)
|
38
|
+
|
39
|
+
new({
|
40
|
+
host: ldap.host,
|
41
|
+
instrumentation_service: ldap.instrumentation_service,
|
42
|
+
port: encryption ? LDAPS_GC_PORT : STANDARD_GC_PORT,
|
43
|
+
auth: auth,
|
44
|
+
encryption: encryption
|
45
|
+
})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module GitHub
|
2
|
+
class Ldap
|
3
|
+
module UserSearch
|
4
|
+
# The default user search strategy, mainly for allowing Domain#user? to
|
5
|
+
# search for a user on the configured domain controller, or use the Global
|
6
|
+
# Catalog to search across the entire Active Directory forest.
|
7
|
+
class Default
|
8
|
+
include Filter
|
9
|
+
|
10
|
+
def initialize(ldap)
|
11
|
+
@ldap = ldap
|
12
|
+
@options = {
|
13
|
+
:attributes => [],
|
14
|
+
:paged_searches_supported => true,
|
15
|
+
:size => 1
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Performs a normal search on the configured domain controller
|
20
|
+
# using the default base DN, uid, search_options
|
21
|
+
def perform(login, base_name, uid, search_options)
|
22
|
+
search_options[:filter] = login_filter(uid, login)
|
23
|
+
search_options[:base] = base_name
|
24
|
+
search(options.merge(search_options))
|
25
|
+
end
|
26
|
+
|
27
|
+
# The default search. This can be overridden by a child class
|
28
|
+
# like GitHub::Ldap::UserSearch::ActiveDirectory to change the
|
29
|
+
# scope of the search.
|
30
|
+
def search(options)
|
31
|
+
ldap.search(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :options, :ldap
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class GitHubLdapConnectionCacheTestCases < GitHub::Ldap::Test
|
4
|
+
|
5
|
+
def test_returns_cached_connection
|
6
|
+
conn1 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad1.ghe.dev"))
|
7
|
+
conn2 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad1.ghe.dev"))
|
8
|
+
assert_equal conn1.object_id, conn2.object_id
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_creates_new_connections_per_host
|
12
|
+
conn1 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad1.ghe.dev"))
|
13
|
+
conn2 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad2.ghe.dev"))
|
14
|
+
conn3 = GitHub::Ldap::ConnectionCache.get_connection(options.merge(:host => "ad2.ghe.dev"))
|
15
|
+
refute_equal conn1.object_id, conn2.object_id
|
16
|
+
assert_equal conn2.object_id, conn3.object_id
|
17
|
+
end
|
18
|
+
end
|
data/test/domain_test.rb
CHANGED
@@ -140,6 +140,15 @@ module GitHubLdapDomainTestCases
|
|
140
140
|
assert user = @domain.user?('user1')
|
141
141
|
refute @domain.auth(user, 'foo'), 'Expected user not not bind'
|
142
142
|
end
|
143
|
+
|
144
|
+
def test_user_search_returns_first_entry
|
145
|
+
entry = mock("Net::Ldap::Entry")
|
146
|
+
search_strategy = mock("GitHub::Ldap::UserSearch::Default")
|
147
|
+
search_strategy.stubs(:perform).returns([entry])
|
148
|
+
@ldap.expects(:user_search_strategy).returns(search_strategy)
|
149
|
+
user = @domain.user?('user1', :attributes => [:cn])
|
150
|
+
assert_equal entry, user
|
151
|
+
end
|
143
152
|
end
|
144
153
|
|
145
154
|
class GitHubLdapDomainTest < GitHub::Ldap::Test
|
data/test/ldap_test.rb
CHANGED
@@ -9,6 +9,21 @@ module GitHubLdapTestCases
|
|
9
9
|
assert @ldap.test_connection, "Ldap connection expected to succeed"
|
10
10
|
end
|
11
11
|
|
12
|
+
def test_connection_with_list_of_hosts_with_one_valid_host
|
13
|
+
ldap = GitHub::Ldap.new(options.merge(hosts: [["localhost", options[:port]]]))
|
14
|
+
assert ldap.test_connection, "Ldap connection expected to succeed"
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_connection_with_list_of_hosts_with_first_valid
|
18
|
+
ldap = GitHub::Ldap.new(options.merge(hosts: [["localhost", options[:port]], ["invalid.local", options[:port]]]))
|
19
|
+
assert ldap.test_connection, "Ldap connection expected to succeed"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_connection_with_list_of_hosts_with_first_invalid
|
23
|
+
ldap = GitHub::Ldap.new(options.merge(hosts: [["invalid.local", options[:port]], ["localhost", options[:port]]]))
|
24
|
+
assert ldap.test_connection, "Ldap connection expected to succeed"
|
25
|
+
end
|
26
|
+
|
12
27
|
def test_simple_tls
|
13
28
|
assert_equal :simple_tls, @ldap.check_encryption(:ssl)
|
14
29
|
assert_equal :simple_tls, @ldap.check_encryption('SSL')
|
@@ -114,6 +129,17 @@ module GitHubLdapTestCases
|
|
114
129
|
assert_equal GitHub::Ldap::MemberSearch::Recursive, @ldap.member_search_strategy
|
115
130
|
end
|
116
131
|
|
132
|
+
def test_user_search_strategy_global_catalog_when_configured
|
133
|
+
@ldap.configure_user_search_strategy("global_catalog")
|
134
|
+
assert_kind_of GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_user_search_strategy_default_when_configured
|
138
|
+
@ldap.configure_user_search_strategy("default")
|
139
|
+
refute_kind_of GitHub::Ldap::UserSearch::ActiveDirectory, @ldap.user_search_strategy
|
140
|
+
assert_kind_of GitHub::Ldap::UserSearch::Default, @ldap.user_search_strategy
|
141
|
+
end
|
142
|
+
|
117
143
|
def test_capabilities
|
118
144
|
assert_kind_of Net::LDAP::Entry, @ldap.capabilities
|
119
145
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class GitHubLdapReferralChaserTestCases < GitHub::Ldap::Test
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@ldap = GitHub::Ldap.new(options)
|
7
|
+
@chaser = GitHub::Ldap::ReferralChaser.new(@ldap)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_creates_referral_with_connection_credentials
|
11
|
+
@ldap.expects(:search).yields({ search_referrals: ["ldap://dc1.ghe.local/"]}).returns([])
|
12
|
+
|
13
|
+
referral = mock("GitHub::Ldap::ReferralChaser::Referral")
|
14
|
+
referral.stubs(:search).returns([])
|
15
|
+
|
16
|
+
GitHub::Ldap::ReferralChaser::Referral.expects(:new)
|
17
|
+
.with("ldap://dc1.ghe.local/", "uid=admin,dc=github,dc=com", "passworD1", options[:port])
|
18
|
+
.returns(referral)
|
19
|
+
|
20
|
+
@chaser.search({})
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_creates_referral_with_default_port
|
24
|
+
@ldap.expects(:search).yields({
|
25
|
+
search_referrals: ["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]
|
26
|
+
}).returns([])
|
27
|
+
|
28
|
+
stub_referral_connection = mock("GitHub::Ldap")
|
29
|
+
stub_referral_connection.stubs(:search).returns([])
|
30
|
+
GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(port: options[:port])).returns(stub_referral_connection)
|
31
|
+
chaser = GitHub::Ldap::ReferralChaser.new(@ldap)
|
32
|
+
chaser.search({})
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_creates_referral_for_first_referral_string
|
36
|
+
@ldap.expects(:search).multiple_yields([
|
37
|
+
{ search_referrals:
|
38
|
+
["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local",
|
39
|
+
"ldap://dc2.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]
|
40
|
+
}
|
41
|
+
],[
|
42
|
+
{ search_referrals:
|
43
|
+
["ldap://dc3.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local",
|
44
|
+
"ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]
|
45
|
+
}
|
46
|
+
]).returns([])
|
47
|
+
|
48
|
+
referral = mock("GitHub::Ldap::ReferralChaser::Referral")
|
49
|
+
referral.stubs(:search).returns([])
|
50
|
+
|
51
|
+
GitHub::Ldap::ReferralChaser::Referral.expects(:new)
|
52
|
+
.with(
|
53
|
+
"ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local",
|
54
|
+
"uid=admin,dc=github,dc=com",
|
55
|
+
"passworD1",
|
56
|
+
options[:port])
|
57
|
+
.returns(referral)
|
58
|
+
|
59
|
+
@chaser.search({})
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_returns_referral_search_results
|
63
|
+
@ldap.expects(:search).multiple_yields([
|
64
|
+
{ search_referrals:
|
65
|
+
["ldap://dc1.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local",
|
66
|
+
"ldap://dc2.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]
|
67
|
+
}
|
68
|
+
],[
|
69
|
+
{ search_referrals:
|
70
|
+
["ldap://dc3.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local",
|
71
|
+
"ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local"]
|
72
|
+
}
|
73
|
+
]).returns([])
|
74
|
+
|
75
|
+
referral = mock("GitHub::Ldap::ReferralChaser::Referral")
|
76
|
+
referral.expects(:search).returns(["result", "result"])
|
77
|
+
|
78
|
+
GitHub::Ldap::ReferralChaser::Referral.expects(:new).returns(referral)
|
79
|
+
|
80
|
+
results = @chaser.search({})
|
81
|
+
assert_equal(["result", "result"], results)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_handle_blank_url_string_in_referral
|
85
|
+
@ldap.expects(:search).yields({ search_referrals: [""] })
|
86
|
+
|
87
|
+
results = @chaser.search({})
|
88
|
+
assert_equal([], results)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_returns_referral_search_results
|
92
|
+
@ldap.expects(:search).yields({ foo: ["not a referral"] })
|
93
|
+
|
94
|
+
GitHub::Ldap::ReferralChaser::Referral.expects(:new).never
|
95
|
+
results = @chaser.search({})
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_referral_should_use_host_from_referral_string
|
99
|
+
GitHub::Ldap::ConnectionCache.expects(:get_connection).with(has_entry(host: "dc4.ghe.local"))
|
100
|
+
GitHub::Ldap::ReferralChaser::Referral.new("ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local", "", "")
|
101
|
+
end
|
102
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -13,6 +13,8 @@ require 'github/ldap/server'
|
|
13
13
|
require 'minitest/mock'
|
14
14
|
require 'minitest/autorun'
|
15
15
|
|
16
|
+
require 'mocha/mini_test'
|
17
|
+
|
16
18
|
if ENV.fetch('TESTENV', "apacheds") == "apacheds"
|
17
19
|
# Make sure we clean up running test server
|
18
20
|
# NOTE: We need to do this manually since its internal `at_exit` hook
|
data/test/url_test.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class GitHubLdapURLTestCases < GitHub::Ldap::Test
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local:123/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local?cn,mail,telephoneNumber?base?(cn=Charlie)")
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_host
|
10
|
+
assert_equal "dc4.ghe.local", @url.host
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_port
|
14
|
+
assert_equal 123, @url.port
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_scheme
|
18
|
+
assert_equal "ldap", @url.scheme
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_default_port
|
22
|
+
url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local/CN=Maggie%20Mae,CN=Users,DC=dc4,DC=ghe,DC=local?attributes?scope?filter")
|
23
|
+
assert_equal 389, url.port
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_simple_url
|
27
|
+
url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local")
|
28
|
+
assert_equal 389, url.port
|
29
|
+
assert_equal "dc4.ghe.local", url.host
|
30
|
+
assert_equal "ldap", url.scheme
|
31
|
+
assert_equal "", url.dn
|
32
|
+
assert_equal nil, url.attributes
|
33
|
+
assert_equal nil, url.filter
|
34
|
+
assert_equal nil, url.scope
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_invalid_scheme
|
38
|
+
ex = assert_raises(GitHub::Ldap::URL::InvalidLdapURLException) do
|
39
|
+
GitHub::Ldap::URL.new("http://dc4.ghe.local")
|
40
|
+
end
|
41
|
+
assert_equal("Invalid LDAP URL: http://dc4.ghe.local", ex.message)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_invalid_url
|
45
|
+
ex = assert_raises(GitHub::Ldap::URL::InvalidLdapURLException) do
|
46
|
+
GitHub::Ldap::URL.new("not a url")
|
47
|
+
end
|
48
|
+
assert_equal("Invalid LDAP URL: not a url", ex.message)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_parse_dn
|
52
|
+
assert_equal "CN=Maggie Mae,CN=Users,DC=dc4,DC=ghe,DC=local", @url.dn
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_parse_attributes
|
56
|
+
assert_equal "cn,mail,telephoneNumber", @url.attributes
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_parse_filter
|
60
|
+
assert_equal "(cn=Charlie)", @url.filter
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_parse_scope
|
64
|
+
assert_equal "base", @url.scope
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_default_scope
|
68
|
+
url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local/base_dn?cn=joe??filter")
|
69
|
+
assert_equal "", url.scope
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_net_ldap_scopes
|
73
|
+
sub_scope_url = GitHub::Ldap::URL.new("ldap://ghe.local/base_dn?cn=joe?sub?filter")
|
74
|
+
one_scope_url = GitHub::Ldap::URL.new("ldap://ghe.local/base_dn?cn=joe?one?filter")
|
75
|
+
base_scope_url = GitHub::Ldap::URL.new("ldap://ghe.local/base_dn?cn=joe?base?filter")
|
76
|
+
default_scope_url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local/base_dn?cn=joe??filter")
|
77
|
+
invalid_scope_url = GitHub::Ldap::URL.new("ldap://dc4.ghe.local/base_dn?cn=joe?invalid?filter")
|
78
|
+
|
79
|
+
assert_equal Net::LDAP::SearchScope_BaseObject, base_scope_url.net_ldap_scope
|
80
|
+
assert_equal Net::LDAP::SearchScope_SingleLevel, one_scope_url.net_ldap_scope
|
81
|
+
assert_equal Net::LDAP::SearchScope_WholeSubtree, sub_scope_url.net_ldap_scope
|
82
|
+
assert_equal Net::LDAP::SearchScope_BaseObject, default_scope_url.net_ldap_scope
|
83
|
+
assert_equal Net::LDAP::SearchScope_BaseObject, invalid_scope_url.net_ldap_scope
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class GitHubLdapActiveDirectoryUserSearchTests < GitHub::Ldap::Test
|
4
|
+
|
5
|
+
def test_global_catalog_returns_empty_array_for_no_results
|
6
|
+
ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev'))
|
7
|
+
ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(ldap)
|
8
|
+
|
9
|
+
mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog")
|
10
|
+
mock_global_catalog_connection.expects(:search).returns(nil)
|
11
|
+
ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection)
|
12
|
+
results = ad_user_search.perform("login", "CN=Joe", "uid", {})
|
13
|
+
assert_equal [], results
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_global_catalog_returns_array_of_results
|
17
|
+
ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev'))
|
18
|
+
ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(ldap)
|
19
|
+
|
20
|
+
mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog")
|
21
|
+
stub_entry = mock("Net::LDAP::Entry")
|
22
|
+
|
23
|
+
mock_global_catalog_connection.expects(:search).returns(stub_entry)
|
24
|
+
ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection)
|
25
|
+
|
26
|
+
results = ad_user_search.perform("login", "CN=Joe", "uid", {})
|
27
|
+
assert_equal [stub_entry], results
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_searches_with_empty_base_dn
|
31
|
+
ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev'))
|
32
|
+
ad_user_search = GitHub::Ldap::UserSearch::ActiveDirectory.new(ldap)
|
33
|
+
|
34
|
+
mock_global_catalog_connection = mock("GitHub::Ldap::UserSearch::GlobalCatalog")
|
35
|
+
mock_global_catalog_connection.expects(:search).with(has_entry(:base => ""))
|
36
|
+
ad_user_search.expects(:global_catalog_connection).returns(mock_global_catalog_connection)
|
37
|
+
ad_user_search.perform("login", "CN=Joe", "uid", {})
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_global_catalog_default_settings
|
41
|
+
ldap = GitHub::Ldap.new(options.merge(host: 'ghe.dev'))
|
42
|
+
global_catalog = GitHub::Ldap::UserSearch::GlobalCatalog.connection(ldap)
|
43
|
+
instrumentation_service = global_catalog.instance_variable_get(:@instrumentation_service)
|
44
|
+
|
45
|
+
auth = global_catalog.instance_variable_get(:@auth)
|
46
|
+
assert_equal :simple, auth[:method]
|
47
|
+
assert_equal "uid=admin,dc=github,dc=com", auth[:username]
|
48
|
+
assert_equal "passworD1", auth[:password]
|
49
|
+
assert_equal "ghe.dev", global_catalog.host
|
50
|
+
assert_equal 3268, global_catalog.port
|
51
|
+
assert_equal "MockInstrumentationService", instrumentation_service.class.name
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class GitHubLdapActiveDirectoryUserSearchTests < GitHub::Ldap::Test
|
4
|
+
def setup
|
5
|
+
@ldap = GitHub::Ldap.new(options)
|
6
|
+
@default_user_search = GitHub::Ldap::UserSearch::Default.new(@ldap)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_default_search_options
|
10
|
+
@ldap.expects(:search).with(has_entries(
|
11
|
+
attributes: [],
|
12
|
+
size: 1,
|
13
|
+
paged_searches_supported: true,
|
14
|
+
base: "CN=HI,CN=McDunnough",
|
15
|
+
filter: kind_of(Net::LDAP::Filter)
|
16
|
+
))
|
17
|
+
@default_user_search.perform("","CN=HI,CN=McDunnough","",{})
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: github-ldap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.10.
|
4
|
+
version: 1.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Calavera
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2017-02-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: net-ldap
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 0.
|
20
|
+
version: 0.16.0
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 0.
|
27
|
+
version: 0.16.0
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: bundler
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- Rakefile
|
99
99
|
- github-ldap.gemspec
|
100
100
|
- lib/github/ldap.rb
|
101
|
+
- lib/github/ldap/connection_cache.rb
|
101
102
|
- lib/github/ldap/domain.rb
|
102
103
|
- lib/github/ldap/filter.rb
|
103
104
|
- lib/github/ldap/fixtures.ldif
|
@@ -114,7 +115,11 @@ files:
|
|
114
115
|
- lib/github/ldap/membership_validators/classic.rb
|
115
116
|
- lib/github/ldap/membership_validators/recursive.rb
|
116
117
|
- lib/github/ldap/posix_group.rb
|
118
|
+
- lib/github/ldap/referral_chaser.rb
|
117
119
|
- lib/github/ldap/server.rb
|
120
|
+
- lib/github/ldap/url.rb
|
121
|
+
- lib/github/ldap/user_search/active_directory.rb
|
122
|
+
- lib/github/ldap/user_search/default.rb
|
118
123
|
- lib/github/ldap/virtual_attributes.rb
|
119
124
|
- lib/github/ldap/virtual_group.rb
|
120
125
|
- script/changelog
|
@@ -123,6 +128,7 @@ files:
|
|
123
128
|
- script/install-openldap
|
124
129
|
- script/package
|
125
130
|
- script/release
|
131
|
+
- test/connection_cache_test.rb
|
126
132
|
- test/domain_test.rb
|
127
133
|
- test/filter_test.rb
|
128
134
|
- test/fixtures/common/seed.ldif
|
@@ -138,6 +144,7 @@ files:
|
|
138
144
|
- test/membership_validators/classic_test.rb
|
139
145
|
- test/membership_validators/recursive_test.rb
|
140
146
|
- test/posix_group_test.rb
|
147
|
+
- test/referral_chaser_test.rb
|
141
148
|
- test/support/vm/activedirectory/.gitignore
|
142
149
|
- test/support/vm/activedirectory/README.md
|
143
150
|
- test/support/vm/activedirectory/env.sh.example
|
@@ -146,6 +153,9 @@ files:
|
|
146
153
|
- test/support/vm/openldap/README.md
|
147
154
|
- test/support/vm/openldap/Vagrantfile
|
148
155
|
- test/test_helper.rb
|
156
|
+
- test/url_test.rb
|
157
|
+
- test/user_search/active_directory_test.rb
|
158
|
+
- test/user_search/default_test.rb
|
149
159
|
homepage: https://github.com/github/github-ldap
|
150
160
|
licenses:
|
151
161
|
- MIT
|
@@ -166,11 +176,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
176
|
version: '0'
|
167
177
|
requirements: []
|
168
178
|
rubyforge_project:
|
169
|
-
rubygems_version: 2.5.
|
179
|
+
rubygems_version: 2.5.2
|
170
180
|
signing_key:
|
171
181
|
specification_version: 4
|
172
182
|
summary: LDAP client authentication wrapper without all the boilerplate
|
173
183
|
test_files:
|
184
|
+
- test/connection_cache_test.rb
|
174
185
|
- test/domain_test.rb
|
175
186
|
- test/filter_test.rb
|
176
187
|
- test/fixtures/common/seed.ldif
|
@@ -186,6 +197,7 @@ test_files:
|
|
186
197
|
- test/membership_validators/classic_test.rb
|
187
198
|
- test/membership_validators/recursive_test.rb
|
188
199
|
- test/posix_group_test.rb
|
200
|
+
- test/referral_chaser_test.rb
|
189
201
|
- test/support/vm/activedirectory/.gitignore
|
190
202
|
- test/support/vm/activedirectory/README.md
|
191
203
|
- test/support/vm/activedirectory/env.sh.example
|
@@ -194,3 +206,6 @@ test_files:
|
|
194
206
|
- test/support/vm/openldap/README.md
|
195
207
|
- test/support/vm/openldap/Vagrantfile
|
196
208
|
- test/test_helper.rb
|
209
|
+
- test/url_test.rb
|
210
|
+
- test/user_search/active_directory_test.rb
|
211
|
+
- test/user_search/default_test.rb
|