omniauth-ldap 2.3.3 → 2.3.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bcc01a9129d0db019b5530a9bf5f7b5241f9eacba974d5c5585b4620a8d140b
4
- data.tar.gz: 5eb2878ad0b0d471d60dfb4596baddb077cde9c26499ad1d2c3f661a96f1b242
3
+ metadata.gz: cfb42b529db19042a0140d9bdb39698b177710df48bc80eb9c1470bfebda0ae2
4
+ data.tar.gz: 411ba1e8817fc5814c248cbf096471ebe2f4a013a69dff3b6771143526a73f8b
5
5
  SHA512:
6
- metadata.gz: f3d489556fa774b9865a3138dcce9f9eef4d2afedbeff2d0bdb5ce239a3b18dd430bcdf2438b77135434e511750a50236fb0e6902ad00ce16e60d1021058fb41
7
- data.tar.gz: 4d544ca2868b9c0eb8d283dbc996b305bd1ca3d8070c9b5d342dc3de6d8d98206f197926da1bfd9f9b57e03728f8d96932a824b540fce3f4c66efd7e8ae08630
6
+ metadata.gz: e5cd173bb9dd917627ba9d96d3fe3a5e713bb74e3623d8ab1247fe71da0243e0e66658f64dd356247e060fbddda4a9031e76242dd8b0ea0575d9233bfcee1b0d
7
+ data.tar.gz: 70d8dd160e9793037bb4564cde716dfc8cd98c3805b73c65f49c5ecd2383b13c920828affab59e458b224b8f1eebfd4a127d9bd06a55d967e1d397f21f01a1da
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -32,6 +32,31 @@ Please file a bug if you notice a violation of semantic versioning.
32
32
 
33
33
  ### Security
34
34
 
35
+ ## [2.3.4] - 2026-05-18
36
+
37
+ - TAG: [v2.3.4][2.3.4t]
38
+ - COVERAGE: 97.44% -- 304/312 lines in 4 files
39
+ - BRANCH COVERAGE: 79.58% -- 113/142 branches in 4 files
40
+ - 94.44% documented
41
+
42
+ ### Added
43
+
44
+ - Add `header_auth_source` to require explicit selection of trusted header identity source (`:env` or `:http_header`)
45
+ - Add `header_auth_require_tls` to require TLS for trusted header SSO by default
46
+ - Log a prominent security warning when `header_auth` is enabled
47
+
48
+ ### Changed
49
+
50
+ - Trusted header SSO now defaults to trusting only server-set env variables and no longer checks Rack `HTTP_` header variants unless `header_auth_source: :http_header` is configured
51
+
52
+ ### Fixed
53
+
54
+ - Fix OpenSSL 3/Ruby 4 compatibility in the TLS options adaptor spec
55
+
56
+ ### Security
57
+
58
+ - Harden trusted header SSO against spoofing by removing automatic fallback from `REMOTE_USER` to `HTTP_REMOTE_USER`
59
+
35
60
  ## [2.3.3] - 2025-11-10
36
61
 
37
62
  - TAG: [v2.3.3][2.3.3t]
@@ -240,7 +265,9 @@ Please file a bug if you notice a violation of semantic versioning.
240
265
  [1.0.0]: https://github.com/omniauth/omniauth-ldap/compare/5656da80d4193e0d0584f44bac493a87695e580f...v1.0.0
241
266
  [1.0.0t]: https://github.com/omniauth/omniauth-ldap/releases/tag/v1.0.0
242
267
 
243
- [Unreleased]: https://github.com/omniauth/omniauth-ldap/compare/v2.3.3...HEAD
268
+ [Unreleased]: https://github.com/omniauth/omniauth-ldap/compare/v2.3.4...HEAD
269
+ [2.3.4]: https://github.com/omniauth/omniauth-ldap/compare/v2.3.3...v2.3.4
270
+ [2.3.4t]: https://github.com/omniauth/omniauth-ldap/releases/tag/v2.3.4
244
271
  [2.3.3]: https://github.com/omniauth/omniauth-ldap/compare/v2.3.2...v2.3.3
245
272
  [2.3.3t]: https://github.com/omniauth/omniauth-ldap/releases/tag/v2.3.3
246
273
  [2.3.2]: https://github.com/omniauth/omniauth-ldap/compare/v2.3.1...v2.3.2
