el_dap 0.0.2 → 0.0.3
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.
- data/CHANGELOG +6 -0
- data/README.rdoc +19 -1
- data/TODO.rdoc +5 -0
- data/lib/el_dap.rb +4 -0
- data/lib/el_dap/base.rb +15 -47
- data/lib/el_dap/exceptions.rb +3 -0
- data/lib/el_dap/validator.rb +11 -0
- data/lib/el_dap/version.rb +1 -1
- data/lib/el_dap/worker.rb +38 -0
- data/spec/el_dap/base_spec.rb +64 -91
- data/spec/el_dap/validator_spec.rb +31 -0
- data/spec/el_dap/worker_spec.rb +44 -0
- metadata +10 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
0.0.3
|
2
|
+
=====
|
3
|
+
|
4
|
+
* When using multiple servers, return the first valid result. Only use additional servers on a timeout exception.
|
5
|
+
* An InvalidCredentialsError exception will be thrown on a search if the user credentials are invalid i.e. cannot bind
|
6
|
+
|
1
7
|
0.0.2
|
2
8
|
=====
|
3
9
|
|
data/README.rdoc
CHANGED
@@ -24,7 +24,25 @@ Just add this to your gem file:
|
|
24
24
|
|
25
25
|
== Usage
|
26
26
|
|
27
|
-
|
27
|
+
=== Confguration
|
28
|
+
|
29
|
+
To perform any ElDap operation you will need to provide at least two configuration values:
|
30
|
+
|
31
|
+
* *server_ips*: an array of server IP addresses
|
32
|
+
* *treebase*: a comma-seperated list of domain components
|
33
|
+
|
34
|
+
For search operations you will also need to provide the following configuration settings:
|
35
|
+
|
36
|
+
* *username*: the username of the account that will perform the search (typically this would be a service account)
|
37
|
+
* *password*: the password of the account that will perform the search
|
38
|
+
|
39
|
+
You also have the option of providing a timeout value:
|
40
|
+
|
41
|
+
* *timeout*: timeout in seconds for ElDap operations (default is 15 seconds)
|
42
|
+
|
43
|
+
=== Examples
|
44
|
+
|
45
|
+
Assuming we have an Active Directory called <b>ad.domain.com</b> which can also be referred to simply as *ad*,
|
28
46
|
the following examples are valid:
|
29
47
|
|
30
48
|
=== Authenticate a user
|
data/TODO.rdoc
ADDED
data/lib/el_dap.rb
CHANGED
data/lib/el_dap/base.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module ElDap
|
2
2
|
class Base
|
3
|
-
include Constants
|
4
|
-
|
5
3
|
attr_accessor :server_ips, :username, :password, :timeout, :treebase
|
6
4
|
|
7
5
|
def initialize
|
@@ -10,69 +8,39 @@ module ElDap
|
|
10
8
|
yield(self) if block_given?
|
11
9
|
end
|
12
10
|
|
13
|
-
def validate(
|
14
|
-
return false if
|
15
|
-
|
11
|
+
def validate(username, password)
|
12
|
+
return false if Validator.blank?(username, password)
|
13
|
+
|
14
|
+
@server_ips.each do |ip_address|
|
16
15
|
begin
|
17
16
|
Timeout::timeout(self.timeout) do
|
17
|
+
worker = Worker.new(:username => username, :password => password, :ip_address => ip_address)
|
18
18
|
return worker.bind
|
19
19
|
end
|
20
20
|
rescue Timeout::Error
|
21
21
|
next
|
22
22
|
end
|
23
23
|
end
|
24
|
-
false
|
25
24
|
end
|
26
25
|
|
27
26
|
def search(search_string)
|
28
|
-
return nil if
|
29
|
-
|
30
|
-
|
27
|
+
return nil if Validator.blank?(search_string)
|
28
|
+
|
29
|
+
search_result = []
|
30
|
+
|
31
|
+
@server_ips.each do |ip_address|
|
31
32
|
begin
|
32
33
|
Timeout::timeout(self.timeout) do
|
33
|
-
|
34
|
+
worker = Worker.new(:username => self.username, :password => self.password, :ip_address => ip_address)
|
35
|
+
|
36
|
+
raise(InvalidCredentialsError, 'The user credentials provided are invalid') unless worker.bind
|
37
|
+
|
38
|
+
return worker.search_directory(search_string, self.treebase)
|
34
39
|
end
|
35
40
|
rescue Timeout::Error
|
36
41
|
next
|
37
42
|
end
|
38
43
|
end
|
39
|
-
create_result_collection search_result
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
def workers(uname = self.username, pword = self.password)
|
44
|
-
self.server_ips.map do |ip|
|
45
|
-
create_worker uname, pword, ip
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def create_worker(uname, pword, server_ip)
|
50
|
-
obj = ::Net::LDAP.new
|
51
|
-
obj.host = server_ip
|
52
|
-
obj.auth uname, pword
|
53
|
-
obj
|
54
|
-
end
|
55
|
-
|
56
|
-
def search_active_directory(worker, search_string)
|
57
|
-
filters = LDAP_FILTERS & ::Net::LDAP::Filter.eq(LDAP_SEARCH_FIELD, "*#{search_string}*")
|
58
|
-
result = worker.search(:base => self.treebase,
|
59
|
-
:filter => filters,
|
60
|
-
:attributes => LDAP_ATTRS,
|
61
|
-
:return_result => true)
|
62
|
-
# search will return false if unable to bind
|
63
|
-
# e.g. service account credentials have expired
|
64
|
-
result || []
|
65
|
-
end
|
66
|
-
|
67
|
-
def create_result_collection(collection = [])
|
68
|
-
collection ||= []
|
69
|
-
collection.map { |entry| create_struct entry }
|
70
|
-
end
|
71
|
-
|
72
|
-
def create_struct(hash = {})
|
73
|
-
key_values = {}
|
74
|
-
hash.each{|k, v| key_values[k] = v[0]}
|
75
|
-
OpenStruct.new(key_values)
|
76
44
|
end
|
77
45
|
|
78
46
|
end
|
data/lib/el_dap/version.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
module ElDap
|
2
|
+
class Worker < ::Net::LDAP
|
3
|
+
include Constants
|
4
|
+
|
5
|
+
def initialize(args = {})
|
6
|
+
super args
|
7
|
+
self.host = args[:ip_address]
|
8
|
+
self.auth args[:username], args[:password]
|
9
|
+
self
|
10
|
+
end
|
11
|
+
|
12
|
+
def search_directory(search_string, treebase)
|
13
|
+
filters = LDAP_FILTERS & ::Net::LDAP::Filter.eq(LDAP_SEARCH_FIELD, "*#{search_string}*")
|
14
|
+
search_result = search(:base => treebase,
|
15
|
+
:filter => filters,
|
16
|
+
:attributes => LDAP_ATTRS,
|
17
|
+
:return_result => true)
|
18
|
+
# search will return false if unable to bind
|
19
|
+
# e.g. service account credentials have expired
|
20
|
+
return [] unless search_result
|
21
|
+
create_result_collection search_result
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_result_collection(collection = [])
|
27
|
+
collection ||= []
|
28
|
+
collection.map { |entry| create_struct entry }
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_struct(hash = {})
|
32
|
+
key_values = {}
|
33
|
+
hash.each{|k, v| key_values[k] = v[0]}
|
34
|
+
OpenStruct.new(key_values)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/spec/el_dap/base_spec.rb
CHANGED
@@ -2,110 +2,83 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module ElDap
|
4
4
|
describe Base do
|
5
|
-
|
6
5
|
before(:each) do
|
7
|
-
@instance = Base.new
|
8
|
-
|
6
|
+
@instance = Base.new do |i|
|
7
|
+
i.username = 'name'
|
8
|
+
i.password = 'password'
|
9
|
+
i.server_ips = ['1.1.1.1', '2.2.2.2']
|
10
|
+
i.timeout = 10
|
11
|
+
i.treebase = 'tree'
|
12
|
+
end
|
13
|
+
Validator.stub!(:blank?)
|
14
|
+
Worker.stub!(:new)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should initialize with a block" do
|
18
|
+
@instance.username.should == 'name'
|
19
|
+
@instance.password.should == 'password'
|
20
|
+
@instance.server_ips.should == ['1.1.1.1', '2.2.2.2']
|
21
|
+
@instance.timeout.should == 10
|
22
|
+
@instance.treebase.should == 'tree'
|
9
23
|
end
|
10
24
|
|
11
|
-
describe
|
12
|
-
|
13
|
-
@
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
25
|
+
describe '#Validate' do
|
26
|
+
before(:each) do
|
27
|
+
@worker = mock(Worker, :bind => true)
|
28
|
+
Worker.stub!(:new).and_return(@worker)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should check that username and password are not blank" do
|
32
|
+
Validator.should_receive(:blank?).and_return(true)
|
18
33
|
@instance.validate(nil, nil).should be_false
|
19
34
|
end
|
20
|
-
|
21
|
-
it "should
|
22
|
-
|
23
|
-
@instance.
|
24
|
-
@instance.search(nil).should be_nil
|
35
|
+
|
36
|
+
it "should create a new worker for the first ip address" do
|
37
|
+
Worker.should_receive(:new).and_return(@worker)
|
38
|
+
@instance.validate('name', 'password')
|
25
39
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
it "should create an internal worker for each ip address" do
|
30
|
-
@instance.stub!(:server_ips).and_return(['1.1.1.1', '2.2.2.2'])
|
31
|
-
@instance.should_receive(:create_worker).with('username', 'password', '1.1.1.1').and_return('worker1')
|
32
|
-
@instance.should_receive(:create_worker).with('username', 'password', '2.2.2.2').and_return('worker2')
|
33
|
-
@instance.send(:workers, 'username', 'password').should == ['worker1', 'worker2']
|
40
|
+
|
41
|
+
it "should return the result of the validation" do
|
42
|
+
@instance.validate('name', 'password').should be_true
|
34
43
|
end
|
35
|
-
|
36
|
-
it "should
|
37
|
-
|
38
|
-
@
|
39
|
-
@
|
40
|
-
@instance.send(:create_worker, 'username', 'password', '1.1.1.1').should == @ldap
|
44
|
+
|
45
|
+
it "should use the second ip address when the first one times out" do
|
46
|
+
@worker.should_receive(:bind).ordered.and_raise(Timeout::Error)
|
47
|
+
@worker.should_receive(:bind).ordered.and_return(true)
|
48
|
+
@instance.validate('name', 'password').should be_true
|
41
49
|
end
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#Search' do
|
53
|
+
it "should check that username and password are not blank" do
|
54
|
+
Validator.should_receive(:blank?).and_return(true)
|
55
|
+
@instance.search(nil).should be_nil
|
46
56
|
end
|
47
|
-
|
48
|
-
it "should create a
|
49
|
-
|
50
|
-
|
51
|
-
@instance.
|
57
|
+
|
58
|
+
it "should create a new worker for the first ip address" do
|
59
|
+
@worker = mock(Worker, :search_directory => [], :bind => true)
|
60
|
+
Worker.should_receive(:new).and_return(@worker)
|
61
|
+
@instance.search('name')
|
52
62
|
end
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@ldap.should_receive(:search).with(
|
59
|
-
:base => @instance.treebase,
|
60
|
-
:filter => filter1 & filter2,
|
61
|
-
:attributes => Base.const_get('LDAP_ATTRS'),
|
62
|
-
:return_result => true
|
63
|
-
).and_return(['result'])
|
64
|
-
@instance.send(:search_active_directory, @ldap, 'search-string').should == ['result']
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should return a valid result when search cannot bind to the domain" do
|
68
|
-
@ldap.should_receive(:search).and_return(false)
|
69
|
-
@instance.send(:search_active_directory, @ldap, 'search-string').should == []
|
70
|
-
end
|
63
|
+
|
64
|
+
it "should return the result of the search" do
|
65
|
+
@worker = mock(Worker, :search_directory => ['result'], :bind => true)
|
66
|
+
Worker.stub!(:new).and_return(@worker)
|
67
|
+
@instance.search('name').should == ['result']
|
71
68
|
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should stop the validation cycle when the first result if received" do
|
81
|
-
ldap2 = mock(Net::LDAP)
|
82
|
-
ldap2.should_not_receive(:bind)
|
83
|
-
@ldap.should_receive(:bind).and_return(true)
|
84
|
-
@instance.stub!(:workers).and_return([@ldap, ldap2])
|
85
|
-
@instance.validate('username', 'password').should be_true
|
86
|
-
end
|
87
|
-
|
88
|
-
it "should return false when a timeout occurs" do
|
89
|
-
@instance.stub!(:workers).and_return([@ldap])
|
90
|
-
@ldap.should_receive(:bind).and_raise(Timeout::Error)
|
91
|
-
@instance.validate('username', 'password').should be_false
|
92
|
-
end
|
69
|
+
|
70
|
+
it "should use the second ip address when the first one times out" do
|
71
|
+
@worker.stub(:bind).and_return(true)
|
72
|
+
@worker.should_receive(:search_directory).ordered.and_raise(Timeout::Error)
|
73
|
+
@worker.should_receive(:search_directory).ordered.and_return(['result'])
|
74
|
+
@instance.search('name').should == ['result']
|
93
75
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
@ldap.should_receive(:search).and_return(false)
|
99
|
-
@instance.search('string').should == []
|
100
|
-
end
|
101
|
-
|
102
|
-
it "should sanitize the Net::LDAP search result into an array of generic structures" do
|
103
|
-
@instance.should_receive(:workers).and_return([])
|
104
|
-
@instance.should_receive(:create_result_collection).and_return([])
|
105
|
-
@instance.search('search-string').should == []
|
106
|
-
end
|
76
|
+
|
77
|
+
it "should throw an exception if the search user credentials are invalid" do
|
78
|
+
@worker.should_receive(:bind).and_return(false)
|
79
|
+
lambda{ @instance.search('name') }.should raise_error(InvalidCredentialsError, 'The user credentials provided are invalid')
|
107
80
|
end
|
108
81
|
end
|
109
|
-
|
82
|
+
|
110
83
|
end
|
111
84
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ElDap
|
4
|
+
describe Validator do
|
5
|
+
|
6
|
+
it "should return false when a string is not nil or empty" do
|
7
|
+
Validator.blank?('string').should be_false
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return false when all the strings are not nil or empty" do
|
11
|
+
Validator.blank?('string', 'thing').should be_false
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return true when a string is nil or empty" do
|
15
|
+
Validator.blank?('').should be_true
|
16
|
+
Validator.blank?(nil).should be_true
|
17
|
+
Validator.blank?(nil, '').should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return true when any string is nil or empty" do
|
21
|
+
Validator.blank?('', '').should be_true
|
22
|
+
Validator.blank?(nil, nil).should be_true
|
23
|
+
Validator.blank?('', 'string', nil).should be_true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return false when all strings are not nil or empty" do
|
27
|
+
Validator.blank?('string', 'string', 'string').should be_false
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ElDap
|
4
|
+
describe Worker do
|
5
|
+
before(:each) do
|
6
|
+
@instance = Worker.new(:ip_address => '1.1.1.1', :username => 'name', :password => 'password')
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should instantiate with the correct arguments" do
|
10
|
+
@instance.host.should == '1.1.1.1'
|
11
|
+
@instance.instance_variable_get(:@auth).should == {:method=>:simple, :username=>"name", :password=>"password"}
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should search the directory using the correct filters and parameters" do
|
15
|
+
filter1 = Net::LDAP::Filter.eq("objectcategory", "person")
|
16
|
+
filter2 = Net::LDAP::Filter.eq("cn", "*string*")
|
17
|
+
@instance.should_receive(:search).with(
|
18
|
+
:base => 'treebase',
|
19
|
+
:filter => filter1 & filter2,
|
20
|
+
:attributes => Worker.const_get('LDAP_ATTRS'),
|
21
|
+
:return_result => true
|
22
|
+
).and_return([])
|
23
|
+
@instance.search_directory('string', 'treebase').should == []
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should transform a search result into a collection of structs" do
|
27
|
+
@instance.stub!(:create_struct).and_return('struct')
|
28
|
+
@instance.send(:create_result_collection, ['result']).should == ['struct']
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should create a struct from a search result hash" do
|
32
|
+
search_result = {:cn => ['cn'], :mail => ['mail']}
|
33
|
+
struct = OpenStruct.new(:cn => 'cn',:mail => 'mail')
|
34
|
+
@instance.send(:create_struct, search_result).should == struct
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should complete gracefully if invalid credentials are used for search (search returns false)" do
|
38
|
+
@instance.should_receive(:search).and_return(false)
|
39
|
+
@instance.search_directory('string', 'treebase').should == []
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: el_dap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-04-
|
12
|
+
date: 2011-04-20 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: net-ldap
|
16
|
-
requirement: &
|
16
|
+
requirement: &83249460 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: 0.2.2
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *83249460
|
25
25
|
description: A simple search and authentication tool for Active Directory using LDAP.
|
26
26
|
email:
|
27
27
|
- ed.james.email@gmail.com
|
@@ -37,16 +37,22 @@ files:
|
|
37
37
|
- LICENSE
|
38
38
|
- README.rdoc
|
39
39
|
- Rakefile
|
40
|
+
- TODO.rdoc
|
40
41
|
- el_dap.gemspec
|
41
42
|
- lib/el_dap.rb
|
42
43
|
- lib/el_dap/.rvmrc
|
43
44
|
- lib/el_dap/api_methods.rb
|
44
45
|
- lib/el_dap/base.rb
|
45
46
|
- lib/el_dap/constants.rb
|
47
|
+
- lib/el_dap/exceptions.rb
|
48
|
+
- lib/el_dap/validator.rb
|
46
49
|
- lib/el_dap/version.rb
|
50
|
+
- lib/el_dap/worker.rb
|
47
51
|
- spec/el_dap/api_methods_spec.rb
|
48
52
|
- spec/el_dap/base_spec.rb
|
49
53
|
- spec/el_dap/constants_spec.rb
|
54
|
+
- spec/el_dap/validator_spec.rb
|
55
|
+
- spec/el_dap/worker_spec.rb
|
50
56
|
- spec/spec_helper.rb
|
51
57
|
homepage: https://github.com/edjames/el_dap
|
52
58
|
licenses: []
|