omniauth-ldap 2.0.0 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +231 -0
- data/CITATION.cff +20 -0
- data/CODE_OF_CONDUCT.md +134 -0
- data/CONTRIBUTING.md +213 -0
- data/FUNDING.md +66 -0
- data/LICENSE.txt +24 -0
- data/README.md +1014 -67
- data/REEK +0 -0
- data/RUBOCOP.md +71 -0
- data/SECURITY.md +21 -0
- data/lib/omniauth/strategies/ldap.rb +213 -53
- data/lib/omniauth-ldap/adaptor.rb +241 -59
- data/lib/omniauth-ldap/version.rb +4 -1
- data/lib/omniauth-ldap.rb +6 -1
- data/sig/omniauth/ldap/adaptor.rbs +72 -0
- data/sig/omniauth/ldap/version.rbs +11 -0
- data/sig/omniauth/strategies/ldap.rbs +35 -0
- data/sig/omniauth-ldap.rbs +10 -0
- data/sig/rbs/net-ldap.rbs +35 -0
- data/sig/rbs/net-ntlm.rbs +17 -0
- data/sig/rbs/sasl.rbs +12 -0
- data.tar.gz.sig +0 -0
- metadata +332 -47
- metadata.gz.sig +0 -0
- data/.gitignore +0 -3
- data/.rspec +0 -1
- data/Gemfile +0 -11
- data/Guardfile +0 -11
- data/Rakefile +0 -9
- data/omniauth-ldap.gemspec +0 -26
- data/spec/omniauth/strategies/ldap_spec.rb +0 -200
- data/spec/omniauth-ldap/adaptor_spec.rb +0 -86
- data/spec/spec_helper.rb +0 -14
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# this code borrowed pieces from activeldap and net-ldap
|
|
4
|
+
|
|
5
|
+
# External Gems
|
|
6
|
+
require "net/ldap"
|
|
7
|
+
require "net/ntlm"
|
|
8
|
+
require "rack"
|
|
9
|
+
require "sasl"
|
|
2
10
|
|
|
3
|
-
require 'rack'
|
|
4
|
-
require 'net/ldap'
|
|
5
|
-
require 'net/ntlm'
|
|
6
|
-
require 'sasl'
|
|
7
|
-
require 'kconv'
|
|
8
11
|
module OmniAuth
|
|
9
12
|
module LDAP
|
|
10
13
|
class Adaptor
|
|
@@ -13,31 +16,68 @@ module OmniAuth
|
|
|
13
16
|
class AuthenticationError < StandardError; end
|
|
14
17
|
class ConnectionError < StandardError; end
|
|
15
18
|
|
|
16
|
-
VALID_ADAPTER_CONFIGURATION_KEYS = [
|
|
19
|
+
VALID_ADAPTER_CONFIGURATION_KEYS = [
|
|
20
|
+
:hosts,
|
|
21
|
+
:host,
|
|
22
|
+
:port,
|
|
23
|
+
:encryption,
|
|
24
|
+
:disable_verify_certificates,
|
|
25
|
+
:bind_dn,
|
|
26
|
+
:password,
|
|
27
|
+
:try_sasl,
|
|
28
|
+
:sasl_mechanisms,
|
|
29
|
+
:uid,
|
|
30
|
+
:base,
|
|
31
|
+
:allow_anonymous,
|
|
32
|
+
:filter,
|
|
33
|
+
:tls_options,
|
|
34
|
+
:password_policy,
|
|
35
|
+
# Timeouts
|
|
36
|
+
:connect_timeout,
|
|
37
|
+
:read_timeout,
|
|
38
|
+
|
|
39
|
+
# Deprecated
|
|
40
|
+
:method,
|
|
41
|
+
:ca_file,
|
|
42
|
+
:ssl_version,
|
|
43
|
+
]
|
|
17
44
|
|
|
18
45
|
# A list of needed keys. Possible alternatives are specified using sub-lists.
|
|
19
|
-
MUST_HAVE_KEYS = [
|
|
46
|
+
MUST_HAVE_KEYS = [
|
|
47
|
+
:base,
|
|
48
|
+
[:encryption, :method], # :method is deprecated
|
|
49
|
+
[:hosts, :host],
|
|
50
|
+
[:hosts, :port],
|
|
51
|
+
[:uid, :filter],
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
ENCRYPTION_METHOD = {
|
|
55
|
+
simple_tls: :simple_tls,
|
|
56
|
+
start_tls: :start_tls,
|
|
57
|
+
plain: nil,
|
|
20
58
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
:
|
|
24
|
-
:
|
|
59
|
+
# Deprecated. This mapping aimed to be user-friendly, but only caused
|
|
60
|
+
# confusion. Better to pass through the actual `Net::LDAP` encryption type.
|
|
61
|
+
ssl: :simple_tls,
|
|
62
|
+
tls: :start_tls,
|
|
25
63
|
}
|
|
26
64
|
|
|
27
65
|
attr_accessor :bind_dn, :password
|
|
28
|
-
attr_reader :connection, :uid, :base, :auth, :filter
|
|
29
|
-
|
|
66
|
+
attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
|
|
67
|
+
|
|
68
|
+
def self.validate(configuration = {})
|
|
30
69
|
message = []
|
|
31
70
|
MUST_HAVE_KEYS.each do |names|
|
|
32
71
|
names = [names].flatten
|
|
33
|
-
missing_keys = names.select{|name| configuration[name].nil?}
|
|
72
|
+
missing_keys = names.select { |name| configuration[name].nil? }
|
|
34
73
|
if missing_keys == names
|
|
35
|
-
message << names.join(
|
|
74
|
+
message << names.join(" or ")
|
|
36
75
|
end
|
|
37
76
|
end
|
|
38
|
-
raise ArgumentError.new(message.join(",") +" MUST be provided") unless message.empty?
|
|
77
|
+
raise ArgumentError.new(message.join(",") + " MUST be provided") unless message.empty?
|
|
39
78
|
end
|
|
40
|
-
|
|
79
|
+
|
|
80
|
+
def initialize(configuration = {})
|
|
41
81
|
Adaptor.validate(configuration)
|
|
42
82
|
@configuration = configuration.dup
|
|
43
83
|
@configuration[:allow_anonymous] ||= false
|
|
@@ -45,23 +85,44 @@ module OmniAuth
|
|
|
45
85
|
VALID_ADAPTER_CONFIGURATION_KEYS.each do |name|
|
|
46
86
|
instance_variable_set("@#{name}", @configuration[name])
|
|
47
87
|
end
|
|
48
|
-
method = ensure_method(@method)
|
|
49
88
|
config = {
|
|
50
|
-
:
|
|
51
|
-
:
|
|
52
|
-
:
|
|
89
|
+
base: @base,
|
|
90
|
+
hosts: @hosts,
|
|
91
|
+
host: @host,
|
|
92
|
+
port: @port,
|
|
93
|
+
encryption: encryption_options,
|
|
53
94
|
}
|
|
54
|
-
|
|
55
|
-
|
|
95
|
+
# Remove passing timeouts here to avoid issues on older net-ldap versions.
|
|
96
|
+
# We'll set them after initialization if the connection responds to writers.
|
|
97
|
+
@bind_method = if @try_sasl
|
|
98
|
+
:sasl
|
|
99
|
+
else
|
|
100
|
+
((@allow_anonymous || !@bind_dn || !@password) ? :anonymous : :simple)
|
|
101
|
+
end
|
|
56
102
|
|
|
57
|
-
@auth = sasl_auths({:
|
|
58
|
-
@auth ||= {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
103
|
+
@auth = sasl_auths({username: @bind_dn, password: @password}).first if @bind_method == :sasl
|
|
104
|
+
@auth ||= {
|
|
105
|
+
method: @bind_method,
|
|
106
|
+
username: @bind_dn,
|
|
107
|
+
password: @password,
|
|
108
|
+
}
|
|
62
109
|
config[:auth] = @auth
|
|
63
110
|
@connection = Net::LDAP.new(config)
|
|
64
|
-
|
|
111
|
+
# Apply optional timeout settings if supported by the installed net-ldap version
|
|
112
|
+
if !@connect_timeout.nil?
|
|
113
|
+
if @connection.respond_to?(:connect_timeout=)
|
|
114
|
+
@connection.connect_timeout = @connect_timeout
|
|
115
|
+
else
|
|
116
|
+
@connection.instance_variable_set(:@connect_timeout, @connect_timeout)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
if !@read_timeout.nil?
|
|
120
|
+
if @connection.respond_to?(:read_timeout=)
|
|
121
|
+
@connection.read_timeout = @read_timeout
|
|
122
|
+
else
|
|
123
|
+
@connection.instance_variable_set(:@read_timeout, @read_timeout)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
65
126
|
end
|
|
66
127
|
|
|
67
128
|
#:base => "dc=yourcompany, dc=com",
|
|
@@ -69,17 +130,47 @@ module OmniAuth
|
|
|
69
130
|
# :password => psw
|
|
70
131
|
def bind_as(args = {})
|
|
71
132
|
result = false
|
|
133
|
+
@last_operation_result = nil
|
|
134
|
+
@last_password_policy_response = nil
|
|
72
135
|
@connection.open do |me|
|
|
73
|
-
rs = me.search
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
136
|
+
rs = me.search(args)
|
|
137
|
+
raise ConnectionError.new("LDAP search operation failed") unless rs
|
|
138
|
+
|
|
139
|
+
if rs && rs.first
|
|
140
|
+
dn = rs.first.dn
|
|
141
|
+
if dn
|
|
142
|
+
password = args[:password]
|
|
143
|
+
password = password.call if password.respond_to?(:call)
|
|
144
|
+
|
|
145
|
+
bind_args = if @bind_method == :sasl
|
|
146
|
+
sasl_auths({username: dn, password: password}).first
|
|
147
|
+
else
|
|
148
|
+
{
|
|
149
|
+
method: :simple,
|
|
150
|
+
username: dn,
|
|
151
|
+
password: password,
|
|
152
|
+
}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Optionally request LDAP Password Policy control (RFC Draft - de facto standard)
|
|
156
|
+
if @password_policy
|
|
157
|
+
# Always request by OID using a simple hash; avoids depending on gem-specific control classes
|
|
158
|
+
control = {oid: "1.3.6.1.4.1.42.2.27.8.5.1", criticality: true, value: nil}
|
|
159
|
+
if bind_args.is_a?(Hash)
|
|
160
|
+
bind_args = bind_args.merge({controls: [control]})
|
|
161
|
+
else
|
|
162
|
+
# Some Net::LDAP versions allow passing a block for SASL only; ensure we still can add controls if hash
|
|
163
|
+
# When not a Hash, we can't merge; rely on server default behavior.
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
begin
|
|
168
|
+
success = bind_args ? me.bind(bind_args) : me.bind
|
|
169
|
+
ensure
|
|
170
|
+
capture_password_policy(me)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
result = rs.first if success
|
|
83
174
|
end
|
|
84
175
|
end
|
|
85
176
|
end
|
|
@@ -87,29 +178,64 @@ module OmniAuth
|
|
|
87
178
|
end
|
|
88
179
|
|
|
89
180
|
private
|
|
90
|
-
def ensure_method(method)
|
|
91
|
-
method ||= "plain"
|
|
92
|
-
normalized_method = method.to_s.downcase.to_sym
|
|
93
|
-
return METHOD[normalized_method] if METHOD.has_key?(normalized_method)
|
|
94
181
|
|
|
95
|
-
|
|
182
|
+
def encryption_options
|
|
183
|
+
translated_method = translate_method
|
|
184
|
+
return unless translated_method
|
|
185
|
+
|
|
186
|
+
{
|
|
187
|
+
method: translated_method,
|
|
188
|
+
tls_options: tls_options(translated_method),
|
|
189
|
+
}
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def translate_method
|
|
193
|
+
method = @encryption || @method
|
|
194
|
+
method ||= "plain"
|
|
195
|
+
normalized_method = method.to_s.downcase.to_sym
|
|
196
|
+
|
|
197
|
+
unless ENCRYPTION_METHOD.has_key?(normalized_method)
|
|
198
|
+
available_methods = ENCRYPTION_METHOD.keys.collect { |m| m.inspect }.join(", ")
|
|
96
199
|
format = "%s is not one of the available connect methods: %s"
|
|
97
200
|
raise ConfigurationError, format % [method.inspect, available_methods]
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
ENCRYPTION_METHOD[normalized_method]
|
|
98
204
|
end
|
|
99
205
|
|
|
100
|
-
def
|
|
206
|
+
def tls_options(translated_method)
|
|
207
|
+
return {} if translated_method.nil? # (plain)
|
|
208
|
+
|
|
209
|
+
options = default_options
|
|
210
|
+
|
|
211
|
+
if @tls_options
|
|
212
|
+
# Prevent blank config values from overwriting SSL defaults
|
|
213
|
+
configured_options = sanitize_hash_values(@tls_options)
|
|
214
|
+
configured_options = symbolize_hash_keys(configured_options)
|
|
215
|
+
|
|
216
|
+
options.merge!(configured_options)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Retain backward compatibility until deprecated configs are removed.
|
|
220
|
+
options[:ca_file] = @ca_file if @ca_file
|
|
221
|
+
options[:ssl_version] = @ssl_version if @ssl_version
|
|
222
|
+
|
|
223
|
+
options
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def sasl_auths(options = {})
|
|
101
227
|
auths = []
|
|
102
228
|
sasl_mechanisms = options[:sasl_mechanisms] || @sasl_mechanisms
|
|
103
229
|
sasl_mechanisms.each do |mechanism|
|
|
104
|
-
normalized_mechanism = mechanism.downcase.
|
|
230
|
+
normalized_mechanism = mechanism.downcase.tr("-", "_")
|
|
105
231
|
sasl_bind_setup = "sasl_bind_setup_#{normalized_mechanism}"
|
|
106
232
|
next unless respond_to?(sasl_bind_setup, true)
|
|
107
233
|
initial_credential, challenge_response = send(sasl_bind_setup, options)
|
|
108
234
|
auths << {
|
|
109
|
-
:
|
|
110
|
-
:
|
|
111
|
-
:
|
|
112
|
-
:
|
|
235
|
+
method: :sasl,
|
|
236
|
+
initial_credential: initial_credential,
|
|
237
|
+
mechanism: mechanism,
|
|
238
|
+
challenge_response: challenge_response,
|
|
113
239
|
}
|
|
114
240
|
end
|
|
115
241
|
auths
|
|
@@ -118,8 +244,8 @@ module OmniAuth
|
|
|
118
244
|
def sasl_bind_setup_digest_md5(options)
|
|
119
245
|
bind_dn = options[:username]
|
|
120
246
|
initial_credential = ""
|
|
121
|
-
challenge_response =
|
|
122
|
-
pref = SASL::Preferences.new
|
|
247
|
+
challenge_response = proc do |cred|
|
|
248
|
+
pref = SASL::Preferences.new(digest_uri: "ldap/#{@host}", username: bind_dn, has_password?: true, password: options[:password])
|
|
123
249
|
sasl = SASL.new("DIGEST-MD5", pref)
|
|
124
250
|
response = sasl.receive("challenge", cred)
|
|
125
251
|
response[1]
|
|
@@ -130,18 +256,74 @@ module OmniAuth
|
|
|
130
256
|
def sasl_bind_setup_gss_spnego(options)
|
|
131
257
|
bind_dn = options[:username]
|
|
132
258
|
psw = options[:password]
|
|
133
|
-
raise LdapError.new(
|
|
259
|
+
raise LdapError.new("invalid binding information") unless bind_dn && psw
|
|
134
260
|
|
|
135
|
-
nego = proc {|challenge|
|
|
136
|
-
t2_msg = Net::NTLM::Message.parse(
|
|
137
|
-
bind_dn, domain = bind_dn.split(
|
|
138
|
-
t2_msg.target_name = Net::NTLM
|
|
139
|
-
t3_msg = t2_msg.response(
|
|
261
|
+
nego = proc { |challenge|
|
|
262
|
+
t2_msg = Net::NTLM::Message.parse(challenge)
|
|
263
|
+
bind_dn, domain = bind_dn.split("\\").reverse
|
|
264
|
+
t2_msg.target_name = Net::NTLM.encode_utf16le(domain) if domain
|
|
265
|
+
t3_msg = t2_msg.response({user: bind_dn, password: psw}, {ntlmv2: true})
|
|
140
266
|
t3_msg.serialize
|
|
141
267
|
}
|
|
142
268
|
[Net::NTLM::Message::Type1.new.serialize, nego]
|
|
143
269
|
end
|
|
144
270
|
|
|
271
|
+
private
|
|
272
|
+
|
|
273
|
+
def default_options
|
|
274
|
+
if @disable_verify_certificates
|
|
275
|
+
# It is important to explicitly set verify_mode for two reasons:
|
|
276
|
+
# 1. The behavior of OpenSSL is undefined when verify_mode is not set.
|
|
277
|
+
# 2. The net-ldap gem implementation verifies the certificate hostname
|
|
278
|
+
# unless verify_mode is set to VERIFY_NONE.
|
|
279
|
+
{verify_mode: OpenSSL::SSL::VERIFY_NONE}
|
|
280
|
+
else
|
|
281
|
+
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.dup
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Removes keys that have blank values
|
|
286
|
+
#
|
|
287
|
+
# This gem may not always be in the context of Rails so we
|
|
288
|
+
# do this rather than `.blank?`.
|
|
289
|
+
def sanitize_hash_values(hash)
|
|
290
|
+
hash.delete_if do |_, value|
|
|
291
|
+
value.nil? ||
|
|
292
|
+
(value.is_a?(String) && value !~ /\S/)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def symbolize_hash_keys(hash)
|
|
297
|
+
hash.each_with_object({}) do |(key, value), result|
|
|
298
|
+
result[key.to_sym] = value
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Capture the operation result and extract any Password Policy response control if present.
|
|
303
|
+
def capture_password_policy(conn)
|
|
304
|
+
return unless @password_policy
|
|
305
|
+
return unless conn.respond_to?(:get_operation_result)
|
|
306
|
+
|
|
307
|
+
begin
|
|
308
|
+
@last_operation_result = conn.get_operation_result
|
|
309
|
+
controls = if @last_operation_result && @last_operation_result.respond_to?(:controls)
|
|
310
|
+
@last_operation_result.controls || []
|
|
311
|
+
else
|
|
312
|
+
[]
|
|
313
|
+
end
|
|
314
|
+
if controls.any?
|
|
315
|
+
# Find Password Policy response control by OID
|
|
316
|
+
ppolicy_oid = "1.3.6.1.4.1.42.2.27.8.5.1"
|
|
317
|
+
ctrl = controls.find do |c|
|
|
318
|
+
(c.respond_to?(:oid) && c.oid == ppolicy_oid) || (c.is_a?(Hash) && c[:oid] == ppolicy_oid)
|
|
319
|
+
end
|
|
320
|
+
@last_password_policy_response = ctrl if ctrl
|
|
321
|
+
end
|
|
322
|
+
rescue StandardError
|
|
323
|
+
# Swallow errors to keep authentication flow unaffected when server or gem doesn't support controls
|
|
324
|
+
@last_password_policy_response = nil
|
|
325
|
+
end
|
|
326
|
+
end
|
|
145
327
|
end
|
|
146
328
|
end
|
|
147
329
|
end
|
data/lib/omniauth-ldap.rb
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module OmniAuth
|
|
2
|
+
module LDAP
|
|
3
|
+
class Adaptor
|
|
4
|
+
class LdapError < ::StandardError
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class ConfigurationError < ::StandardError
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class AuthenticationError < ::StandardError
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class ConnectionError < ::StandardError
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
VALID_ADAPTER_CONFIGURATION_KEYS: Array[Symbol]
|
|
17
|
+
MUST_HAVE_KEYS: Array[untyped]
|
|
18
|
+
ENCRYPTION_METHOD: Hash[Symbol, Symbol?]
|
|
19
|
+
|
|
20
|
+
attr_accessor bind_dn: String?
|
|
21
|
+
attr_accessor password: String?
|
|
22
|
+
|
|
23
|
+
# Net::LDAP is provided by the net-ldap gem; we reference it here for clarity.
|
|
24
|
+
attr_reader connection: Net::LDAP
|
|
25
|
+
attr_reader uid: String?
|
|
26
|
+
attr_reader base: String?
|
|
27
|
+
# auth is the hash passed to Net::LDAP#auth or similar
|
|
28
|
+
attr_reader auth: Hash[Symbol, untyped]
|
|
29
|
+
# filter is an LDAP filter string when configured
|
|
30
|
+
attr_reader filter: String?
|
|
31
|
+
# optional: request password policy control and capture response
|
|
32
|
+
attr_reader password_policy: bool?
|
|
33
|
+
attr_reader last_operation_result: untyped
|
|
34
|
+
attr_reader last_password_policy_response: untyped
|
|
35
|
+
|
|
36
|
+
# Validate that required keys exist in the configuration
|
|
37
|
+
def self.validate: (?Hash[Symbol, untyped]) -> void
|
|
38
|
+
def initialize: (?Hash[Symbol, untyped]) -> void
|
|
39
|
+
|
|
40
|
+
# Perform a search and optionally bind; returns the matched entry or false
|
|
41
|
+
def bind_as: (?Hash[Symbol, untyped]) -> (Net::LDAP::Entry? | false)
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# Returns encryption settings hash or nil
|
|
46
|
+
def encryption_options: () -> Hash[Symbol, untyped]?
|
|
47
|
+
# Translate configured method/encryption into Net::LDAP symbol
|
|
48
|
+
def translate_method: () -> Symbol?
|
|
49
|
+
# Returns a Net::LDAP encryption default options hash
|
|
50
|
+
def default_options: () -> Hash[Symbol, untyped]
|
|
51
|
+
# Sanitize provided TLS options
|
|
52
|
+
def sanitize_hash_values: (Hash[untyped, untyped]) -> Hash[untyped, untyped]
|
|
53
|
+
# Symbolize option keys
|
|
54
|
+
def symbolize_hash_keys: (Hash[untyped, untyped]) -> Hash[Symbol, untyped]
|
|
55
|
+
# Capture password policy control from last operation
|
|
56
|
+
def capture_password_policy: (Net::LDAP) -> void
|
|
57
|
+
|
|
58
|
+
# Returns an array of SASL auth hashes
|
|
59
|
+
def sasl_auths: (?Hash[Symbol, untyped]) -> Array[Hash[Symbol, untyped]]
|
|
60
|
+
|
|
61
|
+
# Returns initial credential and a proc that accepts a challenge and returns the response
|
|
62
|
+
def sasl_bind_setup_digest_md5: (?Hash[Symbol, untyped]) -> Array[untyped]
|
|
63
|
+
def sasl_bind_setup_gss_spnego: (?Hash[Symbol, untyped]) -> Array[untyped]
|
|
64
|
+
|
|
65
|
+
@try_sasl: bool?
|
|
66
|
+
@allow_anonymous: bool?
|
|
67
|
+
@tls_options: Hash[untyped, untyped]?
|
|
68
|
+
@sasl_mechanisms: Array[String]?
|
|
69
|
+
@disable_verify_certificates: bool?
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module OmniAuth
|
|
2
|
+
module Strategies
|
|
3
|
+
class LDAP
|
|
4
|
+
OMNIAUTH_GTE_V2: bool
|
|
5
|
+
|
|
6
|
+
# The request_phase either returns a Rack-compatible response or the form response.
|
|
7
|
+
def request_phase: () -> (Rack::Response | Array[untyped] | String)
|
|
8
|
+
|
|
9
|
+
# The callback_phase may call super (untyped) or return a failure symbol
|
|
10
|
+
def callback_phase: () -> untyped
|
|
11
|
+
|
|
12
|
+
# Accepts an adaptor and returns a Net::LDAP::Filter or similar
|
|
13
|
+
# Optional second argument allows overriding the username (used for header-based SSO)
|
|
14
|
+
def filter: (OmniAuth::LDAP::Adaptor) -> Net::LDAP::Filter
|
|
15
|
+
| (OmniAuth::LDAP::Adaptor, String?) -> Net::LDAP::Filter
|
|
16
|
+
|
|
17
|
+
# Map a user object (Net::LDAP::Entry-like) into a Hash for the auth info
|
|
18
|
+
def self.map_user: (Hash[String, untyped], untyped) -> Hash[String, untyped]
|
|
19
|
+
|
|
20
|
+
def missing_credentials?: () -> bool
|
|
21
|
+
|
|
22
|
+
# Extract username from a trusted header when enabled
|
|
23
|
+
def header_username: () -> (String | nil)
|
|
24
|
+
|
|
25
|
+
# Perform a directory lookup for a given username; returns an Entry or nil
|
|
26
|
+
def directory_lookup: (OmniAuth::LDAP::Adaptor, String) -> untyped
|
|
27
|
+
|
|
28
|
+
def uid: () { () -> String } -> void
|
|
29
|
+
|
|
30
|
+
def info: () { () -> Hash[untyped, untyped] } -> void
|
|
31
|
+
|
|
32
|
+
def extra: () { () -> Hash[Symbol, untyped] } -> void
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Top-level signature file for the gem. Detailed signatures live in the files below:
|
|
2
|
+
# - sig/omniauth/ldap/version.rbs
|
|
3
|
+
# - sig/omniauth/ldap/adaptor.rbs
|
|
4
|
+
# - sig/omniauth/strategies/ldap.rbs
|
|
5
|
+
# This file is intentionally minimal to avoid duplicating declarations.
|
|
6
|
+
|
|
7
|
+
module OmniAuth
|
|
8
|
+
module LDAP
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Minimal stubs for net-ldap types used by the gem
|
|
2
|
+
module Net
|
|
3
|
+
class LDAP
|
|
4
|
+
def initialize: (Hash[Symbol, untyped]) -> void
|
|
5
|
+
def open: () { (self) -> untyped } -> untyped
|
|
6
|
+
def search: (?Hash[Symbol, untyped]) -> Array[Net::LDAP::Entry]
|
|
7
|
+
def bind: (?Hash[Symbol, untyped]) -> bool
|
|
8
|
+
def get_operation_result: () -> Net::LDAP::PDU
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class LDAP::Entry
|
|
12
|
+
def dn: () -> String
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class LDAP::Filter
|
|
16
|
+
def self.construct: (String) -> Net::LDAP::Filter
|
|
17
|
+
def self.eq: (String, String) -> Net::LDAP::Filter
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class LDAP::Control
|
|
21
|
+
def initialize: (String, bool, untyped) -> void
|
|
22
|
+
def oid: () -> String
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module LDAP::Controls
|
|
26
|
+
class PasswordPolicy
|
|
27
|
+
def initialize: () -> void
|
|
28
|
+
def oid: () -> String
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class LDAP::PDU
|
|
33
|
+
def controls: () -> Array[untyped]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Minimal stubs for net-ntlm types used by the gem
|
|
2
|
+
module Net
|
|
3
|
+
module NTLM
|
|
4
|
+
class Message
|
|
5
|
+
def self.parse: (untyped) -> Net::NTLM::Message
|
|
6
|
+
def response: (?Hash[Symbol, untyped], ?Hash[Symbol, untyped]) -> Net::NTLM::Message
|
|
7
|
+
# writer used by adaptor to set target name when a domain is present
|
|
8
|
+
def target_name=: (String) -> String
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Message::Type1
|
|
12
|
+
def serialize: () -> String
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.encode_utf16le: (String) -> String
|
|
16
|
+
end
|
|
17
|
+
end
|
data/sig/rbs/sasl.rbs
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Minimal stubs for SASL bindings used in tests
|
|
2
|
+
module SASL
|
|
3
|
+
class Preferences
|
|
4
|
+
def initialize: (?Hash[Symbol, untyped]) -> void
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class SASL
|
|
8
|
+
def initialize: (String, SASL::Preferences) -> void
|
|
9
|
+
def receive: (String, untyped) -> [untyped, untyped]
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
data.tar.gz.sig
ADDED
|
Binary file
|