data/CITATION.cff CHANGED
File without changes
data/CODE_OF_CONDUCT.md CHANGED
File without changes
data/CONTRIBUTING.md CHANGED
File without changes
data/FUNDING.md CHANGED
File without changes
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Peter H. Boling, and omniauth-ldap contributors
3
+ Copyright (c) 2025 - 2026 Peter H. Boling, and omniauth-ldap contributors
4
4
  Copyright (c) 2014 David Benko
5
5
  Copyright (c) 2011 by Ping Yu and Intridea, Inc.
6
6
 
data/README.md CHANGED
@@ -1,32 +1,3 @@
1
- | 📍 NOTE |
2
- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
3
- | RubyGems (the [GitHub org][rubygems-org], not the website) [suffered][draper-security] a [hostile takeover][ellen-takeover] in September 2025. |
4
- | Ultimately [4 maintainers][simi-removed] were [hard removed][martin-removed] and a reason has been given for only 1 of those, while 2 others resigned in protest. |
5
- | It is a [complicated story][draper-takeover] which is difficult to [parse quickly][draper-lies]. |
6
- | I'm adding notes like this to gems because I [don't condone theft][draper-theft] of repositories or gems from their rightful owners. |
7
- | If a similar theft happened with my repos/gems, I'd hope some would stand up for me. |
8
- | Disenfranchised former-maintainers have started [gem.coop][gem-coop]. |
9
- | Once available I will publish there exclusively; unless RubyCentral makes amends with the community. |
10
- | The ["Technology for Humans: Joel Draper"][reinteractive-podcast] podcast episode by [reinteractive][reinteractive] is the most cogent summary I'm aware of. |
11
- | See [here][gem-naming], [here][gem-coop] and [here][martin-ann] for more info on what comes next. |
12
- | What I'm doing: A (WIP) proposal for [bundler/gem scopes][gem-scopes], and a (WIP) proposal for a federated [gem server][gem-server]. |
13
-
14
- [rubygems-org]: https://github.com/rubygems/
15
- [draper-security]: https://joel.drapper.me/p/ruby-central-security-measures/
16
- [draper-takeover]: https://joel.drapper.me/p/ruby-central-takeover/
17
- [ellen-takeover]: https://pup-e.com/blog/goodbye-rubygems/
18
- [simi-removed]: https://www.reddit.com/r/ruby/s/gOk42POCaV
19
- [martin-removed]: https://bsky.app/profile/martinemde.com/post/3m3occezxxs2q
20
- [draper-lies]: https://joel.drapper.me/p/ruby-central-fact-check/
21
- [draper-theft]: https://joel.drapper.me/p/ruby-central/
22
- [reinteractive]: https://reinteractive.com/ruby-on-rails
23
- [gem-coop]: https://gem.coop
24
- [gem-naming]: https://github.com/gem-coop/gem.coop/issues/12
25
- [martin-ann]: https://martinemde.com/2025/10/05/announcing-gem-coop.html
26
- [gem-scopes]: https://github.com/galtzo-floss/bundle-namespace
27
- [gem-server]: https://github.com/galtzo-floss/gem-server
28
- [reinteractive-podcast]: https://youtu.be/_H4qbtC5qzU?si=BvuBU90R2wAqD2E6
29
-
30
1
  [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![omniauth Logo (presumed to be) by tomeara, (presumed to be) MIT License][🖼️omniauth-i]][🖼️omniauth]
31
2
 
