omniauth-ldap 2.3.1 โ 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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +30 -1
- data/LICENSE.txt +1 -0
- data/README.md +210 -9
- data/lib/omniauth/strategies/ldap.rb +73 -19
- data/lib/omniauth-ldap/adaptor.rb +87 -13
- data/lib/omniauth-ldap/version.rb +1 -1
- data/sig/omniauth/ldap/adaptor.rbs +24 -6
- data/sig/omniauth/strategies/ldap.rbs +6 -3
- data/sig/omniauth-ldap.rbs +5 -0
- data/sig/rbs/net-ldap.rbs +17 -1
- data/sig/rbs/net-ntlm.rbs +2 -1
- data.tar.gz.sig +0 -0
- metadata +6 -6
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 64fced98d7ab577e6c9abc446ace5678b829670e9d241f0a759c61efc47ecf5e
|
|
4
|
+
data.tar.gz: 7fda93687c96509833b9d72f277995f53eb2368ebe44740180ceadd3afac6ebe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8750eeed19ed13d89d041b14123b68cc459e7f5595d04d6d0fe67227c06c312f7952264f6fdd19a8f57957ce98c9ea3620d125fd01c445446c8848400a668e12
|
|
7
|
+
data.tar.gz: ed9dc416b2eba5c6e9d9cc5e889f50bd70347ff4a6ce9261cb8703e77d010c7834a5a566ef8ed7f93f5fbaf4baba0afa9965191decebdf84ed8ffd8b79590a8d
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -32,6 +32,33 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
32
32
|
|
|
33
33
|
### Security
|
|
34
34
|
|
|
35
|
+
## [2.3.2] - 2025-11-06
|
|
36
|
+
|
|
37
|
+
- TAG: [v2.3.2][2.3.2t]
|
|
38
|
+
- COVERAGE: 97.64% -- 290/297 lines in 4 files
|
|
39
|
+
- BRANCH COVERAGE: 79.69% -- 102/128 branches in 4 files
|
|
40
|
+
- 44.12% documented
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- Support for SCRIPT_NAME for proper URL generation
|
|
45
|
+
- behind certain proxies/load balancers, or
|
|
46
|
+
- under a subdirectory
|
|
47
|
+
- Password Policy for LDAP Directories
|
|
48
|
+
- password_policy: true|false (default: false)
|
|
49
|
+
- on authentication failure, if the server returns password policy controls, the info will be included in the failure message
|
|
50
|
+
- https://datatracker.ietf.org/doc/html/draft-behera-ldap-password-policy-11
|
|
51
|
+
- Support for JSON bodies
|
|
52
|
+
- Support custom LDAP attributes mapping
|
|
53
|
+
- Raise a distinct error when LDAP server is unreachable
|
|
54
|
+
- Previously raised an invalid credentials authentication failure error, which is technically incorrect
|
|
55
|
+
- Documentation of TLS verification options
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- Make support for OmniAuth v1.2+ explicit
|
|
60
|
+
- Versions < 1.2 do not support SCRIPT_NAME properly, and may cause other issues
|
|
61
|
+
|
|
35
62
|
## [2.3.1] - 2025-11-05
|
|
36
63
|
|
|
37
64
|
- TAG: [v2.3.1][2.3.1t]
|
|
@@ -197,6 +224,8 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
197
224
|
[1.0.0]: https://github.com/omniauth/omniauth-ldap/compare/5656da80d4193e0d0584f44bac493a87695e580f...v1.0.0
|
|
198
225
|
[1.0.0t]: https://github.com/omniauth/omniauth-ldap/releases/tag/v1.0.0
|
|
199
226
|
|
|
200
|
-
[Unreleased]: https://github.com/omniauth/omniauth-ldap/compare/v2.3.
|
|
227
|
+
[Unreleased]: https://github.com/omniauth/omniauth-ldap/compare/v2.3.2...HEAD
|
|
228
|
+
[2.3.2]: https://github.com/omniauth/omniauth-ldap/compare/v2.3.1...v2.3.2
|
|
229
|
+
[2.3.2t]: https://github.com/omniauth/omniauth-ldap/releases/tag/v2.3.2
|
|
201
230
|
[2.3.1]: https://github.com/omniauth/omniauth-ldap/compare/v2.0.0...v2.3.1
|
|
202
231
|
[2.3.1t]: https://github.com/omniauth/omniauth-ldap/releases/tag/v2.3.1
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
# ๐ OmniAuth LDAP
|
|
40
40
|
|
|
41
|
-
[![Version][๐ฝversioni]][๐ฝversion] [![GitHub tag (latest SemVer)][โณ๏ธtag-img]][โณ๏ธtag] [![License: MIT][๐license-img]][๐license-ref] [![Downloads Rank][๐ฝdl-ranki]][๐ฝdl-rank] [![Open Source Helpers][๐ฝoss-helpi]][๐ฝoss-help] [![CodeCov Test Coverage][๐codecovi]][๐codecov] [![Coveralls Test Coverage][๐coveralls-img]][๐coveralls] [![
|
|
41
|
+
[![Version][๐ฝversioni]][๐ฝversion] [![GitHub tag (latest SemVer)][โณ๏ธtag-img]][โณ๏ธtag] [![License: MIT][๐license-img]][๐license-ref] [![Downloads Rank][๐ฝdl-ranki]][๐ฝdl-rank] [![Open Source Helpers][๐ฝoss-helpi]][๐ฝoss-help] [![CodeCov Test Coverage][๐codecovi]][๐codecov] [![Coveralls Test Coverage][๐coveralls-img]][๐coveralls] [![CI Heads][๐3-hd-wfi]][๐3-hd-wf] [![CI Runtime Dependencies @ HEAD][๐12-crh-wfi]][๐12-crh-wf] [![CI Current][๐11-c-wfi]][๐11-c-wf] [![CI Truffle Ruby][๐9-t-wfi]][๐9-t-wf] [![CI JRuby][๐10-j-wfi]][๐10-j-wf] [![Deps Locked][๐13-๐๏ธ-wfi]][๐13-๐๏ธ-wf] [![Deps Unlocked][๐14-๐๏ธ-wfi]][๐14-๐๏ธ-wf] [![CI Supported][๐6-s-wfi]][๐6-s-wf] [![CI Legacy][๐4-lg-wfi]][๐4-lg-wf] [![CI Unsupported][๐7-us-wfi]][๐7-us-wf] [![CI Ancient][๐1-an-wfi]][๐1-an-wf] [![CI Test Coverage][๐2-cov-wfi]][๐2-cov-wf] [![CI Style][๐5-st-wfi]][๐5-st-wf] [![CodeQL][๐codeQL-img]][๐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][๐15-๐ชช-wfi]][๐15-๐ชช-wf]
|
|
42
42
|
|
|
43
43
|
`if ci_badges.map(&:color).detect { it != "green"}` โ๏ธ [let me know][๐ผ๏ธgaltzo-discord], as I may have missed the [discord notification][๐ผ๏ธgaltzo-discord].
|
|
44
44
|
|
|
@@ -63,9 +63,17 @@ use OmniAuth::Strategies::LDAP,
|
|
|
63
63
|
name_proc: proc { |name| name.gsub(/@.*$/, "") },
|
|
64
64
|
bind_dn: "default_bind_dn",
|
|
65
65
|
password: "password",
|
|
66
|
+
# Optional timeouts (seconds)
|
|
67
|
+
connect_timeout: 3,
|
|
68
|
+
read_timeout: 7,
|
|
66
69
|
tls_options: {
|
|
67
70
|
ssl_version: "TLSv1_2",
|
|
68
71
|
ciphers: ["AES-128-CBC", "AES-128-CBC-HMAC-SHA1", "AES-128-CBC-HMAC-SHA256"],
|
|
72
|
+
},
|
|
73
|
+
mapping: {
|
|
74
|
+
"name" => "cn;lang-en",
|
|
75
|
+
"email" => ["preferredEmail", "mail"],
|
|
76
|
+
"nickname" => ["uid", "userid", "sAMAccountName"],
|
|
69
77
|
}
|
|
70
78
|
# Or, alternatively:
|
|
71
79
|
# use OmniAuth::Strategies::LDAP, filter: '(&(uid=%{username})(memberOf=cn=myapp-users,ou=groups,dc=example,dc=com))'
|
|
@@ -73,6 +81,50 @@ use OmniAuth::Strategies::LDAP,
|
|
|
73
81
|
|
|
74
82
|
All of the listed options are required, with the exception of `:title`, `:name_proc`, `:bind_dn`, and `:password`.
|
|
75
83
|
|
|
84
|
+
## TLS certificate verification
|
|
85
|
+
|
|
86
|
+
This gem enables TLS certificate verification by default when you use `encryption: "ssl"` (LDAPS / simple TLS) or `encryption: "tls"` (STARTTLS). We always pass `tls_options` to Net::LDAP based on `OpenSSL::SSL::SSLContext::DEFAULT_PARAMS`, which includes `verify_mode: OpenSSL::SSL::VERIFY_PEER` and sane defaults.
|
|
87
|
+
|
|
88
|
+
- Secure by default: you do not need to set anything extra to verify the LDAP server certificate.
|
|
89
|
+
- To customize trust or ciphers, supply your own `tls_options`, which are merged over the safe defaults.
|
|
90
|
+
- If you truly need to skip verification (not recommended), set `disable_verify_certificates: true`.
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
# Verify server certs (default behavior)
|
|
96
|
+
use OmniAuth::Strategies::LDAP,
|
|
97
|
+
host: ENV["LDAP_HOST"],
|
|
98
|
+
port: 636,
|
|
99
|
+
encryption: "ssl", # or "tls"
|
|
100
|
+
base: "dc=example,dc=com",
|
|
101
|
+
uid: "uid"
|
|
102
|
+
|
|
103
|
+
# Use a private CA bundle and restrict protocol/ciphers
|
|
104
|
+
use OmniAuth::Strategies::LDAP,
|
|
105
|
+
host: ENV["LDAP_HOST"],
|
|
106
|
+
port: 636,
|
|
107
|
+
encryption: "ssl",
|
|
108
|
+
base: "dc=example,dc=com",
|
|
109
|
+
uid: "uid",
|
|
110
|
+
tls_options: {
|
|
111
|
+
ca_file: "/etc/ssl/private/my_org_ca.pem",
|
|
112
|
+
ssl_version: "TLSv1_2",
|
|
113
|
+
ciphers: ["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"],
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# Opt out of verification (NOT recommended โ use only in trusted test/dev scenarios)
|
|
117
|
+
use OmniAuth::Strategies::LDAP,
|
|
118
|
+
host: ENV["LDAP_HOST"],
|
|
119
|
+
port: 636,
|
|
120
|
+
encryption: "ssl",
|
|
121
|
+
base: "dc=example,dc=com",
|
|
122
|
+
uid: "uid",
|
|
123
|
+
disable_verify_certificates: true
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Note: Net::LDAP historically defaulted to no certificate validation when `tls_options` were not provided. This library mitigates that by always providing secure `tls_options` unless you explicitly disable verification.
|
|
127
|
+
|
|
76
128
|
## ๐ก Info you can shake a stick at
|
|
77
129
|
|
|
78
130
|
| Tokens to Remember | [![Gem name][โณ๏ธname-img]][โณ๏ธgem-name] [![Gem namespace][โณ๏ธnamespace-img]][โณ๏ธgem-namespace] |
|
|
@@ -191,6 +243,28 @@ The following options are available for configuring the OmniAuth LDAP strategy:
|
|
|
191
243
|
- `:sasl_mechanisms` - Array of SASL mechanisms to use (e.g., ["DIGEST-MD5", "GSS-SPNEGO"]).
|
|
192
244
|
- `:allow_anonymous` - Whether to allow anonymous binding (default: false).
|
|
193
245
|
- `:logger` - A logger instance for debugging (optional, for internal use).
|
|
246
|
+
- `:password_policy` - When true, the strategy will request the LDAP Password Policy response control (OID `1.3.6.1.4.1.42.2.27.8.5.1`) during the user bind. If the server supports it, the adaptor exposes:
|
|
247
|
+
- `adaptor.last_operation_result` โ the last Net::LDAP operation result object.
|
|
248
|
+
- `adaptor.last_password_policy_response` โ the matching password policy response control (implementation-specific object). This can indicate conditions such as password expired, account locked, reset required, or grace logins remaining (per the draft RFC).
|
|
249
|
+
- `:connect_timeout` - Maximum time in seconds to wait when establishing the TCP connection to the LDAP server. Forwarded to `Net::LDAP`.
|
|
250
|
+
- `:read_timeout` - Maximum time in seconds to wait for reads during LDAP operations (search/bind). Forwarded to `Net::LDAP`.
|
|
251
|
+
- `:mapping` - Customize how LDAP attributes map to the returned `auth.info` hash. A sensible default mapping is built into the strategy and will be merged with your overrides. See `lib/omniauth/strategies/ldap.rb` for the default keys and behavior; values can be a String (single attribute), an Array (first present attribute wins), or a Hash (string pattern with placeholders like `%0` combined from multiple attributes).
|
|
252
|
+
|
|
253
|
+
Example enabling password policy:
|
|
254
|
+
|
|
255
|
+
```ruby
|
|
256
|
+
use OmniAuth::Builder do
|
|
257
|
+
provider :ldap,
|
|
258
|
+
host: "ldap.example.com",
|
|
259
|
+
base: "dc=example,dc=com",
|
|
260
|
+
uid: "uid",
|
|
261
|
+
bind_dn: "cn=search,dc=example,dc=com",
|
|
262
|
+
password: ENV["LDAP_SEARCH_PASSWORD"],
|
|
263
|
+
password_policy: true
|
|
264
|
+
end
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Note: This is best-effort and compatible with a range of net-ldap versions. If your server supports the control, you can inspect the response via the `adaptor` instance during/after authentication (for example in a failure handler) to tailor error messages.
|
|
194
268
|
|
|
195
269
|
### Auth Hash UID vs LDAP :uid (search attribute)
|
|
196
270
|
|
|
@@ -299,6 +373,58 @@ end
|
|
|
299
373
|
|
|
300
374
|
Then link users to `/auth/ldap` in your app (for example, in a Devise sign-in page).
|
|
301
375
|
|
|
376
|
+
### Use JSON Body
|
|
377
|
+
|
|
378
|
+
This gem is compatible with JSON-encoded POST bodies as well as traditional form-encoded.
|
|
379
|
+
|
|
380
|
+
- Set header `Content-Type` to `application/json`.
|
|
381
|
+
- Send a JSON object containing `username` and `password`.
|
|
382
|
+
- Rails automatically exposes parsed JSON params via `env["action_dispatch.request.request_parameters"]`, which this strategy reads first. In non-Rails Rack apps, ensure you use a JSON parser middleware if you post raw JSON.
|
|
383
|
+
|
|
384
|
+
Examples
|
|
385
|
+
|
|
386
|
+
- curl (JSON):
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
curl -i \
|
|
390
|
+
-X POST \
|
|
391
|
+
-H 'Content-Type: application/json' \
|
|
392
|
+
-d '{"username":"alice","password":"secret"}' \
|
|
393
|
+
http://localhost:3000/auth/ldap
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
The request phase will redirect to `/auth/ldap/callback` when both fields are present.
|
|
397
|
+
|
|
398
|
+
- curl (form-encoded, still supported):
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
curl -i \
|
|
402
|
+
-X POST \
|
|
403
|
+
-H 'Content-Type: application/x-www-form-urlencoded' \
|
|
404
|
+
--data-urlencode 'username=alice' \
|
|
405
|
+
--data-urlencode 'password=secret' \
|
|
406
|
+
http://localhost:3000/auth/ldap
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
- Browser (JavaScript fetch):
|
|
410
|
+
|
|
411
|
+
```js
|
|
412
|
+
fetch('/auth/ldap', {
|
|
413
|
+
method: 'POST',
|
|
414
|
+
headers: { 'Content-Type': 'application/json' },
|
|
415
|
+
body: JSON.stringify({ username: 'alice', password: 'secret' })
|
|
416
|
+
}).then(res => {
|
|
417
|
+
if (res.redirected) {
|
|
418
|
+
window.location = res.url; // typically /auth/ldap/callback
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Notes
|
|
424
|
+
|
|
425
|
+
- You can still initiate authentication by visiting `GET /auth/ldap` to render the HTML form and then submitting it (form-encoded). JSON is an additional option, not a replacement.
|
|
426
|
+
- In the callback phase (`POST /auth/ldap/callback`), the strategy reads JSON credentials the same way; Rails exposes them via `action_dispatch.request.request_parameters` and non-Rails apps should use a JSON parser middleware.
|
|
427
|
+
|
|
302
428
|
### Using a custom filter
|
|
303
429
|
|
|
304
430
|
If you need to restrict authentication to a group or use a more complex lookup, pass `:filter`. Use `%{username}` โ it will be replaced with the processed username (after `:name_proc`).
|
|
@@ -401,6 +527,84 @@ provider :ldap,
|
|
|
401
527
|
|
|
402
528
|
This trims `alice@example.com` to `alice` before searching.
|
|
403
529
|
|
|
530
|
+
### Mounted under a subdirectory (SCRIPT_NAME)
|
|
531
|
+
|
|
532
|
+
If your app is served from a path prefix (for example, behind a reverse proxy at `/myapp`, or mounted via Rack::URLMap, or Rails `relative_url_root`), the OmniAuth callback must include that subdirectory. This strategy uses `callback_url` for the form action and redirects, so it automatically includes any `SCRIPT_NAME` set by Rack/Rails. In other words, you typically do not need any special configuration beyond ensuring `SCRIPT_NAME` is correct in the request environment.
|
|
533
|
+
|
|
534
|
+
- Works out-of-the-box when:
|
|
535
|
+
- You mount the app at a path using Rackโs `map`/`URLMap`.
|
|
536
|
+
- You set Railsโ `config.relative_url_root` (or `RAILS_RELATIVE_URL_ROOT`) or deploy under a prefix with a reverse proxy that sets `SCRIPT_NAME`.
|
|
537
|
+
|
|
538
|
+
Rack example (mounted at /myapp):
|
|
539
|
+
|
|
540
|
+
```ruby
|
|
541
|
+
# config.ru
|
|
542
|
+
require "rack"
|
|
543
|
+
require "omniauth-ldap"
|
|
544
|
+
|
|
545
|
+
app = Rack::Builder.new do
|
|
546
|
+
use(Rack::Session::Cookie, secret: "change_me")
|
|
547
|
+
use(OmniAuth::Builder) do
|
|
548
|
+
provider(
|
|
549
|
+
:ldap,
|
|
550
|
+
host: "ldap.example.com",
|
|
551
|
+
base: "dc=example,dc=com",
|
|
552
|
+
uid: "uid",
|
|
553
|
+
title: "Example LDAP",
|
|
554
|
+
)
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
run(->(env) { [404, {"Content-Type" => "text/plain"}, [env.key?("omniauth.auth").to_s]] })
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
run Rack::URLMap.new(
|
|
561
|
+
"/myapp" => app,
|
|
562
|
+
)
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
- Visiting `POST /myapp/auth/ldap` renders the login form with `action='http://host/myapp/auth/ldap/callback'`.
|
|
566
|
+
- Any redirects (including header-based SSO fast path) will also point to `http://host/myapp/auth/ldap/callback`.
|
|
567
|
+
|
|
568
|
+
Rails example (relative_url_root):
|
|
569
|
+
|
|
570
|
+
```ruby
|
|
571
|
+
# config/environments/production.rb (or an initializer)
|
|
572
|
+
Rails.application.configure do
|
|
573
|
+
config.relative_url_root = "/myapp" # or set ENV["RAILS_RELATIVE_URL_ROOT"]
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
# config/initializers/omniauth.rb
|
|
577
|
+
Rails.application.config.middleware.use(OmniAuth::Builder) do
|
|
578
|
+
provider :ldap,
|
|
579
|
+
title: "Acme LDAP",
|
|
580
|
+
host: "ldap.acme.internal",
|
|
581
|
+
base: "dc=acme,dc=corp",
|
|
582
|
+
uid: "uid",
|
|
583
|
+
bind_dn: "cn=search,dc=acme,dc=corp",
|
|
584
|
+
password: ENV["LDAP_SEARCH_PASSWORD"],
|
|
585
|
+
name_proc: proc { |n| n.split("@").first }
|
|
586
|
+
end
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
- With `relative_url_root` set, Rails/Rack provide `SCRIPT_NAME=/myapp`, and this strategy will issue a form with `action='.../myapp/auth/ldap/callback'` and redirect accordingly.
|
|
590
|
+
|
|
591
|
+
Behind proxies with unusual host/proto handling (optional):
|
|
592
|
+
|
|
593
|
+
OmniAuth usually derives the correct scheme/host/prefix from Rack (and standard `X-Forwarded-*` headers). If your environment produces incorrect absolute URLs, you can override the computed host and prefix by setting `OmniAuth.config.full_host`:
|
|
594
|
+
|
|
595
|
+
```ruby
|
|
596
|
+
OmniAuth.config.full_host = lambda do |env|
|
|
597
|
+
scheme = (env["HTTP_X_FORWARDED_PROTO"] || env["rack.url_scheme"]).to_s.split(",").first
|
|
598
|
+
host = env["HTTP_X_FORWARDED_HOST"] || env["HTTP_HOST"] || [env["SERVER_NAME"], env["SERVER_PORT"]].compact.join(":")
|
|
599
|
+
script = env["SCRIPT_NAME"].to_s
|
|
600
|
+
"#{scheme}://#{host}#{script}"
|
|
601
|
+
end
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
Note: You generally do not need this override. Prefer configuring your proxy to pass standard `X-Forwarded-Proto` and `X-Forwarded-Host` headers and let Rack/OmniAuth compute the full URL.
|
|
605
|
+
|
|
606
|
+
- Header-based SSO (`header_auth: true`) also respects `SCRIPT_NAME`; when a trusted header is present on `POST /myapp/auth/ldap`, the strategy redirects to `http://host/myapp/auth/ldap/callback`.
|
|
607
|
+
|
|
404
608
|
### Trusted header SSO (REMOTE_USER and friends)
|
|
405
609
|
|
|
406
610
|
Some deployments terminate SSO at a reverse proxy or portal and forward the already-authenticated user identity via an HTTP header such as `REMOTE_USER`.
|
|
@@ -520,8 +724,6 @@ See [CONTRIBUTING.md][๐คcontributing].
|
|
|
520
724
|
|
|
521
725
|
[![Coveralls Test Coverage][๐coveralls-img]][๐coveralls]
|
|
522
726
|
|
|
523
|
-
[![QLTY Test Coverage][๐qlty-covi]][๐qlty-cov]
|
|
524
|
-
|
|
525
727
|
### ๐ช Code of Conduct
|
|
526
728
|
|
|
527
729
|
Everyone interacting with this project's codebases, issue trackers,
|
|
@@ -602,6 +804,9 @@ See [LICENSE.txt][๐license] for the official [Copyright Notice][๐copyright
|
|
|
602
804
|
</picture>
|
|
603
805
|
</a>, and omniauth-ldap contributors.
|
|
604
806
|
</li>
|
|
807
|
+
<li>
|
|
808
|
+
Copyright (c) 2014 David Benko
|
|
809
|
+
</li>
|
|
605
810
|
<li>
|
|
606
811
|
Copyright (c) 2011 by Ping Yu and Intridea, Inc.
|
|
607
812
|
</li>
|
|
@@ -622,7 +827,7 @@ To join the community or get help ๐๏ธ Join the Discord.
|
|
|
622
827
|
|
|
623
828
|
To say "thanks!" โ๏ธ Join the Discord or ๐๏ธ send money.
|
|
624
829
|
|
|
625
|
-
[![Sponsor me on GitHub Sponsors][๐sponsor-bottom-img]][๐sponsor] ๐ [![Sponsor me on Liberapay][โณliberapay-bottom-img]][โณliberapay
|
|
830
|
+
[![Sponsor me on GitHub Sponsors][๐sponsor-bottom-img]][๐sponsor] ๐ [![Sponsor me on Liberapay][โณliberapay-bottom-img]][โณliberapay] ๐ [![Donate on PayPal][๐paypal-bottom-img]][๐paypal]
|
|
626
831
|
|
|
627
832
|
### Please give the project a star โญ โฅ.
|
|
628
833
|
|
|
@@ -705,10 +910,6 @@ Thanks for RTFM. โบ๏ธ
|
|
|
705
910
|
[๐ฝoss-helpi]: https://www.codetriage.com/omniauth/omniauth-ldap/badges/users.svg
|
|
706
911
|
[๐ฝversion]: https://bestgems.org/gems/omniauth-ldap
|
|
707
912
|
[๐ฝversioni]: https://img.shields.io/gem/v/omniauth-ldap.svg
|
|
708
|
-
[๐qlty-mnt]: https://qlty.sh/gh/omniauth/projects/omniauth-ldap
|
|
709
|
-
[๐qlty-mnti]: https://qlty.sh/gh/omniauth/projects/omniauth-ldap/maintainability.svg
|
|
710
|
-
[๐qlty-cov]: https://qlty.sh/gh/omniauth/projects/omniauth-ldap/metrics/code?sort=coverageRating
|
|
711
|
-
[๐qlty-covi]: https://qlty.sh/gh/omniauth/projects/omniauth-ldap/coverage.svg
|
|
712
913
|
[๐codecov]: https://codecov.io/gh/omniauth/omniauth-ldap
|
|
713
914
|
[๐codecovi]: https://codecov.io/gh/omniauth/omniauth-ldap/graph/badge.svg
|
|
714
915
|
[๐coveralls]: https://coveralls.io/github/omniauth/omniauth-ldap?branch=main
|
|
@@ -790,7 +991,7 @@ Thanks for RTFM. โบ๏ธ
|
|
|
790
991
|
[๐gitmoji]: https://gitmoji.dev
|
|
791
992
|
[๐gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
792
993
|
[๐งฎkloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
793
|
-
[๐งฎkloc-img]: https://img.shields.io/badge/KLOC-0.
|
|
994
|
+
[๐งฎkloc-img]: https://img.shields.io/badge/KLOC-0.297-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
794
995
|
[๐security]: SECURITY.md
|
|
795
996
|
[๐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
796
997
|
[๐copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -9,7 +9,7 @@ module OmniAuth
|
|
|
9
9
|
|
|
10
10
|
InvalidCredentialsError = Class.new(StandardError)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
option :mapping, {
|
|
13
13
|
"name" => "cn",
|
|
14
14
|
"first_name" => "givenName",
|
|
15
15
|
"last_name" => "sn",
|
|
@@ -23,7 +23,7 @@ module OmniAuth
|
|
|
23
23
|
"url" => ["wwwhomepage"],
|
|
24
24
|
"image" => "jpegPhoto",
|
|
25
25
|
"description" => "description",
|
|
26
|
-
}
|
|
26
|
+
}
|
|
27
27
|
option :title, "LDAP Authentication" # default title for authentication form
|
|
28
28
|
# For OmniAuth >= 2.0 the default allowed request method is POST only.
|
|
29
29
|
# Ensure the strategy follows that default so GET /auth/:provider returns 404 as expected in tests.
|
|
@@ -46,6 +46,9 @@ module OmniAuth
|
|
|
46
46
|
# standard Rack "HTTP_" variant automatically.
|
|
47
47
|
option :header_auth, false
|
|
48
48
|
option :header_name, "REMOTE_USER"
|
|
49
|
+
# Optional timeouts (forwarded to Net::LDAP when supported)
|
|
50
|
+
option :connect_timeout, nil
|
|
51
|
+
option :read_timeout, nil
|
|
49
52
|
|
|
50
53
|
def request_phase
|
|
51
54
|
# OmniAuth >= 2.0 expects the request phase to be POST-only for /auth/:provider.
|
|
@@ -57,18 +60,18 @@ module OmniAuth
|
|
|
57
60
|
# Fast-path: if a trusted identity header is present, skip the login form
|
|
58
61
|
# and jump to the callback where we will complete using directory lookup.
|
|
59
62
|
if header_username
|
|
60
|
-
return Rack::Response.new([], 302, "Location" =>
|
|
63
|
+
return Rack::Response.new([], 302, "Location" => callback_url).finish
|
|
61
64
|
end
|
|
62
65
|
|
|
63
66
|
# If credentials were POSTed directly to /auth/:provider, redirect to the callback path.
|
|
64
67
|
# This mirrors the behavior of many OmniAuth providers and allows test helpers (like
|
|
65
68
|
# OmniAuth::Test::PhonySession) to populate `env['omniauth.auth']` on the callback request.
|
|
66
|
-
if request.post? &&
|
|
67
|
-
return Rack::Response.new([], 302, "Location" =>
|
|
69
|
+
if request.post? && request_data["username"].to_s != "" && request_data["password"].to_s != ""
|
|
70
|
+
return Rack::Response.new([], 302, "Location" => callback_url).finish
|
|
68
71
|
end
|
|
69
72
|
|
|
70
73
|
OmniAuth::LDAP::Adaptor.validate(@options)
|
|
71
|
-
f = OmniAuth::Form.new(title: options[:title] || "LDAP Authentication", url:
|
|
74
|
+
f = OmniAuth::Form.new(title: options[:title] || "LDAP Authentication", url: callback_url)
|
|
72
75
|
f.text_field("Login", "username")
|
|
73
76
|
f.password_field("Password", "password")
|
|
74
77
|
f.button("Sign In")
|
|
@@ -88,7 +91,7 @@ module OmniAuth
|
|
|
88
91
|
return fail!(:invalid_credentials, InvalidCredentialsError.new("User not found for header #{hu}"))
|
|
89
92
|
end
|
|
90
93
|
@ldap_user_info = entry
|
|
91
|
-
@user_info = self.class.map_user(
|
|
94
|
+
@user_info = self.class.map_user(@options[:mapping], @ldap_user_info)
|
|
92
95
|
return super
|
|
93
96
|
rescue => e
|
|
94
97
|
return fail!(:ldap_error, e)
|
|
@@ -97,13 +100,18 @@ module OmniAuth
|
|
|
97
100
|
|
|
98
101
|
return fail!(:missing_credentials) if missing_credentials?
|
|
99
102
|
begin
|
|
100
|
-
@ldap_user_info = @adaptor.bind_as(filter: filter(@adaptor), size: 1, password:
|
|
103
|
+
@ldap_user_info = @adaptor.bind_as(filter: filter(@adaptor), size: 1, password: request_data["password"])
|
|
101
104
|
|
|
102
105
|
unless @ldap_user_info
|
|
103
|
-
|
|
106
|
+
# Attach password policy info to env if available (best-effort)
|
|
107
|
+
attach_password_policy_env(@adaptor)
|
|
108
|
+
return fail!(:invalid_credentials, InvalidCredentialsError.new("Invalid credentials for #{request_data["username"]}"))
|
|
104
109
|
end
|
|
105
110
|
|
|
106
|
-
|
|
111
|
+
# Optionally attach policy info even on success (e.g., timeBeforeExpiration)
|
|
112
|
+
attach_password_policy_env(@adaptor)
|
|
113
|
+
|
|
114
|
+
@user_info = self.class.map_user(@options[:mapping], @ldap_user_info)
|
|
107
115
|
super
|
|
108
116
|
rescue => e
|
|
109
117
|
fail!(:ldap_error, e)
|
|
@@ -111,11 +119,12 @@ module OmniAuth
|
|
|
111
119
|
end
|
|
112
120
|
|
|
113
121
|
def filter(adaptor, username_override = nil)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
Net::LDAP::Filter.
|
|
122
|
+
flt = adaptor.filter
|
|
123
|
+
if flt && !flt.to_s.empty?
|
|
124
|
+
username = Net::LDAP::Filter.escape(@options[:name_proc].call(username_override || request_data["username"]))
|
|
125
|
+
Net::LDAP::Filter.construct(flt % {username: username})
|
|
117
126
|
else
|
|
118
|
-
Net::LDAP::Filter.equals(adaptor.uid, @options[:name_proc].call(username_override ||
|
|
127
|
+
Net::LDAP::Filter.equals(adaptor.uid, @options[:name_proc].call(username_override || request_data["username"]))
|
|
119
128
|
end
|
|
120
129
|
end
|
|
121
130
|
|
|
@@ -173,8 +182,12 @@ module OmniAuth
|
|
|
173
182
|
end
|
|
174
183
|
|
|
175
184
|
def missing_credentials?
|
|
176
|
-
|
|
177
|
-
end
|
|
185
|
+
request_data["username"].nil? || request_data["username"].empty? || request_data["password"].nil? || request_data["password"].empty?
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def request_data
|
|
189
|
+
@env["action_dispatch.request.request_parameters"] || request.params
|
|
190
|
+
end
|
|
178
191
|
|
|
179
192
|
# Extract a normalized username from a trusted header when enabled.
|
|
180
193
|
# Returns nil when not configured or not present.
|
|
@@ -193,13 +206,54 @@ module OmniAuth
|
|
|
193
206
|
# (bind_dn/password or anonymous). Does not attempt to bind as the user.
|
|
194
207
|
def directory_lookup(adaptor, username)
|
|
195
208
|
entry = nil
|
|
196
|
-
|
|
209
|
+
search_filter = filter(adaptor, username)
|
|
197
210
|
adaptor.connection.open do |conn|
|
|
198
|
-
rs = conn.search(filter:
|
|
199
|
-
entry = rs
|
|
211
|
+
rs = conn.search(filter: search_filter, size: 1)
|
|
212
|
+
entry = rs && rs.first
|
|
200
213
|
end
|
|
201
214
|
entry
|
|
202
215
|
end
|
|
216
|
+
|
|
217
|
+
# If the adaptor captured a Password Policy response control, expose a minimal, stable hash
|
|
218
|
+
# in the Rack env for applications to inspect.
|
|
219
|
+
def attach_password_policy_env(adaptor)
|
|
220
|
+
return unless adaptor.respond_to?(:password_policy) && adaptor.password_policy
|
|
221
|
+
ctrl = adaptor.respond_to?(:last_password_policy_response) ? adaptor.last_password_policy_response : nil
|
|
222
|
+
op = adaptor.respond_to?(:last_operation_result) ? adaptor.last_operation_result : nil
|
|
223
|
+
return unless ctrl || op
|
|
224
|
+
|
|
225
|
+
request.env["omniauth.ldap.password_policy"] = extract_password_policy(ctrl, op)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Best-effort extraction across net-ldap versions; if fields are not available, returns a raw payload.
|
|
229
|
+
def extract_password_policy(control, operation)
|
|
230
|
+
data = {raw: control}
|
|
231
|
+
if control
|
|
232
|
+
# Prefer named readers if present
|
|
233
|
+
if control.respond_to?(:error)
|
|
234
|
+
data[:error] = control.public_send(:error)
|
|
235
|
+
elsif control.respond_to?(:ppolicy_error)
|
|
236
|
+
data[:error] = control.public_send(:ppolicy_error)
|
|
237
|
+
end
|
|
238
|
+
if control.respond_to?(:time_before_expiration)
|
|
239
|
+
data[:time_before_expiration] = control.public_send(:time_before_expiration)
|
|
240
|
+
end
|
|
241
|
+
if control.respond_to?(:grace_authns_remaining)
|
|
242
|
+
data[:grace_authns_remaining] = control.public_send(:grace_authns_remaining)
|
|
243
|
+
elsif control.respond_to?(:grace_logins_remaining)
|
|
244
|
+
data[:grace_authns_remaining] = control.public_send(:grace_logins_remaining)
|
|
245
|
+
end
|
|
246
|
+
if control.respond_to?(:oid)
|
|
247
|
+
data[:oid] = control.public_send(:oid)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
if operation
|
|
251
|
+
code = operation.respond_to?(:code) ? operation.code : nil
|
|
252
|
+
message = operation.respond_to?(:message) ? operation.message : nil
|
|
253
|
+
data[:operation] = {code: code, message: message}
|
|
254
|
+
end
|
|
255
|
+
data
|
|
256
|
+
end
|
|
203
257
|
end
|
|
204
258
|
end
|
|
205
259
|
end
|
|
@@ -31,6 +31,10 @@ module OmniAuth
|
|
|
31
31
|
:allow_anonymous,
|
|
32
32
|
:filter,
|
|
33
33
|
:tls_options,
|
|
34
|
+
:password_policy,
|
|
35
|
+
# Timeouts
|
|
36
|
+
:connect_timeout,
|
|
37
|
+
:read_timeout,
|
|
34
38
|
|
|
35
39
|
# Deprecated
|
|
36
40
|
:method,
|
|
@@ -59,7 +63,7 @@ module OmniAuth
|
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
attr_accessor :bind_dn, :password
|
|
62
|
-
attr_reader :connection, :uid, :base, :auth, :filter
|
|
66
|
+
attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
|
|
63
67
|
|
|
64
68
|
def self.validate(configuration = {})
|
|
65
69
|
message = []
|
|
@@ -88,6 +92,8 @@ module OmniAuth
|
|
|
88
92
|
port: @port,
|
|
89
93
|
encryption: encryption_options,
|
|
90
94
|
}
|
|
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.
|
|
91
97
|
@bind_method = if @try_sasl
|
|
92
98
|
:sasl
|
|
93
99
|
else
|
|
@@ -102,6 +108,21 @@ module OmniAuth
|
|
|
102
108
|
}
|
|
103
109
|
config[:auth] = @auth
|
|
104
110
|
@connection = Net::LDAP.new(config)
|
|
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
|
|
105
126
|
end
|
|
106
127
|
|
|
107
128
|
#:base => "dc=yourcompany, dc=com",
|
|
@@ -109,20 +130,47 @@ module OmniAuth
|
|
|
109
130
|
# :password => psw
|
|
110
131
|
def bind_as(args = {})
|
|
111
132
|
result = false
|
|
133
|
+
@last_operation_result = nil
|
|
134
|
+
@last_password_policy_response = nil
|
|
112
135
|
@connection.open do |me|
|
|
113
136
|
rs = me.search(args)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
|
126
174
|
end
|
|
127
175
|
end
|
|
128
176
|
end
|
|
@@ -250,6 +298,32 @@ module OmniAuth
|
|
|
250
298
|
result[key.to_sym] = value
|
|
251
299
|
end
|
|
252
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
|
|
253
327
|
end
|
|
254
328
|
end
|
|
255
329
|
end
|
|
@@ -15,7 +15,7 @@ module OmniAuth
|
|
|
15
15
|
|
|
16
16
|
VALID_ADAPTER_CONFIGURATION_KEYS: Array[Symbol]
|
|
17
17
|
MUST_HAVE_KEYS: Array[untyped]
|
|
18
|
-
|
|
18
|
+
ENCRYPTION_METHOD: Hash[Symbol, Symbol?]
|
|
19
19
|
|
|
20
20
|
attr_accessor bind_dn: String?
|
|
21
21
|
attr_accessor password: String?
|
|
@@ -28,6 +28,10 @@ module OmniAuth
|
|
|
28
28
|
attr_reader auth: Hash[Symbol, untyped]
|
|
29
29
|
# filter is an LDAP filter string when configured
|
|
30
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
|
|
31
35
|
|
|
32
36
|
# Validate that required keys exist in the configuration
|
|
33
37
|
def self.validate: (?Hash[Symbol, untyped]) -> void
|
|
@@ -38,17 +42,31 @@ module OmniAuth
|
|
|
38
42
|
|
|
39
43
|
private
|
|
40
44
|
|
|
41
|
-
# Returns
|
|
42
|
-
def
|
|
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
|
|
43
57
|
|
|
44
58
|
# Returns an array of SASL auth hashes
|
|
45
59
|
def sasl_auths: (?Hash[Symbol, untyped]) -> Array[Hash[Symbol, untyped]]
|
|
46
60
|
|
|
47
|
-
# Returns initial credential
|
|
48
|
-
# Use Array[untyped] here to avoid tuple syntax issues in some linters; the runtime value
|
|
49
|
-
# is commonly a two-element array [initial_credential, proc].
|
|
61
|
+
# Returns initial credential and a proc that accepts a challenge and returns the response
|
|
50
62
|
def sasl_bind_setup_digest_md5: (?Hash[Symbol, untyped]) -> Array[untyped]
|
|
51
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?
|
|
52
70
|
end
|
|
53
71
|
end
|
|
54
72
|
end
|
|
@@ -3,9 +3,6 @@ module OmniAuth
|
|
|
3
3
|
class LDAP
|
|
4
4
|
OMNIAUTH_GTE_V2: bool
|
|
5
5
|
|
|
6
|
-
# CONFIG is a read-only mapping of string keys to mapping definitions
|
|
7
|
-
CONFIG: Hash[String, untyped]
|
|
8
|
-
|
|
9
6
|
# The request_phase either returns a Rack-compatible response or the form response.
|
|
10
7
|
def request_phase: () -> (Rack::Response | Array[untyped] | String)
|
|
11
8
|
|
|
@@ -27,6 +24,12 @@ module OmniAuth
|
|
|
27
24
|
|
|
28
25
|
# Perform a directory lookup for a given username; returns an Entry or nil
|
|
29
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
|
|
30
33
|
end
|
|
31
34
|
end
|
|
32
35
|
end
|
data/sig/omniauth-ldap.rbs
CHANGED
data/sig/rbs/net-ldap.rbs
CHANGED
|
@@ -5,6 +5,7 @@ module Net
|
|
|
5
5
|
def open: () { (self) -> untyped } -> untyped
|
|
6
6
|
def search: (?Hash[Symbol, untyped]) -> Array[Net::LDAP::Entry]
|
|
7
7
|
def bind: (?Hash[Symbol, untyped]) -> bool
|
|
8
|
+
def get_operation_result: () -> Net::LDAP::PDU
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
class LDAP::Entry
|
|
@@ -15,5 +16,20 @@ module Net
|
|
|
15
16
|
def self.construct: (String) -> Net::LDAP::Filter
|
|
16
17
|
def self.eq: (String, String) -> Net::LDAP::Filter
|
|
17
18
|
end
|
|
18
|
-
end
|
|
19
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
|
data/sig/rbs/net-ntlm.rbs
CHANGED
|
@@ -4,6 +4,8 @@ module Net
|
|
|
4
4
|
class Message
|
|
5
5
|
def self.parse: (untyped) -> Net::NTLM::Message
|
|
6
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
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
class Message::Type1
|
|
@@ -13,4 +15,3 @@ module Net
|
|
|
13
15
|
def self.encode_utf16le: (String) -> String
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
|
-
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omniauth-ldap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.3.
|
|
4
|
+
version: 2.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Boling
|
|
@@ -65,7 +65,7 @@ dependencies:
|
|
|
65
65
|
requirements:
|
|
66
66
|
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '1'
|
|
68
|
+
version: '1.2'
|
|
69
69
|
- - "<"
|
|
70
70
|
- !ruby/object:Gem::Version
|
|
71
71
|
version: '3'
|
|
@@ -75,7 +75,7 @@ dependencies:
|
|
|
75
75
|
requirements:
|
|
76
76
|
- - ">="
|
|
77
77
|
- !ruby/object:Gem::Version
|
|
78
|
-
version: '1'
|
|
78
|
+
version: '1.2'
|
|
79
79
|
- - "<"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
81
|
version: '3'
|
|
@@ -408,10 +408,10 @@ licenses:
|
|
|
408
408
|
- MIT
|
|
409
409
|
metadata:
|
|
410
410
|
homepage_uri: https://omniauth-ldap.galtzo.com/
|
|
411
|
-
source_code_uri: https://github.com/omniauth/omniauth-ldap/tree/v2.3.
|
|
412
|
-
changelog_uri: https://github.com/omniauth/omniauth-ldap/blob/v2.3.
|
|
411
|
+
source_code_uri: https://github.com/omniauth/omniauth-ldap/tree/v2.3.2
|
|
412
|
+
changelog_uri: https://github.com/omniauth/omniauth-ldap/blob/v2.3.2/CHANGELOG.md
|
|
413
413
|
bug_tracker_uri: https://github.com/omniauth/omniauth-ldap/issues
|
|
414
|
-
documentation_uri: https://www.rubydoc.info/gems/omniauth-ldap/2.3.
|
|
414
|
+
documentation_uri: https://www.rubydoc.info/gems/omniauth-ldap/2.3.2
|
|
415
415
|
funding_uri: https://github.com/sponsors/pboling
|
|
416
416
|
wiki_uri: https://github.com/omniauth/omniauth-ldap/wiki
|
|
417
417
|
news_uri: https://www.railsbling.com/tags/omniauth-ldap
|
metadata.gz.sig
CHANGED
|
Binary file
|