wobaduser 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b28543ca5d946a4e698ad38bd4b29c492a7ac1b8
4
+ data.tar.gz: adccab4655ae479b566d8fa8ff23adee912b5011
5
+ SHA512:
6
+ metadata.gz: f97d54312d98d9faa83f77079c4131f4c7aa76f7be52ebf2709d59aa4987b879599a8deff312d7fbbe60f512566e86ed5ea5b5a8fd2a2b3a71cefd0ff777aa0e
7
+ data.tar.gz: 2ffd81aa1db62405afd8eb596c06c27cb123c84ffc99fdc0b02081f6c05284a74c49dacea90492c69f0c42c91fcbcbd04bb46453be9aa7e99023f90415ed5426
@@ -0,0 +1,25 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .*.swp
24
+ utils/
25
+ .localenv
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wobaduser.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014-2018 Wolfgang Barth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,14 @@
1
+ wobaduser
2
+ =========
3
+
4
+ Lightweight Active Directory access.
5
+
6
+ If you are looking for a full featured solution to access and modify Active Directory, see [https://github.com/ajrkerr/active_directory](https://github.com/ajrkerr/active_directory)
7
+
8
+ Licence
9
+ -------
10
+
11
+ wobauth Copyright (C) 2014-2018 Wolfgang Barth
12
+
13
+ MIT license, see [LICENSE](LICENSE)
14
+
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,5 @@
1
+ class String
2
+ def as_utf8
3
+ self.force_encoding('UTF-8')
4
+ end
5
+ end
@@ -0,0 +1,19 @@
1
+ require "wobaduser/version"
2
+ require 'net/ldap'
3
+ require 'active_support/core_ext/module'
4
+ require 'active_support/core_ext/hash'
5
+ require 'string_addons'
6
+
7
+ module Wobaduser
8
+ autoload :LDAP, 'wobaduser/ldap'
9
+ autoload :Base, 'wobaduser/base'
10
+ autoload :User, 'wobaduser/user'
11
+
12
+ def self.setup
13
+ yield self
14
+ end
15
+
16
+ # timeout for ldap connections
17
+ mattr_accessor :timeout
18
+ @@timeout = 10
19
+ end
@@ -0,0 +1,174 @@
1
+ # additional copyright info:
2
+ # the metaprogramming for generate_single_value_readers and
3
+ # generate_multi_value_readers was published 2008 by Ernie Miller on
4
+ # http://erniemiller.org/2008/04/04/simplified-active-directory-authentication/
5
+ # with an excellent explanation.
6
+ #
7
+ require 'immutable-struct'
8
+
9
+ module Wobaduser
10
+ class Base
11
+ SearchResult = ImmutableStruct.new( :success?, :errors, :entries )
12
+
13
+ ###################################################################
14
+ # ATTR_SV is for single valued attributes only. result is a string.
15
+ # ATTR_MV is for multi valued attributes. result is an array.
16
+ # Concrete values should be set in subclasses. See Wobaduser::User
17
+ # for an example.
18
+ #
19
+ ATTR_SV={}
20
+ ATTR_MV={}
21
+ #
22
+ ###################################################################
23
+
24
+ attr_reader :errors, :entry
25
+
26
+ # Create an new Wobaduser object
27
+ # not to be intended to call directly, but possible. Better to use
28
+ # Wobaduser::User.new or Wobaduser::Group.new. There are to modes:
29
+ # 1) use Wobaduser::LDAP + LDAP-Filter
30
+ # 2) use a retrieved LDAP entry, i.e. used in Wobaduser::Base.search
31
+ #
32
+ # [+:entry+] ldap entry
33
+ # [+:ldap+] instance of Wobaduser::LDAP
34
+ # [+:filter+] ldap filter (as string, *not* as Net::LDAP::Filter)
35
+ # [+:ldap_options+] additional ldap options for search
36
+ #
37
+ # :entry and (:ldap, :filter) are mutually exclusive
38
+ #
39
+ def initialize(options = {})
40
+ options.symbolize_keys!
41
+ keys = options.keys
42
+ if keys.include?(:entry) && (keys & [:ldap, :filter, :ldap_options]).any?
43
+ raise ArgumentError, ":entry and one of (:ldap, :filter, :ldap_options) are mutually exclusive!"
44
+ end
45
+ reset_errors
46
+ get_ldap_entry(options)
47
+ unless entry.nil?
48
+ self.class.class_eval do
49
+ generate_single_value_readers
50
+ generate_multi_value_readers
51
+ end
52
+ end
53
+ end
54
+
55
+ def self.search(options = {})
56
+ search = search_ldap_entries(options)
57
+ if search.success?
58
+ entries = search.entries.map {|entry| self.new(entry: entry)}
59
+ result = SearchResult.new(success: true, errors: [], entries: entries)
60
+ else
61
+ result = SearchResult.new(success: false, errors: search.errors, entries: [])
62
+ end
63
+ end
64
+
65
+ def self.filter
66
+ Net::LDAP::Filter.present('objectClass')
67
+ end
68
+
69
+ def valid?
70
+ @entry.kind_of? Net::LDAP::Entry
71
+ end
72
+
73
+ protected
74
+
75
+ #
76
+ # method generator for single value attributes defined in ATTR_SV
77
+ #
78
+ def self.generate_single_value_readers
79
+ return if ATTR_SV.nil?
80
+ self::ATTR_SV.each_pair do |k, v|
81
+ val, block = Array(v)
82
+ define_method(k) do
83
+ if @entry.attribute_names.include?(val)
84
+ attribute = @entry.send(val)
85
+ attribute = attribute.first if attribute.is_a? Array
86
+ if block.is_a?(Proc)
87
+ final = block[attribute.to_s]
88
+ else
89
+ final = attribute.to_s
90
+ end
91
+ final = final.force_encoding('UTF-8') if final.is_a? String
92
+ return final
93
+ else
94
+ return ''
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ #
101
+ # method generator for multi value attributes defined in ATTR_MV
102
+ #
103
+ def self.generate_multi_value_readers
104
+ return if ATTR_SV.nil?
105
+ self::ATTR_MV.each_pair do |k, v|
106
+ val, block = Array(v)
107
+ define_method(k) do
108
+ if @entry.attribute_names.include?(val)
109
+ if block.is_a?(Proc)
110
+ finals = @entry.send(val).collect(&block)
111
+ else
112
+ finals = @entry.send(val)
113
+ end
114
+ finals = finals.map{|v| v.is_a?(String) ? v.to_s.force_encoding('UTF-8') : v } if finals.is_a? Array
115
+ return finals.compact
116
+ else
117
+ return []
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ def self.search_ldap_entries(options)
124
+ ldap = options.fetch(:ldap)
125
+ if ldap.nil?
126
+ raise "ldap connection not yet available"
127
+ end
128
+ filter = options.fetch(:filter)
129
+ ldap_options = options.fetch(:ldap_options, {}).
130
+ merge(filter: build_filter(filter))
131
+ entries = ldap.search(ldap_options)
132
+ if ldap.errors.any?
133
+ result = SearchResult.new(success: false, errors: ldap.errors, entries: [])
134
+ else
135
+ result = SearchResult.new(success: true, errors: [], entries: entries)
136
+ end
137
+ end
138
+
139
+ def self.build_filter(filter)
140
+ unless filter.kind_of? Net::LDAP::Filter
141
+ filter = Net::LDAP::Filter.construct(filter)
142
+ end
143
+ filter & self.filter
144
+ end
145
+
146
+ protected
147
+
148
+ def add_error(message)
149
+ @errors << message
150
+ end
151
+
152
+ def reset_errors
153
+ @errors = []
154
+ end
155
+
156
+ private
157
+
158
+ def get_ldap_entry(options)
159
+ if options.keys.include?(:entry)
160
+ @entry = options.fetch(:entry)
161
+ reset_errors
162
+ else
163
+ result = Wobaduser::Base.search_ldap_entries(options)
164
+ if result.success?
165
+ @entry = result.entries.first
166
+ else
167
+ add_error(result.errors.join(", "))
168
+ @entry = nil
169
+ end
170
+ end
171
+ end
172
+
173
+ end
174
+ end
@@ -0,0 +1,84 @@
1
+ require 'timeout'
2
+ require 'net/ldap'
3
+
4
+ module Wobaduser
5
+ class LDAP
6
+ attr_reader :ldap_options, :errors
7
+
8
+ # Wobaduser::LDAP.new({ldap_options: {}, bind: true})
9
+ #
10
+ # [+:ldap_options+] for possible ldap options see Net::LDAP::new
11
+ # [+:bind+] true: bind on initialize, false: bind on later operations
12
+ #
13
+ def initialize(options = {})
14
+ options.symbolize_keys!
15
+ reset_errors
16
+ @ldap_options = options.fetch(:ldap_options).symbolize_keys!
17
+ do_bind = options.fetch(:bind, true)
18
+ connection(ldap_options: @ldap_options, bind: do_bind)
19
+ end
20
+
21
+ # execute ldap search operation
22
+ #
23
+ # for possible ldap options see Net::LDAP#search
24
+ #
25
+ def search(options = {})
26
+ reset_errors
27
+ options.symbolize_keys!
28
+ begin
29
+ result = connection.search(options)
30
+ add_error(operation_error)
31
+ rescue => e
32
+ result = []
33
+ add_error(e.message)
34
+ end
35
+ result
36
+ end
37
+
38
+ # returns last ldap operation error, if any
39
+ #
40
+ def operation_error
41
+ (connection.get_operation_result.code == 0) ? nil : connection.get_operation_result
42
+ end
43
+
44
+ private
45
+ attr_reader :connection
46
+
47
+ def add_error(message)
48
+ @errors << message
49
+ end
50
+
51
+ def reset_errors
52
+ @errors = []
53
+ end
54
+
55
+ def connected?
56
+ !!@connected
57
+ end
58
+
59
+ def connection(options ={})
60
+ return @connection if @connected
61
+ @connected = false
62
+ reset_errors
63
+ options.symbolize_keys!
64
+ @connection ||= Net::LDAP.new(options.fetch(:ldap_options))
65
+ if options.fetch(:bind, true)
66
+ begin
67
+ Timeout::timeout(Wobaduser.timeout) {
68
+ if @connection.bind
69
+ @connected = true
70
+ else
71
+ add_error(operation_error)
72
+ end
73
+ }
74
+ rescue Timeout::Error => e
75
+ add_error("Timeout: could not bind to server within #{Wobaduser.timeout} seconds")
76
+ rescue Net::LDAP::Error => e
77
+ add_error(e.message)
78
+ end
79
+ end
80
+ @connection
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,72 @@
1
+ module Wobaduser
2
+ class User < Base
3
+
4
+ ########################################################################
5
+ # ATTR_SV is for single valued attributes only. Generated readers will
6
+ # convert the value to a string before returning or calling your Proc.
7
+
8
+ ATTR_SV = {
9
+ # method name ldap attribute
10
+ :username => :userprincipalname,
11
+ :userprincipalname => :userprincipalname,
12
+ :givenname => :givenname,
13
+ :sn => :sn,
14
+ :cn => :cn,
15
+ :dn => :dn,
16
+ :displayname => :displayname,
17
+ :mail => :mail,
18
+ :title => :title,
19
+ :telephonenumber => :telephonenumber,
20
+ :facsimiletelephonenumber => :facsimiletelephonenumber,
21
+ :mobile => :mobile,
22
+ :description => :description,
23
+ :department => :department,
24
+ :company => :company,
25
+ :postalcode => :postalcode,
26
+ :l => :l,
27
+ :streetaddress => :streetaddress,
28
+ :samaccountname => :samaccountname,
29
+ :primarygroupid => :primarygroupid,
30
+ :guid => [ :objectguid, Proc.new {|p| Base64.encode64(p).chomp } ],
31
+ :useraccountcontrol => :useraccountcontrol,
32
+ :is_valid? => [ :useraccountcontrol, Proc.new {|c| (c.to_i & 2) == 0 } ],
33
+ }
34
+
35
+ # ATTR_MV is for multi-valued attributes. Generated readers will always
36
+ # return an array.
37
+
38
+ ATTR_MV = {
39
+ # method name ldap attribute
40
+ :members => :member,
41
+ :objectclass => :objectclass,
42
+ :groups => [ :memberof,
43
+ # Get the simplified name of first-level groups.
44
+ # TODO: Handle escaped special characters
45
+ Proc.new {|g| g.sub(/.*?CN=(.*?),.*/, '\1')} ],
46
+ # :mailaliases => [ :proxyAddresses, Proc.new{|p| p.lowercase.gsub(/\Asmtp:/,'')}]
47
+ :mailaliases => [ :proxyaddresses, Proc.new {|p|
48
+ p = p.downcase
49
+ next unless p=~ /\Asmtp:/
50
+ p.gsub(/\Asmtp:/, '')
51
+ }],
52
+ }
53
+ #
54
+ ########################################################################
55
+
56
+ def filter(valid = false)
57
+ filter = Net::LDAP::Filter.eq('objectClass', 'user')
58
+ if valid
59
+ filter & ~(Net::LDAP::Filter.ex('UserAccountControl:1.2.840.113556.1.4.803', 2))
60
+ else
61
+ filter
62
+ end
63
+ end
64
+
65
+ def all_groups
66
+ filter = Net::LDAP::Filter.present("cn") & Net::LDAP::Filter.eq("objectClass", "group") &
67
+ Net::LDAP::Filter.ex("member:1.2.840.113556.1.4.1941", @entry.dn)
68
+ @ldap.search(filter: filter, attributes: ['cn']).map(&:cn).flatten.map(&:as_utf8)
69
+ end
70
+ end
71
+ end
72
+
@@ -0,0 +1,4 @@
1
+ module Wobaduser
2
+ VERSION = "1.0.0"
3
+ RELEASEDATE = "2018-07-21"
4
+ end
@@ -0,0 +1,15 @@
1
+ LDAP_HOST=
2
+ LDAP_PORT=
3
+ LDAP_BASE=
4
+ LDAP_USER=
5
+ LDAP_PASSWD=
6
+ # SN must match UPN2 & UPN3
7
+ # GIVENNAME must match UPN2 & UPN3
8
+ # EMAIL must match UPN2
9
+ USERPRINCIPALNAME=
10
+ USERPRINCIPALNAME2=
11
+ USERPRINCIPALNAME3=
12
+ LDAP_SEARCH_SN=
13
+ LDAP_SEARCH_GIVENNAME=
14
+ LDAP_SEARCH_EMAIL=
15
+
@@ -0,0 +1,78 @@
1
+ require 'timeout'
2
+ require 'spec_helper'
3
+
4
+ describe 'LdapSetup' do
5
+ context "with dummy options" do
6
+ let(:ldap_options) {{ "host" => '127.0.0.1', "base" => 'dc=example,dc=com', :port => 3268}}
7
+ let(:ldap) { Wobaduser::LDAP.new(ldap_options: ldap_options, bind: false) }
8
+ let(:filter) { Net::LDAP::Filter.eq("userprincipalname", "doesnotexist") }
9
+
10
+ it "set ldap options as symbols" do
11
+ expect(ldap.ldap_options).to be_a_kind_of Hash
12
+ opts = ldap.ldap_options
13
+ expect(opts).to include(:host, :base, :port)
14
+ expect(opts).not_to include("host", "base", "port")
15
+ end
16
+
17
+ it { expect(ldap).to respond_to(:search) }
18
+ it { expect(ldap).to respond_to(:errors) }
19
+ it { expect(ldap).not_to respond_to(:connection) }
20
+ it { expect(ldap).not_to respond_to(:connected?) }
21
+
22
+ it "ldap search doesn't raise an error" do
23
+ expect{
24
+ ldap.search(filter: filter)
25
+ }.not_to raise_error
26
+ end
27
+
28
+ it "ldap search delivers some errors" do
29
+ ldap.search(filter: filter)
30
+ expect(ldap.errors.any?).to be_truthy
31
+ end
32
+
33
+ it "connect to a existing host without ldap server should get connection refused" do
34
+ ldap = nil
35
+ Wobaduser.timeout = 2
36
+ expect {
37
+ ldap = Wobaduser::LDAP.new(ldap_options: ldap_options, bind: true)
38
+ }.not_to raise_error
39
+ expect(ldap.errors.any?).to be_truthy
40
+ expect(ldap.errors.join(" ")).to match /Connection refused/
41
+ end
42
+
43
+ it "connect to a nonexistent host should timeout" do
44
+ Wobaduser.timeout = 2
45
+ ldap_options['host'] = '1.2.3.4'
46
+ ldap = Wobaduser::LDAP.new(ldap_options: ldap_options, bind: true)
47
+ expect(ldap.errors.join(" ")).to match /Timeout: could not bind to server/
48
+ end
49
+ end
50
+
51
+ context "with real environment" do
52
+ let(:ldap_options) { {
53
+ host: ENV['LDAP_HOST'],
54
+ base: ENV['LDAP_BASE'],
55
+ port: ENV['LDAP_PORT'],
56
+ auth: {
57
+ method: :simple,
58
+ username: ENV['LDAP_USER'],
59
+ password: ENV['LDAP_PASSWD'],
60
+ }
61
+ } }
62
+ let(:ldap) { Wobaduser::LDAP.new(ldap_options: ldap_options, bind: true) }
63
+
64
+ it "Wobaduser::LDAP should delegate search" do
65
+ expect(ldap).to respond_to(:search)
66
+ end
67
+
68
+ it "search should return Net::LDAP::Entries" do
69
+ filter = Net::LDAP::Filter.eq("userprincipalname", ENV['USERPRINCIPALNAME'])
70
+ entry = ldap.search(filter: filter).first
71
+ expect(ldap.errors.any?).to be_falsey
72
+ expect(entry).to be_a_kind_of Net::LDAP::Entry
73
+ expect(entry).to respond_to(:userprincipalname)
74
+ expect(entry.userprincipalname).to include(ENV['USERPRINCIPALNAME'])
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,26 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup
3
+
4
+ require 'wobaduser'
5
+ require 'dotenv'
6
+
7
+ Dotenv.load( File.expand_path(__FILE__ + '/../.localenv'),
8
+ File.expand_path(__FILE__ + '/../.env'))
9
+
10
+ RSpec.configure do |config|
11
+ config.run_all_when_everything_filtered = true
12
+ # config.filter_run :focus
13
+ config.mock_framework = :rspec
14
+
15
+ config.around(:each) do |example|
16
+ Timeout::timeout(Wobaduser.timeout + 1) {
17
+ example.run
18
+ }
19
+ end
20
+
21
+ # Run specs in random order to surface order dependencies. If you find an
22
+ # order dependency and want to debug it, you can fix the order by providing
23
+ # the seed, which is printed after each run.
24
+ # --seed 1234
25
+ config.order = 'random'
26
+ end
@@ -0,0 +1,126 @@
1
+ require 'timeout'
2
+ require 'spec_helper'
3
+
4
+ describe 'User' do
5
+ context "with different options on #new" do
6
+ let(:ldap_options) {{"host" => '127.0.0.1', "base" => 'dc=example,dc=com', :port => 3268}}
7
+ let(:ldap) { Wobaduser::LDAP.new(ldap_options: ldap_options) }
8
+ let(:entry) { instance_double("Net::LDAP::Entry") }
9
+ let(:filter) { Net::LDAP::Filter.eq("userprincipalname", "doesnotexist") }
10
+
11
+ it ":entry does not raise an ArgumentError" do
12
+ expect {
13
+ Wobaduser::User.new(entry: entry)
14
+ }.not_to raise_error
15
+ end
16
+
17
+ it ":ldap + :filter does not raise an ArgumentError" do
18
+ expect {
19
+ Wobaduser::User.new(ldap: ldap, filter: filter)
20
+ }.not_to raise_error
21
+ end
22
+
23
+ [:ldap, :filter, :ldap_options].each do |option|
24
+ it ":entry and #{option} raises an ArgumentError" do
25
+ expect {
26
+ Wobaduser::User.new(entry: entry, option => nil)
27
+ }.to raise_error(ArgumentError)
28
+ end
29
+ end
30
+ end
31
+
32
+ context "with dummy options" do
33
+ let(:ldap_options) {{"host" => '127.0.0.1', "base" => 'dc=example,dc=com', :port => 3268}}
34
+ let(:ldap) { Wobaduser::LDAP.new(ldap_options: ldap_options, bind: false) }
35
+ let(:user) { Wobaduser::User.new(ldap: ldap, filter: filter) }
36
+ let(:filter) { Net::LDAP::Filter.eq("userprincipalname", "doesnotexist") }
37
+
38
+ it { expect(ldap.errors.any?).to be_falsey }
39
+
40
+ it { expect { user }.not_to raise_error }
41
+ it { expect(user.errors.any?).to be_truthy }
42
+ end
43
+
44
+ context "with real environment" do
45
+ let(:ldap_options) {{
46
+ host: ENV['LDAP_HOST'],
47
+ base: ENV['LDAP_BASE'],
48
+ port: ENV['LDAP_PORT'],
49
+ auth: {
50
+ method: :simple,
51
+ username: ENV['LDAP_USER'],
52
+ password: ENV['LDAP_PASSWD'],
53
+ }
54
+ }}
55
+ let(:ldap) {Wobaduser::LDAP.new(ldap_options: ldap_options, bind: true)}
56
+
57
+ context "and valid USERPRINCIPALNAME" do
58
+ let(:filter) {Net::LDAP::Filter.eq("userprincipalname", ENV['USERPRINCIPALNAME'])}
59
+
60
+ it "valid user should respond to various attribute methods" do
61
+ user = Wobaduser::User.new(ldap: ldap, filter: filter)
62
+ expect(user.valid?).to be_truthy
63
+ expect(user).to respond_to(:userprincipalname)
64
+ expect(user.userprincipalname).to include(ENV['USERPRINCIPALNAME'])
65
+ Wobaduser::User::ATTR_SV.each do |key,value|
66
+ expect(user.send(key)).to be_a_kind_of String unless key == :is_valid?
67
+ end
68
+ Wobaduser::User::ATTR_MV.each do |key,value|
69
+ expect(user.send(key)).to be_a_kind_of Array
70
+ end
71
+ end
72
+ end
73
+
74
+ context "and invalid USERPRINCIPALNAME" do
75
+ let(:filter) {Net::LDAP::Filter.eq("userprincipalname", "doesnotexist")}
76
+
77
+ it "valid user should respond to various attribute methods" do
78
+ user = Wobaduser::User.new(ldap: ldap, filter: filter)
79
+ expect(user.valid?).to be_falsey
80
+ end
81
+ end
82
+
83
+ describe "::search" do
84
+ let(:entries) { Wobaduser::User.search(ldap: ldap, filter: filter) }
85
+ let(:users) { entries.entries }
86
+
87
+ context "search for sn" do
88
+ let(:filter) {Net::LDAP::Filter.eq("sn", "#{ENV['LDAP_SEARCH_SN']}*")}
89
+
90
+ it { expect(entries.success?).to be_truthy }
91
+ it { expect(users).to be_a_kind_of Array }
92
+ it { expect(users.map {|u| u.userprincipalname}).to include(
93
+ ENV['USERPRINCIPALNAME3'], ENV['USERPRINCIPALNAME2']) }
94
+ end
95
+
96
+ context "search for givenname" do
97
+ let(:filter) {Net::LDAP::Filter.eq("givenname", ENV['LDAP_SEARCH_GIVENNAME'])}
98
+
99
+ it { expect(entries.success?).to be_truthy }
100
+ it { expect(users).to be_a_kind_of Array }
101
+ it { expect(users.map {|u| u.userprincipalname}).to include(
102
+ ENV['USERPRINCIPALNAME3'], ENV['USERPRINCIPALNAME2']) }
103
+ end
104
+
105
+ context "search for mail" do
106
+ let(:filter) {Net::LDAP::Filter.eq("mail", ENV['LDAP_SEARCH_EMAIL'])}
107
+
108
+ it { expect(entries.success?).to be_truthy }
109
+ it { expect(users).to be_a_kind_of Array }
110
+ it { expect(users.map {|u| u.userprincipalname}).to include(
111
+ ENV['USERPRINCIPALNAME2']) }
112
+ end
113
+
114
+ context "with invalid filter" do
115
+ let(:filter) {"bla"}
116
+ let(:entries) { Wobaduser::User.search(ldap: ldap, filter: filter) }
117
+
118
+ it "raises a FilterSyntaxInvalidError" do
119
+ expect {
120
+ entries.success?
121
+ }.to raise_error(Net::LDAP::FilterSyntaxInvalidError)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wobaduser/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wobaduser"
8
+ spec.version = Wobaduser::VERSION
9
+ spec.authors = ["Wolfgang Barth"]
10
+ spec.email = ["wob@swobspace.net"]
11
+ spec.summary = %q{Lightweight Active Directory LDAP read access}
12
+ spec.description = %q{Lightweight Active Directory LDAP read access}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "net-ldap"
22
+ spec.add_dependency "activesupport"
23
+ spec.add_dependency "immutable-struct"
24
+
25
+ spec.add_development_dependency "bundler", "> 1.6"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "dotenv"
29
+ end
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wobaduser
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Wolfgang Barth
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-07-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-ldap
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: immutable-struct
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: dotenv
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Lightweight Active Directory LDAP read access
112
+ email:
113
+ - wob@swobspace.net
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rspec"
120
+ - Gemfile
121
+ - LICENSE
122
+ - README.md
123
+ - Rakefile
124
+ - lib/string_addons.rb
125
+ - lib/wobaduser.rb
126
+ - lib/wobaduser/base.rb
127
+ - lib/wobaduser/ldap.rb
128
+ - lib/wobaduser/user.rb
129
+ - lib/wobaduser/version.rb
130
+ - spec/.env
131
+ - spec/ldap_setup_spec.rb
132
+ - spec/spec_helper.rb
133
+ - spec/user_spec.rb
134
+ - utils/test.rb
135
+ - utils/test2.rb
136
+ - wobaduser.gemspec
137
+ homepage: ''
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.6.14.1
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Lightweight Active Directory LDAP read access
161
+ test_files:
162
+ - spec/.env
163
+ - spec/ldap_setup_spec.rb
164
+ - spec/spec_helper.rb
165
+ - spec/user_spec.rb