32
3
  [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
@@ -48,6 +19,13 @@
48
19
 
49
20
  [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
50
21
 
22
+ <details>
23
+ <summary>👣 How will this project approach the September 2025 hostile takeover of RubyGems? 🚑️</summary>
24
+
25
+ I've summarized my thoughts in [this blog post](https://dev.to/galtzo/hostile-takeover-of-rubygems-my-thoughts-5hlo).
26
+
27
+ </details>
28
+
51
29
  ## 🌻 Synopsis
52
30
 
53
31
  Use the LDAP strategy as a middleware in your application:
@@ -79,7 +57,9 @@ use OmniAuth::Strategies::LDAP,
79
57
  # use OmniAuth::Strategies::LDAP, filter: '(&(uid=%{username})(memberOf=cn=myapp-users,ou=groups,dc=example,dc=com))'
80
58
  ```
81
59
 
82
- All of the listed options are required, with the exception of `:title`, `:name_proc`, `:bind_dn`, and `:password`.
60
+ At minimum you normally configure `:host`, `:base`, and either `:uid` or `:filter`. The other options shown above customize connection behavior, TLS, username normalization, timeouts, and returned auth info.
61
+
62
+ For trusted header SSO, enable `header_auth: true` and explicitly choose the trusted identity source with `header_auth_source: :env` or `header_auth_source: :http_header`. See [Trusted header SSO](#trusted-header-sso-remote_user-and-friends) for the security requirements.
83
63
 
84
64
  ### TLS certificate verification
85
65
 
@@ -228,14 +208,14 @@ The following options are available for configuring the OmniAuth LDAP strategy:
228
208
  ### Required Options
229
209
 
230
210
  - `:host` - The hostname or IP address of the LDAP server.
231
- - `:port` - The port number of the LDAP server (default: 389).
232
- - `:method` - The connection method. Allowed values: `:plain`, `:ssl`, `:tls` (default: `:plain`).
233
211
  - `:base` - The base DN for the LDAP search.
234
212
  - `:uid` or `:filter` - Either `:uid` (the LDAP attribute for username, default: "sAMAccountName") or `:filter` (LDAP filter for searching user entries). If `:filter` is provided, `:uid` is not required. Note: This `:uid` option is the search attribute, not the top-level `auth.uid` in the OmniAuth result.
235
213
 
236
214
  ### Optional Options
237
215
 
238
216
  - `:title` - The title for the authentication form (default: "LDAP Authentication").
217
+ - `:port` - The port number of the LDAP server (default: 389).
218
+ - `:encryption` - The connection method. Allowed values: `:plain`, `:ssl`, `:tls` (default: `:plain`). `:method` is still accepted for compatibility, but is deprecated.
239
219
  - `:bind_dn` - The DN to bind with for searching users (required if anonymous access is not allowed).
240
220
  - `:password` - The password for the bind DN.
241
221
  - `:name_proc` - A proc to process the username before using it in the search (default: identity proc that returns the username unchanged).
@@ -249,6 +229,10 @@ The following options are available for configuring the OmniAuth LDAP strategy:
249
229
  - `:connect_timeout` - Maximum time in seconds to wait when establishing the TCP connection to the LDAP server. Forwarded to `Net::LDAP`.
250
230
  - `:read_timeout` - Maximum time in seconds to wait for reads during LDAP operations (search/bind). Forwarded to `Net::LDAP`.
251
231
  - `: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).
232
+ - `:header_auth` - Enable trusted upstream identity SSO (default: false). When enabled, the strategy trusts the configured header/env key, performs an LDAP lookup, and skips the user password bind.
233
+ - `:header_name` - Header/env key used for trusted header SSO (default: "REMOTE_USER").
234
+ - `:header_auth_source` - Trusted identity source for header SSO (default: `:env`). Use `:env` to read only `env["REMOTE_USER"]`-style server variables. Use `:http_header` to read only Rack `HTTP_` header keys such as `env["HTTP_REMOTE_USER"]`; only configure this behind a proxy that strips client-supplied copies.
235
+ - `:header_auth_require_tls` - Require TLS for trusted header SSO requests (default: true).
252
236
 
253
237
  Example enabling password policy:
254
238
 
@@ -284,7 +268,7 @@ Where to find the "username"-style value
284
268
  - You can also read the raw attribute from `auth.extra.raw_info` (a `Net::LDAP::Entry`):
285
269
 
286
270
  ```ruby
287
- get "/auth/ldap/callback" do
271
+ post "/auth/ldap/callback" do
288
272
  auth = request.env["omniauth.auth"]
289
273
  dn = auth.uid # => "cn=alice,ou=users,dc=example,dc=com"
290
274
  username = auth.info.nickname # => "alice" (from uid/sAMAccountName)
@@ -300,7 +284,7 @@ If you need top-level `auth.uid` to be something other than the DN (for example,
300
284
  ## 🔧 Basic Usage
301
285
 
302
286
  The strategy exposes a simple Rack middleware and can be used in plain Rack apps, Sinatra, or Rails.
303
- Direct users to `/auth/ldap` to start authentication and handle the callback at `/auth/ldap/callback`.
287
+ With OmniAuth 2.x, initiate authentication with `POST /auth/ldap`; `GET /auth/ldap` returns 404 by default. Older OmniAuth 1.x deployments may still render the form on `GET /auth/ldap`. Handle the callback at `/auth/ldap/callback`.
304
288
 
305
289
  Below are several concrete examples to get you started.
306
290
 
@@ -316,7 +300,7 @@ use OmniAuth::Builder do
316
300
  provider :ldap,
317
301
  host: "ldap.example.com",
318
302
  port: 389,
319
- method: :plain,
303
+ encryption: :plain,
320
304
  base: "dc=example,dc=com",
321
305
  uid: "uid",
322
306
  title: "Example LDAP"
@@ -325,7 +309,7 @@ end
325
309
  run lambda { |env| [404, {"Content-Type" => "text/plain"}, [env.key?("omniauth.auth").to_s]] }
326
310
  ```
327
311
 
328
- Visit `GET /auth/ldap` to initiate authentication (the middleware will render a login form unless you POST to `/auth/ldap`).
312
+ Submit `POST /auth/ldap` to initiate authentication. With OmniAuth 2.x, the middleware renders the login form on POST when credentials are not already present; with OmniAuth 1.x, `GET /auth/ldap` can also render the form.
329
313
 
330
314
  ### Sinatra example
331
315
 
@@ -344,10 +328,10 @@ use OmniAuth::Builder do
344
328
  end
345
329
 
346
330
  get "/" do
347
- '<a href="/auth/ldap">Sign in with LDAP</a>'
331
+ '<form action="/auth/ldap" method="post"><button type="submit">Sign in with LDAP</button></form>'
348
332
  end
349
333
 
350
- get "/auth/ldap/callback" do
334
+ post "/auth/ldap/callback" do
351
335
  auth = request.env["omniauth.auth"]
352
336
  "Hello, #{auth.info["name"]}"
353
337
  end
@@ -371,7 +355,7 @@ Rails.application.config.middleware.use(OmniAuth::Builder) do
371
355
  end
372
356
  ```
373
357
 
374
- Then link users to `/auth/ldap` in your app (for example, in a Devise sign-in page).
358
+ Then submit users to `/auth/ldap` with POST in your app (for example, from a Devise sign-in page).
375
359
 
376
360
  ### Use JSON Body
377
361
 
@@ -422,7 +406,7 @@ Examples
422
406
 
423
407
  Notes
424
408
 
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.
409
+ - You can still initiate authentication with a regular form POST and then submit credentials as form-encoded data. JSON is an additional option, not a replacement.
426
410
  - 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
411
 
428
412
  ### Using a custom filter
@@ -607,15 +591,19 @@ Note: You generally do not need this override. Prefer configuring your proxy to
607
591
 
608
592
  ### Trusted header SSO (REMOTE_USER and friends)
609
593
 
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`.
594
+ Some deployments terminate SSO at a reverse proxy or portal and forward the already-authenticated user identity via a server-set environment variable or HTTP header such as `REMOTE_USER`.
611
595
  When you enable this mode, the LDAP strategy will trust the upstream header, perform a directory lookup for that user, and complete OmniAuth without asking the user for a password.
612
596
 
613
- Important: Only enable this behind a trusted front-end that strips and sets the header itself. Never enable on a public endpoint without such a gateway, or an attacker could spoof the header.
597
+ Important: Only enable this behind a trusted front-end that authenticates users before they can reach the OmniAuth endpoint. When `header_auth` is enabled the strategy logs a prominent security warning because it trusts the upstream identity completely.
614
598
 
615
599
  Configuration options:
616
600
 
617
601
  - `:header_auth` (Boolean, default: false) — Enable trusted header SSO.
618
- - `:header_name` (String, default: "REMOTE_USER") — The env/header key to read. The strategy checks both `env["REMOTE_USER"]` and the Rack variant `env["HTTP_REMOTE_USER"]`.
602
+ - `:header_name` (String, default: "REMOTE_USER") — The env/header key to read.
603
+ - `:header_auth_source` (`:env` or `:http_header`, default: `:env`) — Which Rack env key form to trust.
604
+ - `:env` reads only the exact server-set environment key, such as `env["REMOTE_USER"]`.
605
+ - `:http_header` reads only the Rack HTTP header key, such as `env["HTTP_REMOTE_USER"]`. Only use this behind a proxy that strips client-sent copies of the header before setting its trusted value.
606
+ - `:header_auth_require_tls` (Boolean, default: true) — Raise an error if trusted header SSO is used on a non-TLS request.
619
607
  - `:name_proc` is applied to the header value before search (e.g., to strip a domain part).
620
608
  - Search is done using your configured `:uid` or `:filter` and the service bind (`:bind_dn`/`:password`) or anonymous bind if allowed.
621
609
 
@@ -629,8 +617,9 @@ use OmniAuth::Builder do
629
617
  uid: "uid",
630
618
  bind_dn: "cn=search,dc=example,dc=com",
631
619
  password: ENV["LDAP_SEARCH_PASSWORD"],
632
- header_auth: true, # trust REMOTE_USER
633
- header_name: "REMOTE_USER", # default
620
+ header_auth: true, # trust the configured upstream identity
621
+ header_name: "REMOTE_USER", # default
622
+ header_auth_source: :env, # default; reads env["REMOTE_USER"]
634
623
  name_proc: proc { |n| n.split("@").first }
635
624
  end
636
625
  ```
@@ -648,6 +637,7 @@ Rails.application.config.middleware.use(OmniAuth::Builder) do
648
637
  password: ENV["LDAP_SEARCH_PASSWORD"],
649
638
  header_auth: true,
650
639
  header_name: "REMOTE_USER",
640
+ header_auth_source: :env,
651
641
  # Optionally restrict with a group filter while using the header value
652
642
  filter: "(&(sAMAccountName=%{username})(memberOf=cn=myapp-users,ou=groups,dc=acme,dc=corp))",
653
643
  name_proc: proc { |n| n.gsub(/@.*$/, "") }
@@ -662,8 +652,9 @@ Flow:
662
652
 
663
653
  Security checklist:
664
654
 
665
- - Ensure your reverse proxy strips user-controlled copies of the header and sets the canonical `REMOTE_USER` itself.
666
- - Prefer TLS-secured internal links between the proxy and your app.
655
+ - Prefer `header_auth_source: :env` for server-set variables such as `REMOTE_USER`.
656
+ - Use `header_auth_source: :http_header` only when your reverse proxy strips user-controlled copies of the header and sets the canonical value itself.
657
+ - Keep `header_auth_require_tls` enabled unless a separate trusted channel protects traffic between the proxy and your app.
667
658
  - Consider also restricting with a group-based `:filter` so only authorized users can sign in.
668
659
 
669
660
  ## 🦷 FLOSS Funding
@@ -795,7 +786,7 @@ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright
795
786
 
796
787
  <ul>
797
788
  <li>
798
- Copyright (c) 2025 Peter H. Boling, of
789
+ Copyright (c) 2025 - 2026 Peter H. Boling, of
799
790
  <a href="https://discord.gg/3qme4XHNKN">
800
791
  Galtzo.com
801
792
  <picture>
@@ -990,7 +981,7 @@ Thanks for RTFM. ☺️
990
981
  [📌gitmoji]: https://gitmoji.dev
991
982
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
992
983
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
993
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.293-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
984
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-0.312-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
994
985
  [🔐security]: SECURITY.md
995
986
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
996
987
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
data/REEK CHANGED
File without changes
data/RUBOCOP.md CHANGED
File without changes
data/SECURITY.md CHANGED
File without changes
@@ -97,12 +97,18 @@ module OmniAuth
97
97
  option :name_proc, lambda { |n| n }
98
98
 
99
99
  # Trusted header SSO support (disabled by default)
100
- # :header_auth - when true and the header is present, the strategy trusts the upstream gateway
101
- # and searches the directory for the user without requiring a user password.
102
- # :header_name - which header/env key to read (default: "REMOTE_USER"). We will also check the
103
- # standard Rack "HTTP_" variant automatically.
100
+ # :header_auth - when true and the configured header/env key is present, the strategy trusts
101
+ # the upstream gateway and searches the directory for the user without
102
+ # requiring a user password.
103
+ # :header_name - which header/env key to read (default: "REMOTE_USER").
104
+ # :header_auth_source - :env trusts only server-set env variables. :http_header trusts only
105
+ # Rack HTTP header keys, and should only be used behind a proxy that
106
+ # strips client-supplied copies of the header.
107
+ # :header_auth_require_tls - require a TLS request for header auth.
104
108
  option :header_auth, false
105
109
  option :header_name, "REMOTE_USER"
110
+ option :header_auth_source, :env
111
+ option :header_auth_require_tls, true
106
112
 
107
113
  # Optional timeouts (forwarded to Net::LDAP when supported)
108
114
  option :connect_timeout, nil
@@ -124,6 +130,8 @@ module OmniAuth
124
130
  return Rack::Response.new("", 404, {"Content-Type" => "text/plain"}).finish
125
131
  end
126
132
 
133
+ validate_header_auth_configuration!
134
+
127
135
  # Fast-path: if a trusted identity header is present, skip the login form
128
136
  # and jump to the callback where we will complete using directory lookup.
129
137
  if header_username
@@ -163,6 +171,8 @@ module OmniAuth
163
171
 
164
172
  return fail!(:invalid_request_method) unless valid_request_method?
165
173
 
174
+ validate_header_auth_configuration!
175
+
166
176
  # Header-based SSO (REMOTE_USER-style) path
167
177
  if (hu = header_username)
168
178
  begin
@@ -311,24 +321,62 @@ module OmniAuth
311
321
  @env["action_dispatch.request.request_parameters"] || request.params
312
322
  end
313
323
 
314
- # Extract a normalized username from a trusted header when enabled.
324
+ # Extract a normalized username from a trusted header/env key when enabled.
315
325
  # Returns nil when not configured or not present.
316
326
  #
317
- # The method will attempt the raw env key (e.g. "REMOTE_USER") and the Rack
318
- # HTTP_ variant (e.g. "HTTP_REMOTE_USER" or "HTTP_X_REMOTE_USER").
327
+ # The source is intentionally explicit: :env reads the raw env key
328
+ # (e.g. "REMOTE_USER"), while :http_header reads the Rack HTTP_ variant
329
+ # (e.g. "HTTP_REMOTE_USER" or "HTTP_X_REMOTE_USER").
319
330
  #
320
331
  # @return [String, nil] normalized username or nil if not present
321
332
  def header_username
322
333
  return unless options[:header_auth]
323
334
 
324
- name = options[:header_name] || "REMOTE_USER"
325
- # Try both the raw env var (e.g., REMOTE_USER) and the Rack HTTP_ variant (e.g., HTTP_REMOTE_USER or HTTP_X_REMOTE_USER)
326
- raw = request.env[name] || request.env["HTTP_#{name.upcase.tr("-", "_")}"]
335
+ raw = request.env[header_auth_env_key]
327
336
  return if raw.nil? || raw.to_s.strip.empty?
328
337
 
329
338
  options[:name_proc].call(raw.to_s)
330
339
  end
331
340
 
341
+ # Validate trusted header auth before reading the configured identity key.
342
+ #
343
+ # @raise [ArgumentError] when the header auth options are unsafe or invalid
344
+ # @return [void]
345
+ def validate_header_auth_configuration!
346
+ return unless options[:header_auth]
347
+
348
+ log_header_auth_warning
349
+
350
+ source = (options[:header_auth_source] || :env).to_sym
351
+ unless [:env, :http_header].include?(source)
352
+ raise ArgumentError, "header_auth_source must be :env or :http_header"
353
+ end
354
+
355
+ if options[:header_auth_require_tls] && !request.ssl?
356
+ raise ArgumentError, "header_auth requires TLS unless header_auth_require_tls is disabled"
357
+ end
358
+ end
359
+
360
+ # Rack env key selected by the explicit header auth source option.
361
+ #
362
+ # @return [String]
363
+ def header_auth_env_key
364
+ name = options[:header_name] || "REMOTE_USER"
365
+ return name if (options[:header_auth_source] || :env).to_sym == :env
366
+
367
+ "HTTP_#{name.upcase.tr("-", "_")}"
368
+ end
369
+
370
+ # Warn operators that trusted header auth delegates authentication to the upstream gateway.
371
+ #
372
+ # @return [void]
373
+ def log_header_auth_warning
374
+ logger = OmniAuth.config.respond_to?(:logger) ? OmniAuth.config.logger : nil
375
+ return unless logger && logger.respond_to?(:warn)
376
+
377
+ logger.warn("[omniauth-ldap] SECURITY WARNING: header_auth is enabled. This trusts upstream authentication completely; only enable it behind a trusted proxy that strips client-supplied identity headers.")
378
+ end
379
+
332
380
  # Perform a directory lookup for the given username using the strategy configuration
333
381
  # (bind_dn/password or anonymous). Does not attempt to bind as the user.
334
382
  #
@@ -131,16 +131,18 @@ module OmniAuth
131
131
  # @param configuration [Hash] configuration hash passed to the adaptor
132
132
  # @raise [ArgumentError] when required keys are missing
133
133
  # @return [void]
134
- def self.validate(configuration = {})
135
- message = []
136
- MUST_HAVE_KEYS.each do |names|
137
- names = [names].flatten
138
- missing_keys = names.select { |name| configuration[name].nil? }
139
- if missing_keys == names
140
- message << names.join(" or ")
134
+ class << self
135
+ def validate(configuration = {})
136
+ message = []
137
+ MUST_HAVE_KEYS.each do |names|
138
+ names = [names].flatten
139
+ missing_keys = names.select { |name| configuration[name].nil? }
140
+ if missing_keys == names
141
+ message << names.join(" or ")
142
+ end
141
143
  end
144
+ raise ArgumentError.new(message.join(",") + " MUST be provided") unless message.empty?
142
145
  end
143
- raise ArgumentError.new(message.join(",") + " MUST be provided") unless message.empty?
144
146
  end
145
147
 
146
148
  # Create a new adaptor instance backed by a Net::LDAP connection.
@@ -8,7 +8,7 @@ module OmniAuth
8
8
  module Version
9
9
  # Public semantic version for the gem
10
10
  # @return [String]
11
- VERSION = "2.3.3"
11
+ VERSION = "2.3.4"
12
12
  end
13
13
  # Convenience constant for consumers that expect OmniAuth::LDAP::VERSION
14
14
  # @return [String]
data/lib/omniauth-ldap.rb CHANGED
File without changes
File without changes
File without changes
@@ -22,6 +22,12 @@ module OmniAuth
22
22
  # Extract username from a trusted header when enabled
23
23
  def header_username: () -> (String | nil)
24
24
 
25
+ def validate_header_auth_configuration!: () -> void
26
+
27
+ def header_auth_env_key: () -> String
28
+
29
+ def log_header_auth_warning: () -> void
30
+
25
31
  # Perform a directory lookup for a given username; returns an Entry or nil
26
32
  def directory_lookup: (OmniAuth::LDAP::Adaptor, String) -> untyped
27
33
 
File without changes
data/sig/rbs/net-ldap.rbs CHANGED
File without changes
data/sig/rbs/net-ntlm.rbs CHANGED
File without changes
data/sig/rbs/sasl.rbs CHANGED
File without changes
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.3
4
+ version: 2.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Boling
@@ -380,10 +380,10 @@ licenses:
380
380
  - MIT
381
381
  metadata:
382
382
  homepage_uri: https://omniauth-ldap.galtzo.com/
383
- source_code_uri: https://github.com/omniauth/omniauth-ldap/tree/v2.3.3
384
- changelog_uri: https://github.com/omniauth/omniauth-ldap/blob/v2.3.3/CHANGELOG.md
383
+ source_code_uri: https://github.com/omniauth/omniauth-ldap/tree/v2.3.4
384
+ changelog_uri: https://github.com/omniauth/omniauth-ldap/blob/v2.3.4/CHANGELOG.md
385
385
  bug_tracker_uri: https://github.com/omniauth/omniauth-ldap/issues
386
- documentation_uri: https://www.rubydoc.info/gems/omniauth-ldap/2.3.3
386
+ documentation_uri: https://www.rubydoc.info/gems/omniauth-ldap/2.3.4
387
387
  funding_uri: https://github.com/sponsors/pboling
388
388
  wiki_uri: https://github.com/omniauth/omniauth-ldap/wiki
389
389
  news_uri: https://www.railsbling.com/tags/omniauth-ldap
@@ -412,7 +412,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
412
412
  - !ruby/object:Gem::Version
413
413
  version: '0'
414
414
  requirements: []
415
- rubygems_version: 3.7.2
415
+ rubygems_version: 4.0.11
416
416
  specification_version: 4
417
417
  summary: "\U0001F4C1 LDAP strategy for OmniAuth."
418
418
  test_files: []
metadata.gz.sig CHANGED
Binary file