diff --git a/.git-hooks/footer-template.erb.txt b/.git-hooks/footer-template.erb.txt index d732d69..36cdb0a 100644 --- a/.git-hooks/footer-template.erb.txt +++ b/.git-hooks/footer-template.erb.txt @@ -1,5 +1,5 @@ ⚡️ A message from a fellow meat-based-AI ⚡️ -- [❤️] Finely-crafted open-source tools like <%= @gem_name %> (& many more) are a full-time endeavor. +- [❤️] Finely-crafted open-source tools like <%= @gem_name %> (& many more) require time and effort. - [❤️] Though I adore my work, it lacks financial sustainability. - [❤️] Please, help me continue enhancing your tools by becoming a sponsor: - [💲] https://liberapay.com/pboling/donate diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 2fe1e03..4fbef86 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -63,3 +63,5 @@ jobs: run: bundle exec appraisal ${{ matrix.appraisal }} bundle - name: Run ${{ matrix.appraisal }} checks via ${{ matrix.exec_cmd }} run: bundle exec appraisal ${{ matrix.appraisal }} bundle exec ${{ matrix.exec_cmd }} + - name: Validate RBS Types + run: bundle exec appraisal ${{ matrix.appraisal }} bin/rbs validate diff --git a/.idea/.gitignore b/.idea/.gitignore index f867ed5..a2409a3 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -3,11 +3,11 @@ /workspace.xml # Ignored default folder with query files /queries/ +# Editor-based HTTP Client requests +/httpRequests/ # Datasource local storage ignored files /dataSources/ /dataSources.local.xml -# Editor-based HTTP Client requests -/httpRequests/ # Zencoder local files /zencoder/chats @@ -15,3 +15,33 @@ /zencoder-chats-dedicated.xml # Local project config *.iml + +# Added: Ignore plugin migration/state artifacts (machine-specific) +/copilot.data.migration.*.xml +/GitLink.xml + +# Added: Ignore task & usage statistics (contain local timestamps / paths) +/tasks.xml +/usage.statistics.xml + +# Added: Local inspection profiles (developer-specific customizations) +/inspectionProfiles/ + +# Added: Library & index caches (regenerated per machine) +/libraries/ +/indexLayout.xml +/indexes/ + +# Added: Terminal, SSH, and other per-user runtime config +/terminal/ +/sshConfigs/ + +# Added: RubyMine misc SDK version drift (optional). Comment to share SDK config. +# /misc.xml + +# Commit: VCS local mappings can be regenerated (optional). Comment to share settings. +# /vcs.xml + +# Commit: Dictionary files (local spellcheck customizations) +# /dictionaries/ + diff --git a/.junie/guidelines.md b/.junie/guidelines.md index 94a8baf..2ec9f2e 100644 --- a/.junie/guidelines.md +++ b/.junie/guidelines.md @@ -47,9 +47,7 @@ This document captures project-specific knowledge to streamline setup, testing, - RSpec 3.13 with custom spec/spec_helper.rb configuration: - silent_stream: STDOUT is silenced by default for examples to keep logs clean. - To explicitly test console output, tag the example or group with :check_output. - - Global state hygiene: Around each example, FlossFunding.namespaces and FlossFunding.silenced are snapshotted and restored to prevent cross-test pollution. - DEBUG toggle: Set DEBUG=true to require 'debug' and avoid silencing output during your run. - - ENV seeding: The suite sets ENV["FLOSS_FUNDING_FLOSS_FUNDING"] = "Free-as-in-beer" so that the library’s own namespace is considered activated (avoids noisy warnings). - Coverage: kettle-soup-cover integrates SimpleCov; .simplecov is invoked from spec_helper when enabled by Kettle::Soup::Cover::DO_COV, which is controlled by K_SOUP_COV_DO being set to true / false. - RSpec.describe usage: - Use `describe "#"` to contain a block of specs that test instance method behavior. @@ -73,10 +71,11 @@ This document captures project-specific knowledge to streamline setup, testing, - Output visibility - To see STDOUT from the code under test, use the :check_output tag on the example or group. Example: - RSpec.describe "output", :check_output do - it "prints" do - puts "This output should be visible" - expect(true).to be true + RSpec.describe "with output", :check_output do + it "has output" do + output = capture(:stderr) {kernel.warn("This is a warning")} + logs = [ "This is a warning\n" ] + expect(output).to(include(*logs)) end end - Alternatively, run with DEBUG=true to disable silencing for the entire run. diff --git a/.rubocop_gradual.lock b/.rubocop_gradual.lock index 36c9132..eb377c4 100644 --- a/.rubocop_gradual.lock +++ b/.rubocop_gradual.lock @@ -1,6 +1,6 @@ { - "lib/omniauth-ldap/adaptor.rb:928056405": [ - [68, 7, 413, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 105664470] + "lib/omniauth-ldap/adaptor.rb:4205312053": [ + [134, 7, 413, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 105664470] ], "spec/integration/middleware_spec.rb:2185613788": [ [3, 16, 39, "RSpec/DescribeClass: The first argument to describe should be the class or module being tested.", 638096201], diff --git a/.rubocop_rspec.yml b/.rubocop_rspec.yml index df5911b..ee96d66 100644 --- a/.rubocop_rspec.yml +++ b/.rubocop_rspec.yml @@ -18,7 +18,7 @@ RSpec/InstanceVariable: RSpec/NestedGroups: Enabled: false - + RSpec/ExpectInHook: Enabled: false diff --git a/.yardignore b/.yardignore new file mode 100644 index 0000000..20a63ae --- /dev/null +++ b/.yardignore @@ -0,0 +1,5 @@ +# Ignore built gem artifacts and package dir +pkg/*.gem +*.gem +# Also ignore yardoc cache +.yardoc/ diff --git a/.yardopts b/.yardopts index 479134d..fafc28d 100644 --- a/.yardopts +++ b/.yardopts @@ -1,11 +1,14 @@ +--plugin fence +-e yard/fence/hoist.rb +--plugin yaml --plugin junk --plugin relative_markdown_links ---readme README.md +--readme tmp/yard-fence/README.md --charset utf-8 --markup markdown +--markup-provider kramdown --output docs ---load .yard_gfm_support.rb 'lib/**/*.rb' - -'*.md' -'*.txt' \ No newline at end of file +'tmp/yard-fence/*.md' +'tmp/yard-fence/*.txt' diff --git a/Appraisals b/Appraisals index a9e20bf..474ad12 100644 --- a/Appraisals +++ b/Appraisals @@ -56,48 +56,6 @@ appraise "dep-heads" do eval_gemfile "modular/runtime_heads.gemfile" end -appraise "ruby-2-3-omni-v1.2" do - eval_gemfile "modular/omniauth/r2/v1.2.gemfile" - eval_gemfile "modular/rack/r2.1/v1.0.gemfile" - eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" -end - -appraise "ruby-2-3-omni-v1.3" do - eval_gemfile "modular/omniauth/r2/v1.3.gemfile" - eval_gemfile "modular/rack/r2.1/v1.1.gemfile" - eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" -end - -appraise "ruby-2-3-omni-v1.4" do - eval_gemfile "modular/omniauth/r2/v1.4.gemfile" - eval_gemfile "modular/rack/r2.1/v1.2.gemfile" - eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" -end - -appraise "ruby-2-3-omni-v1.5" do - eval_gemfile "modular/omniauth/r2/v1.5.gemfile" - eval_gemfile "modular/rack/r2.1/v1.3.gemfile" - eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" -end - -appraise "ruby-2-3-omni-v1.6" do - eval_gemfile "modular/omniauth/r2/v1.6.gemfile" - eval_gemfile "modular/rack/r2.1/v1.4.gemfile" - eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" -end - -appraise "ruby-2-3-omni-v1.7" do - eval_gemfile "modular/omniauth/r2/v1.7.gemfile" - eval_gemfile "modular/rack/r2.1/v1.5.gemfile" - eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" -end - -appraise "ruby-2-3-omni-v1.8" do - eval_gemfile "modular/omniauth/r2/v1.8.gemfile" - eval_gemfile "modular/rack/r2.1/v1.6.gemfile" - eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" -end - appraise "ruby-2-4" do eval_gemfile "modular/omniauth/r2/v1.8.gemfile" eval_gemfile "modular/rack/r2.3/v2.1.gemfile" @@ -165,3 +123,45 @@ appraise "style" do eval_gemfile "modular/style.gemfile" eval_gemfile "modular/x_std_libs.gemfile" end + +appraise "ruby-2-3-omni-v1.2" do + eval_gemfile "modular/omniauth/r2/v1.2.gemfile" + eval_gemfile "modular/rack/r2.1/v1.0.gemfile" + eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" +end + +appraise "ruby-2-3-omni-v1.3" do + eval_gemfile "modular/omniauth/r2/v1.3.gemfile" + eval_gemfile "modular/rack/r2.1/v1.1.gemfile" + eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" +end + +appraise "ruby-2-3-omni-v1.4" do + eval_gemfile "modular/omniauth/r2/v1.4.gemfile" + eval_gemfile "modular/rack/r2.1/v1.2.gemfile" + eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" +end + +appraise "ruby-2-3-omni-v1.5" do + eval_gemfile "modular/omniauth/r2/v1.5.gemfile" + eval_gemfile "modular/rack/r2.1/v1.3.gemfile" + eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" +end + +appraise "ruby-2-3-omni-v1.6" do + eval_gemfile "modular/omniauth/r2/v1.6.gemfile" + eval_gemfile "modular/rack/r2.1/v1.4.gemfile" + eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" +end + +appraise "ruby-2-3-omni-v1.7" do + eval_gemfile "modular/omniauth/r2/v1.7.gemfile" + eval_gemfile "modular/rack/r2.1/v1.5.gemfile" + eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" +end + +appraise "ruby-2-3-omni-v1.8" do + eval_gemfile "modular/omniauth/r2/v1.8.gemfile" + eval_gemfile "modular/rack/r2.1/v1.6.gemfile" + eval_gemfile "modular/x_std_libs/r2.3/libs.gemfile" +end diff --git a/CHANGELOG.md b/CHANGELOG.md index b913496..f7b462c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,8 +22,13 @@ Please file a bug if you notice a violation of semantic versioning. ### Added +- Documentation cleanup & updates +- YARD documentation covering 94% of the code + ### Changed +- kettle-dev v1.1.54 + ### Deprecated ### Removed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2d8d54b..9e0ea33 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,13 +24,13 @@ Follow these instructions: ## Executables vs Rake tasks -Executables shipped by dependencies, such as omniauth-ldap, and stone_checksums, are available +Executables shipped by dependencies, such as kettle-dev, and stone_checksums, are available after running `bin/setup`. These include: - gem_checksums - kettle-changelog - kettle-commit-msg -- omniauth-ldap-setup +- kettle-dev-setup - kettle-dvcs - kettle-pre-release - kettle-readme-backers @@ -68,7 +68,9 @@ GitHub API and CI helpers Releasing and signing - SKIP_GEM_SIGNING: If set, skip gem signing during build/release - GEM_CERT_USER: Username for selecting your public cert in `certs/.pem` (defaults to $USER) -- SOURCE_DATE_EPOCH: Reproducible build timestamp. `kettle-release` will set this automatically for the session. +- SOURCE_DATE_EPOCH: Reproducible build timestamp. + - `kettle-release` will set this automatically for the session. + - Not needed on bundler >= 2.7.0, as reproducible builds have become the default. Git hooks and commit message helpers (exe/kettle-commit-msg) - GIT_HOOK_BRANCH_VALIDATE: Branch name validation mode (e.g., `jira`) or `false` to disable @@ -166,6 +168,7 @@ NOTE: To build without signing the gem set `SKIP_GEM_SIGNING` to any value in th 1. Update version.rb to contain the correct version-to-be-released. 2. Run `bundle exec kettle-changelog`. 3. Run `bundle exec kettle-release`. +4. Stay awake and monitor the release process for any errors, and answer any prompts. #### Manual process diff --git a/FUNDING.md b/FUNDING.md index 602bc70..29dcea8 100644 --- a/FUNDING.md +++ b/FUNDING.md @@ -6,7 +6,7 @@ Many paths lead to being a sponsor or a backer of this project. Are you on such [![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 to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon] +[![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon] [⛳liberapay-img]: https://img.shields.io/liberapay/goal/pboling.svg?logo=liberapay&color=a51611&style=flat [⛳liberapay]: https://liberapay.com/pboling/donate @@ -27,11 +27,11 @@ Many paths lead to being a sponsor or a backer of this project. Are you on such -# 🤑 Request for Help +# 🤑 A request for help Maintainers have teeth and need to pay their dentists. -After getting laid off in an RIF in March and filled with many dozens of rejections, -I'm now spending ~60+ hours a week building open source tools. +After getting laid off in an RIF in March, and encountering difficulty finding a new one, +I began spending most of my time building open source tools. I'm hoping to be able to pay for my kids' health insurance this month, so if you value the work I am doing, I need your support. Please consider sponsoring me or the project. @@ -40,16 +40,13 @@ To join the community or get help 👇️ Join the Discord. [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] -To say "thanks for maintaining such a great tool" ☝️ Join the Discord or 👇️ send money. +To say "thanks!" ☝️ Join the Discord or 👇️ send money. -[![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay-img] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal-img] +[![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal] # Another Way to Support Open Source Software -> How wonderful it is that nobody need wait a single moment before starting to improve the world.
->—Anne Frank - -I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions — totaling 79 hours of FLOSS coding over just the past seven days, a pretty regular week for me. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats). +I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats). If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in `bundle fund`. diff --git a/Gemfile.lock b/Gemfile.lock index b37bb30..04f09ac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,9 +41,6 @@ GEM thor (~> 1.0) coderay (1.1.3) concurrent-ruby (1.3.5) - crack (1.0.1) - bigdecimal - rexml date (3.5.0) debug (1.11.0) irb (~> 1.10) @@ -111,15 +108,14 @@ GEM guard (~> 2.1) guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) - hashdiff (1.2.1) hashie (5.0.0) io-console (0.8.1) irb (1.15.3) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.15.2) - kettle-dev (1.1.45) + json (2.16.0) + kettle-dev (1.1.54) kettle-soup-cover (1.0.10) simplecov (~> 0.22) simplecov-cobertura (~> 3.0) @@ -151,6 +147,7 @@ GEM rb-inotify (~> 0.9, >= 0.9.10) logger (1.7.0) lumberjack (1.4.2) + matrix (0.4.3) method_source (1.1.0) mutex_m (0.3.0) nenv (0.3.0) @@ -172,8 +169,13 @@ GEM parser (3.3.10.0) ast (~> 2.4.1) racc + pdf-core (0.10.0) pp (0.6.3) prettyprint + prawn (2.5.0) + matrix (~> 0.4) + pdf-core (~> 0.10.0) + ttfunk (~> 1.8) prettyprint (0.2.0) prism (1.6.0) pry (0.15.2) @@ -210,7 +212,7 @@ GEM rainbow (>= 2.0, < 4.0) rexml (~> 3.1) regexp_parser (2.11.3) - reline (0.6.2) + reline (0.6.3) io-console (~> 0.5) require_bench (1.0.4) version_gem (>= 1.1.3, < 4) @@ -250,7 +252,7 @@ GEM rubocop-ast (>= 1.46.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) - rubocop-ast (1.47.1) + rubocop-ast (1.48.0) parser (>= 3.3.7.2) prism (~> 1.4) rubocop-gradual (0.3.6) @@ -352,19 +354,27 @@ GEM rspec (~> 3.0) timecop (>= 0.7, < 1) tsort (0.2.0) + ttfunk (1.8.0) + bigdecimal (~> 3.1) unicode-display_width (3.2.0) unicode-emoji (~> 4.1) unicode-emoji (4.1.0) - vcr (6.3.1) - base64 version_gem (1.1.9) - webmock (3.26.1) - addressable (>= 2.8.0) - crack (>= 0.3.2) - hashdiff (>= 0.4.0, < 2.0.0) + yaml-converter (0.1.0) + kramdown (>= 2.4, < 3) + kramdown-parser-gfm (~> 1.1) + prawn (>= 2.5, < 3) + version_gem (~> 1.1, >= 1.1.9) yard (0.9.37) + yard-fence (0.8.0) + rdoc (~> 6.11) + version_gem (~> 1.1, >= 1.1.9) + yard (~> 0.9, >= 0.9.37) yard-relative_markdown_links (0.5.0) nokogiri (>= 1.14.3, < 2) + yard-yaml (0.1.0) + version_gem (~> 1.1, >= 1.1.9) + yaml-converter (~> 0.1) zeitwerk (2.7.3) zlib (3.2.2) @@ -390,7 +400,6 @@ DEPENDENCIES kettle-test (~> 1.0, >= 1.0.6) kramdown (~> 2.5, >= 2.5.1) kramdown-parser-gfm (~> 1.1) - logger (~> 1.7) mutex_m (~> 0.2) omniauth-ldap! rack-test (~> 2.2) @@ -409,11 +418,12 @@ DEPENDENCIES standard (>= 1.50) stone_checksums (~> 1.0, >= 1.0.2) stringio (>= 3.0) - vcr (>= 4) - webmock (>= 3) + yaml-converter (~> 0.1) yard (~> 0.9, >= 0.9.37) + yard-fence (~> 0.8) yard-junk (~> 0.0, >= 0.0.10)! yard-relative_markdown_links (~> 0.5.0) + yard-yaml (~> 0.1) BUNDLED WITH 2.7.2 diff --git a/README.md b/README.md index 618fee4..7f3909a 100644 --- a/README.md +++ b/README.md @@ -27,18 +27,18 @@ [gem-server]: https://github.com/galtzo-floss/gem-server [reinteractive-podcast]: https://youtu.be/_H4qbtC5qzU?si=BvuBU90R2wAqD2E6 -[![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] +[![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-ldap Logo by Aboling0, CC BY-SA 4.0][🖼️omniauth-ldap-i]][🖼️omniauth-ldap] [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN [🖼️ruby-lang-i]: https://logos.galtzo.com/assets/images/ruby-lang/avatar-192px.svg [🖼️ruby-lang]: https://www.ruby-lang.org/ -[🖼️omniauth-i]: https://logos.galtzo.com/assets/images/omniauth/avatar-192px.png -[🖼️omniauth]: https://github.com/omniauth/omniauth-ldap +[🖼️omniauth-ldap-i]: https://logos.galtzo.com/assets/images/omniauth/omniauth-ldap/avatar-192px.svg +[🖼️omniauth-ldap]: https://github.com/omniauth/omniauth-ldap # 📁 OmniAuth LDAP -[![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] +[![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] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![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] `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord]. @@ -81,50 +81,6 @@ use OmniAuth::Strategies::LDAP, All of the listed options are required, with the exception of `:title`, `:name_proc`, `:bind_dn`, and `:password`. -## TLS certificate verification - -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. - -- Secure by default: you do not need to set anything extra to verify the LDAP server certificate. -- To customize trust or ciphers, supply your own `tls_options`, which are merged over the safe defaults. -- If you truly need to skip verification (not recommended), set `disable_verify_certificates: true`. - -Examples: - -```ruby -# Verify server certs (default behavior) -use OmniAuth::Strategies::LDAP, - host: ENV["LDAP_HOST"], - port: 636, - encryption: "ssl", # or "tls" - base: "dc=example,dc=com", - uid: "uid" - -# Use a private CA bundle and restrict protocol/ciphers -use OmniAuth::Strategies::LDAP, - host: ENV["LDAP_HOST"], - port: 636, - encryption: "ssl", - base: "dc=example,dc=com", - uid: "uid", - tls_options: { - ca_file: "/etc/ssl/private/my_org_ca.pem", - ssl_version: "TLSv1_2", - ciphers: ["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"], - } - -# Opt out of verification (NOT recommended – use only in trusted test/dev scenarios) -use OmniAuth::Strategies::LDAP, - host: ENV["LDAP_HOST"], - port: 636, - encryption: "ssl", - base: "dc=example,dc=com", - uid: "uid", - disable_verify_certificates: true -``` - -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. - ## 💡 Info you can shake a stick at | Tokens to Remember | [![Gem name][⛳️name-img]][⛳️gem-name] [![Gem namespace][⛳️namespace-img]][⛳️gem-namespace] | @@ -134,8 +90,8 @@ Note: Net::LDAP historically defaulted to no certificate validation when `tls_op | Works with MRI Ruby 3 | [![Ruby 3.0 Compat][💎ruby-3.0i]][🚎4-lg-wf] [![Ruby 3.1 Compat][💎ruby-3.1i]][🚎6-s-wf] [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] | | Works with MRI Ruby 2 | ![Ruby 2.0 Compat][💎ruby-2.0i] ![Ruby 2.1 Compat][💎ruby-2.1i] ![Ruby 2.2 Compat][💎ruby-2.2i]
[![Ruby 2.3 Compat][💎ruby-2.3i]][🚎1-an-wf] [![Ruby 2.4 Compat][💎ruby-2.4i]][🚎1-an-wf] [![Ruby 2.5 Compat][💎ruby-2.5i]][🚎1-an-wf] [![Ruby 2.6 Compat][💎ruby-2.6i]][🚎7-us-wf] [![Ruby 2.7 Compat][💎ruby-2.7i]][🚎7-us-wf] | | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] | -| Source | [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] | -| Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] | +| Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ!][🧮kloc-img]][🧮kloc] | +| Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] | | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] | | Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] | | Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] | @@ -149,11 +105,27 @@ Compatible with MRI Ruby 2.0+, and concordant releases of JRuby, and TruffleRuby |------------------------------------------------|--------------------------------------------------------| | 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ | +### Federated DVCS + +
+ Find this repo on federated forges (Coming soon!) + +| Federated [DVCS][💎d-in-dvcs] Repository | Status | Issues | PRs | Wiki | CI | Discussions | +|-------------------------------------------------|-----------------------------------------------------------------------|---------------------------|--------------------------|---------------------------|--------------------------|------------------------------| +| 🧪 [omniauth/omniauth-ldap on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ | +| 🧊 [omniauth/omniauth-ldap on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ | +| 🐙 [omniauth/omniauth-ldap on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] | +| 🎮️ [Discord Server][✉️discord-invite] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] | [Let's][✉️discord-invite] | [talk][✉️discord-invite] | [about][✉️discord-invite] | [this][✉️discord-invite] | [library!][✉️discord-invite] | + +
+ +[gh-discussions]: https://github.com/omniauth/omniauth-ldap/discussions + ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/omniauth-ldap)](https://tidelift.com/subscription/pkg/rubygems-omniauth-ldap?utm_source=rubygems-omniauth-ldap&utm_medium=referral&utm_campaign=readme) Available as part of the Tidelift Subscription. -
+
Need enterprise-level guarantees? The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. @@ -188,7 +160,7 @@ gem install omniauth-ldap ### 🔒 Secure Installation -
+
For Medium or High Security Installations This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by @@ -668,7 +640,7 @@ Security checklist: ## 🦷 FLOSS Funding -While these tools are free software and will always be, the project would benefit immensely from some funding. +While omniauth tools are free software and will always be, the project would benefit immensely from some funding. Raising a monthly budget of... "dollars" would make the project more sustainable. We welcome both individual and corporate sponsors! We also offer a @@ -678,7 +650,7 @@ Currently, [GitHub Sponsors][🖇sponsor], and [Liberapay][⛳liberapay] are our **If you're working in a company that's making significant use of omniauth tools we'd appreciate it if you suggest to your company to become a omniauth sponsor.** -You can support me in development of OmniAuth tools via +You can support the development of omniauth tools via [GitHub Sponsors][🖇sponsor], [Liberapay][⛳liberapay], [PayPal][🖇paypal], @@ -698,7 +670,7 @@ I’m developing a new library, [floss_funding][🖇floss-funding-gem], designed **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags** -[![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 to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon] +[![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 to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon] ## 🔐 Security @@ -724,6 +696,8 @@ See [CONTRIBUTING.md][🤝contributing]. [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] +[![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] + ### 🪇 Code of Conduct Everyone interacting with this project's codebases, issue trackers, @@ -735,6 +709,8 @@ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][ Made with [contributors-img][🖐contrib-rocks]. +Also see GitLab Contributors: [https://gitlab.com/omniauth/omniauth-ldap/-/graphs/main][🚎contributors-gl] +
⭐️ Star History @@ -770,12 +746,11 @@ For example: spec.add_dependency("omniauth-ldap", "~> 1.0") ``` -
+
📌 Is "Platform Support" part of the public API? More details inside. SemVer should, IMO, but doesn't explicitly, say that dropping support for specific Platforms -is a *breaking change* to an API. -It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless. +is a *breaking change* to an API, and for that reason the bike shedding is endless. To get a better understanding of how SemVer is intended to work over a project's lifetime, read this article from the creator of SemVer: @@ -796,7 +771,7 @@ See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright ## 🤑 A request for help @@ -898,11 +867,17 @@ Thanks for RTFM. ☺️ [🏙️entsup-tidelift-sonar]: https://blog.tidelift.com/tidelift-joins-sonar [💁🏼‍♂️peterboling]: http://www.peterboling.com [🚂railsbling]: http://www.railsbling.com +[📜src-gl-img]: https://img.shields.io/badge/GitLab-FBA326?style=for-the-badge&logo=Gitlab&logoColor=orange +[📜src-gl]: https://gitlab.com/omniauth/omniauth-ldap/ +[📜src-cb-img]: https://img.shields.io/badge/CodeBerg-4893CC?style=for-the-badge&logo=CodeBerg&logoColor=blue +[📜src-cb]: https://codeberg.org/omniauth/omniauth-ldap [📜src-gh-img]: https://img.shields.io/badge/GitHub-238636?style=for-the-badge&logo=Github&logoColor=green [📜src-gh]: https://github.com/omniauth/omniauth-ldap [📜docs-cr-rd-img]: https://img.shields.io/badge/RubyDoc-Current_Release-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white [📜docs-head-rd-img]: https://img.shields.io/badge/YARD_on_Galtzo.com-HEAD-943CD2?style=for-the-badge&logo=readthedocs&logoColor=white +[📜gl-wiki]: https://gitlab.com/omniauth/omniauth-ldap/-/wikis/home [📜gh-wiki]: https://github.com/omniauth/omniauth-ldap/wiki +[📜gl-wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=gitlab&logoColor=white [📜gh-wiki-img]: https://img.shields.io/badge/wiki-examples-943CD2.svg?style=for-the-badge&logo=github&logoColor=white [👽dl-rank]: https://bestgems.org/gems/omniauth-ldap [👽dl-ranki]: https://img.shields.io/gem/rd/omniauth-ldap.svg @@ -910,6 +885,10 @@ Thanks for RTFM. ☺️ [👽oss-helpi]: https://www.codetriage.com/omniauth/omniauth-ldap/badges/users.svg [👽version]: https://bestgems.org/gems/omniauth-ldap [👽versioni]: https://img.shields.io/gem/v/omniauth-ldap.svg +[🏀qlty-mnt]: https://qlty.sh/gh/omniauth/projects/omniauth-ldap +[🏀qlty-mnti]: https://qlty.sh/gh/omniauth/projects/omniauth-ldap/maintainability.svg +[🏀qlty-cov]: https://qlty.sh/gh/omniauth/projects/omniauth-ldap/metrics/code?sort=coverageRating +[🏀qlty-covi]: https://qlty.sh/gh/omniauth/projects/omniauth-ldap/coverage.svg [🏀codecov]: https://codecov.io/gh/omniauth/omniauth-ldap [🏀codecovi]: https://codecov.io/gh/omniauth/omniauth-ldap/graph/badge.svg [🏀coveralls]: https://coveralls.io/github/omniauth/omniauth-ldap?branch=main @@ -973,11 +952,17 @@ Thanks for RTFM. ☺️ [💎jruby-headi]: https://img.shields.io/badge/JRuby-HEAD-FBE742?style=for-the-badge&logo=ruby&logoColor=blue [🤝gh-issues]: https://github.com/omniauth/omniauth-ldap/issues [🤝gh-pulls]: https://github.com/omniauth/omniauth-ldap/pulls +[🤝gl-issues]: https://gitlab.com/omniauth/omniauth-ldap/-/issues +[🤝gl-pulls]: https://gitlab.com/omniauth/omniauth-ldap/-/merge_requests +[🤝cb-issues]: https://codeberg.org/omniauth/omniauth-ldap/issues +[🤝cb-pulls]: https://codeberg.org/omniauth/omniauth-ldap/pulls +[🤝cb-donate]: https://donate.codeberg.org/ [🤝contributing]: CONTRIBUTING.md [🏀codecov-g]: https://codecov.io/gh/omniauth/omniauth-ldap/graphs/tree.svg [🖐contrib-rocks]: https://contrib.rocks [🖐contributors]: https://github.com/omniauth/omniauth-ldap/graphs/contributors [🖐contributors-img]: https://contrib.rocks/image?repo=omniauth/omniauth-ldap +[🚎contributors-gl]: https://gitlab.com/omniauth/omniauth-ldap/-/graphs/main [🪇conduct]: CODE_OF_CONDUCT.md [🪇conduct-img]: https://img.shields.io/badge/Contributor_Covenant-2.1-259D6C.svg [📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint @@ -991,7 +976,7 @@ Thanks for RTFM. ☺️ [📌gitmoji]: https://gitmoji.dev [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ -[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.297-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue +[🧮kloc-img]: https://img.shields.io/badge/KLOC-4.076-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue [🔐security]: SECURITY.md [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year @@ -1011,8 +996,3 @@ Thanks for RTFM. ☺️ [💎appraisal2]: https://github.com/appraisal-rb/appraisal2 [💎appraisal2-img]: https://img.shields.io/badge/appraised_by-appraisal2-34495e.svg?plastic&logo=ruby&logoColor=white [💎d-in-dvcs]: https://railsbling.com/posts/dvcs/put_the_d_in_dvcs/ - -[//]: # (LDAP RFC references) -[rfc4511]: https://datatracker.ietf.org/doc/html/rfc4511 -[rfc4514]: https://datatracker.ietf.org/doc/html/rfc4514 -[rfc4519]: https://datatracker.ietf.org/doc/html/rfc4519 diff --git a/Rakefile b/Rakefile index 97a28ef..d96c6e4 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ # frozen_string_literal: true -# kettle-dev Rakefile v1.1.45 - 2025-10-31 +# kettle-dev Rakefile v1.1.54 - 2025-11-10 # Ruby 2.3 (Safe Navigation) or higher required # # MIT License (see License.txt) diff --git a/bin/yaml-convert b/bin/yaml-convert new file mode 100755 index 0000000..961263e --- /dev/null +++ b/bin/yaml-convert @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'yaml-convert' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("yaml-converter", "yaml-convert") diff --git a/docs/OmniAuth.html b/docs/OmniAuth.html index 7a1578a..98133d0 100644 --- a/docs/OmniAuth.html +++ b/docs/OmniAuth.html @@ -78,14 +78,49 @@
Defined in:
-
lib/omniauth-ldap/adaptor.rb,
- lib/omniauth-ldap/version.rb,
lib/omniauth/strategies/ldap.rb
+
lib/omniauth/strategies/ldap.rb,
+ lib/omniauth-ldap/adaptor.rb,
lib/omniauth-ldap/version.rb
-

Defined Under Namespace

+

Overview

+
+

OmniAuth strategies namespace.

+ +

This file implements an LDAP authentication strategy for OmniAuth.
+It provides both an interactive request phase (login form) and a
+callback phase which binds to an LDAP directory to authenticate the
+user or performs a lookup for header-based SSO.

+ +

The strategy exposes a number of options (see option calls below)
+that control LDAP connection, mapping of LDAP attributes to the
+OmniAuth info hash, header-based SSO behavior, and SSL/timeouts.

+ + +
+
+
+ +
+

Examples:

+ + +

Minimal Rack mounting

+
+ +
use OmniAuth::Builder do
+  provider :ldap, {
+    host: 'ldap.example.com',
+    base: 'dc=example,dc=com'
+  }
+end
+ +
+ + +

Defined Under Namespace

@@ -107,7 +142,7 @@

Defined Under Namespace

diff --git a/docs/OmniAuth/LDAP.html b/docs/OmniAuth/LDAP.html index b440e9a..9dd5ca0 100644 --- a/docs/OmniAuth/LDAP.html +++ b/docs/OmniAuth/LDAP.html @@ -109,13 +109,26 @@

VERSION =
-

Make VERSION available in traditional way

+

Convenience constant for consumers that expect OmniAuth::LDAP::VERSION

+

Returns:

+
    + +
  • + + + (String) + + + +
  • + +
@@ -135,7 +148,7 @@

diff --git a/docs/OmniAuth/LDAP/Adaptor.html b/docs/OmniAuth/LDAP/Adaptor.html index 09194cb..dc4deab 100644 --- a/docs/OmniAuth/LDAP/Adaptor.html +++ b/docs/OmniAuth/LDAP/Adaptor.html @@ -99,7 +99,39 @@ -

Defined Under Namespace

+

Overview

+
+ +
+ Note: +

Public API: Adaptor.validate, #initialize, #bind_as, and attr readers such as #connection, #uid

+
+
+ +

Adaptor encapsulates the behavior required to connect to an LDAP server
+and perform searches and binds. It maps user-provided configuration into
+a Net::LDAP connection and provides compatibility helpers for different
+net-ldap and SASL versions. The adaptor is intentionally defensive and
+provides a small, stable API used by the OmniAuth strategy.

+ + +
+
+
+ +
+

Examples:

+ + +

Initialize with minimal config

+
+ +
adaptor = OmniAuth::LDAP::Adaptor.new(base: 'dc=example,dc=com', host: 'ldap.example.com')
+ +
+ + +

Defined Under Namespace

@@ -119,7 +151,31 @@

VALID_ADAPTER_CONFIGURATION_KEYS = - +
+
+

Valid configuration keys accepted by the adaptor. These correspond to
+the options supported by the gem and are used during initialization.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Array<Symbol>) + + + +
  • + +
+ +
[
   :hosts,
@@ -150,13 +206,27 @@ 

MUST_HAVE_KEYS =
-

A list of needed keys. Possible alternatives are specified using sub-lists.

+

Required configuration keys. This may include alternatives as sub-lists
+(e.g., [:hosts, :host] means either key is acceptable).

+

Returns:

+
    + +
  • + + + (Array) + + + +
  • + +
@@ -169,7 +239,30 @@

]

ENCRYPTION_METHOD = - +
+
+

Supported encryption method mapping for configuration readability.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Hash<Symbol,Symbol,nil>) + + + +
  • + +
+ +
{
   simple_tls: :simple_tls,
@@ -194,7 +287,7 @@ 

Instance Attribute Summary collaps
  • - #auth ⇒ Object + #auth ⇒ Hash @@ -213,7 +306,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute auth.

    +

    The final auth structure used by net-ldap.

  • @@ -222,7 +315,7 @@

    Instance Attribute Summary collaps
  • - #base ⇒ Object + #base ⇒ String @@ -241,7 +334,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute base.

    +

    The base DN for searches.

  • @@ -250,7 +343,7 @@

    Instance Attribute Summary collaps
  • - #bind_dn ⇒ Object + #bind_dn ⇒ String? @@ -267,7 +360,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute bind_dn.

    +

    The distinguished name used for binding when provided in configuration.

  • @@ -276,7 +369,7 @@

    Instance Attribute Summary collaps
  • - #connection ⇒ Object + #connection ⇒ Net::LDAP @@ -295,7 +388,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute connection.

    +

    The underlying Net::LDAP connection object.

  • @@ -304,7 +397,7 @@

    Instance Attribute Summary collaps
  • - #filter ⇒ Object + #filter ⇒ String? @@ -323,7 +416,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute filter.

    +

    Custom filter pattern when provided in configuration.

  • @@ -332,7 +425,7 @@

    Instance Attribute Summary collaps
  • - #last_operation_result ⇒ Object + #last_operation_result ⇒ Object? @@ -351,7 +444,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute last_operation_result.

    +

    Last operation result object returned by the ldap library (if any).

  • @@ -379,7 +472,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute last_password_policy_response.

    +

    Read-only attributes exposing connection and configuration state.

    @@ -388,7 +481,7 @@

    Instance Attribute Summary collaps
  • - #password ⇒ Object + #password ⇒ String? @@ -405,7 +498,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute password.

    +

    The bind password (may be nil for anonymous binds).

  • @@ -414,7 +507,7 @@

    Instance Attribute Summary collaps
  • - #password_policy ⇒ Object + #password_policy ⇒ Boolean @@ -433,7 +526,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute password_policy.

    +

    Whether to request LDAP Password Policy controls.

  • @@ -442,7 +535,7 @@

    Instance Attribute Summary collaps
  • - #uid ⇒ Object + #uid ⇒ String @@ -461,7 +554,7 @@

    Instance Attribute Summary collaps -

    Returns the value of attribute uid.

    +

    The user id attribute used for lookups (e.g., ‘sAMAccountName’).

  • @@ -483,7 +576,7 @@

  • - .validate(configuration = {}) ⇒ Object + .validate(configuration = {}) ⇒ void @@ -497,7 +590,7 @@

    -
    +

    Validate that a minimal configuration is present.

  • @@ -515,7 +608,7 @@

  • - #bind_as(args = {}) ⇒ Object + #bind_as(args = {}) ⇒ Net::LDAP::Entry, ... @@ -538,7 +631,7 @@

  • - #initialize(configuration = {}) ⇒ Adaptor + #initialize(configuration = {}) ⇒ OmniAuth::LDAP::Adaptor @@ -554,7 +647,7 @@

    -

    A new instance of Adaptor.

    +

    Create a new adaptor instance backed by a Net::LDAP connection.

  • @@ -569,7 +662,7 @@

    Constructor Details

    - #initialize(configuration = {}) ⇒ Adaptor + #initialize(configuration = {}) ⇒ OmniAuth::LDAP::Adaptor @@ -577,13 +670,55 @@

    -

    Returns a new instance of Adaptor.

    +

    Create a new adaptor instance backed by a Net::LDAP connection.

    + +

    The constructor does not immediately open a network connection but
    +prepares the Net::LDAP instance according to the provided configuration.
    +It also applies timeout settings where supported by the installed net-ldap version.

    +

    Parameters:

    +
      + +
    • + + configuration + + + (Hash) + + + (defaults to: {}) + + + — +

      user-provided configuration options

      +
      + +
    • + +
    + +

    Raises:

    +
      +
    • + + + (ArgumentError, ConfigurationError) + + + + — +

      on invalid configuration

      +
      + +
    • + +
    @@ -591,56 +726,56 @@

     
     
    -80
    -81
    -82
    -83
    -84
    -85
    -86
    -87
    -88
    -89
    -90
    -91
    -92
    -93
    -94
    -95
    -96
    -97
    -98
    -99
    -100
    -101
    -102
    -103
    -104
    -105
    -106
    -107
    -108
    -109
    -110
    -111
    -112
    -113
    -114
    -115
    -116
    -117
    -118
    -119
    -120
    -121
    -122
    -123
    -124
    -125
    -126
    +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 80
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 155
     
     def initialize(configuration = {})
       Adaptor.validate(configuration)
    @@ -704,7 +839,7 @@ 

    Instance Attribute Details

    - #authObject (readonly) + #authHash (readonly) @@ -712,13 +847,26 @@

    -

    Returns the value of attribute auth.

    +

    The final auth structure used by net-ldap.

    +

    Returns:

    +
      + +
    • + + + (Hash) + + + +
    • + +
    @@ -726,16 +874,12 @@

     
     
    -66
    -67
    -68
    +126

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 66
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 126
     
    -def auth
    -  @auth
    -end
    +attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
    @@ -746,7 +890,7 @@

    - #baseObject (readonly) + #baseString (readonly) @@ -754,13 +898,26 @@

    -

    Returns the value of attribute base.

    +

    The base DN for searches.

    +

    Returns:

    +
      + +
    • + + + (String) + + + +
    • + +
    @@ -768,16 +925,12 @@

     
     
    -66
    -67
    -68
    +126

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 66
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 126
     
    -def base
    -  @base
    -end
    +attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
    @@ -788,7 +941,7 @@

    - #bind_dnObject + #bind_dnString? @@ -796,13 +949,26 @@

    -

    Returns the value of attribute bind_dn.

    +

    The distinguished name used for binding when provided in configuration.

    +

    Returns:

    +
      + +
    • + + + (String, nil) + + + +
    • + +
    @@ -810,12 +976,12 @@

     
     
    -65
    -66
    -67
    +99 +100 +101

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 65
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 99
     
     def bind_dn
       @bind_dn
    @@ -830,7 +996,7 @@ 

    - #connectionObject (readonly) + #connectionNet::LDAP (readonly) @@ -838,13 +1004,26 @@

    -

    Returns the value of attribute connection.

    +

    The underlying Net::LDAP connection object.

    +

    Returns:

    +
      + +
    • + + + (Net::LDAP) + + + +
    • + +
    @@ -852,12 +1031,12 @@

     
     
    -66
    -67
    -68
    +126 +127 +128

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 66
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 126
     
     def connection
       @connection
    @@ -872,7 +1051,7 @@ 

    - #filterObject (readonly) + #filterString? (readonly) @@ -880,13 +1059,26 @@

    -

    Returns the value of attribute filter.

    +

    Custom filter pattern when provided in configuration.

    +

    Returns:

    +
      + +
    • + + + (String, nil) + + + +
    • + +
    @@ -894,16 +1086,12 @@

     
     
    -66
    -67
    -68
    +126

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 66
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 126
     
    -def filter
    -  @filter
    -end
    +attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
    @@ -914,7 +1102,7 @@

    - #last_operation_resultObject (readonly) + #last_operation_resultObject? (readonly) @@ -922,13 +1110,26 @@

    -

    Returns the value of attribute last_operation_result.

    +

    Last operation result object returned by the ldap library (if any)

    +

    Returns:

    +
      + +
    • + + + (Object, nil) + + + +
    • + +
    @@ -936,16 +1137,12 @@

     
     
    -66
    -67
    -68
    +126

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 66
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 126
     
    -def last_operation_result
    -  @last_operation_result
    -end
    +attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
    @@ -964,7 +1161,7 @@

    -

    Returns the value of attribute last_password_policy_response.

    +

    Read-only attributes exposing connection and configuration state.

    @@ -978,16 +1175,12 @@

     
     
    -66
    -67
    -68
    +126

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 66
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 126
     
    -def last_password_policy_response
    -  @last_password_policy_response
    -end
    +attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
    @@ -998,7 +1191,7 @@

    - #passwordObject + #passwordString? @@ -1006,13 +1199,26 @@

    -

    Returns the value of attribute password.

    +

    The bind password (may be nil for anonymous binds)

    +

    Returns:

    +
      + +
    • + + + (String, nil) + + + +
    • + +
    @@ -1020,16 +1226,12 @@

     
     
    -65
    -66
    -67
    +99

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 65
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 99
     
    -def password
    -  @password
    -end
    +attr_accessor :bind_dn, :password
    @@ -1040,7 +1242,7 @@

    - #password_policyObject (readonly) + #password_policyBoolean (readonly) @@ -1048,13 +1250,26 @@

    -

    Returns the value of attribute password_policy.

    +

    Whether to request LDAP Password Policy controls.

    +

    Returns:

    +
      + +
    • + + + (Boolean) + + + +
    • + +
    @@ -1062,16 +1277,12 @@

     
     
    -66
    -67
    -68
    +126

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 66
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 126
     
    -def password_policy
    -  @password_policy
    -end
    +attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
    @@ -1082,7 +1293,7 @@

    - #uidObject (readonly) + #uidString (readonly) @@ -1090,13 +1301,26 @@

    -

    Returns the value of attribute uid.

    +

    The user id attribute used for lookups (e.g., ‘sAMAccountName’)

    +

    Returns:

    +
      + +
    • + + + (String) + + + +
    • + +
    @@ -1104,16 +1328,12 @@

     
     
    -66
    -67
    -68
    +126

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 66
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 126
     
    -def uid
    -  @uid
    -end
    +attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response
    @@ -1129,7 +1349,7 @@

    Class Method Details

    - .validate(configuration = {}) ⇒ Object + .validate(configuration = {}) ⇒ void @@ -1137,13 +1357,35 @@

    - +

    This method returns an undefined value.

    Validate that a minimal configuration is present. Raises ArgumentError when required
    +keys are missing. This is a convenience to provide early feedback to callers.

    +

    Parameters:

    +
      + +
    • + + configuration + + + (Hash) + + + (defaults to: {}) + + + — +

      configuration hash passed to the adaptor

      +
      + +
    • +
    +

    Raises:

      @@ -1154,6 +1396,10 @@

      + — +

      when required keys are missing

      +
      +

    @@ -1164,20 +1410,20 @@

     
     
    -68
    -69
    -70
    -71
    -72
    -73
    -74
    -75
    -76
    -77
    -78
    +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 68
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 134
     
     def self.validate(configuration = {})
       message = []
    @@ -1204,7 +1450,7 @@ 

    Instance Method Details

    - #bind_as(args = {}) ⇒ Object + #bind_as(args = {}) ⇒ Net::LDAP::Entry, ... @@ -1216,11 +1462,114 @@

    :filter => “(mail=#user)”,
    :password => psw

    +

    Attempt to locate a user entry and bind as that entry using the supplied
    +password. Returns the entry on success, or false/nil on failure.

    +

    +

    Parameters:

    +
      + +
    • + + args + + + (Hash) + + + (defaults to: {}) + + + — +

      search and bind options forwarded to net-ldap’s search

      +
      + +
    • + +
    + + + + +

    Options Hash (args):

    +
      + +
    • + :filter + (Net::LDAP::Filter, String) + + + + + —

      LDAP filter to use

      +
      + +
    • + +
    • + :size + (Integer) + + + + + —

      maximum number of results to fetch

      +
      + +
    • + +
    • + :password + (String, Proc) + + + + + —

      a password string or callable returning a password

      +
      + +
    • + +
    + + +

    Returns:

    +
      + +
    • + + + (Net::LDAP::Entry, false, nil) + + + + — +

      the found entry on successful bind, otherwise false/nil

      +
      + +
    • + +
    +

    Raises:

    +
      +
    • + + + (ConnectionError) + + + + — +

      if the underlying LDAP search fails

      +
      + +
    • + +
    @@ -1228,57 +1577,57 @@

     
     
    -131
    -132
    -133
    -134
    -135
    -136
    -137
    -138
    -139
    -140
    -141
    -142
    -143
    -144
    -145
    -146
    -147
    -148
    -149
    -150
    -151
    -152
    -153
    -154
    -155
    -156
    -157
    -158
    -159
    -160
    -161
    -162
    -163
    -164
    -165
    -166
    -167
    -168
    -169
    -170
    -171
    -172
    -173
    -174
    -175
    -176
    -177
    -178
    +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263

    -
    # File 'lib/omniauth-ldap/adaptor.rb', line 131
    +      
    # File 'lib/omniauth-ldap/adaptor.rb', line 216
     
     def bind_as(args = {})
       result = false
    @@ -1338,7 +1687,7 @@ 

    diff --git a/docs/OmniAuth/LDAP/Adaptor/AuthenticationError.html b/docs/OmniAuth/LDAP/Adaptor/AuthenticationError.html index f5f0c99..2a8a858 100644 --- a/docs/OmniAuth/LDAP/Adaptor/AuthenticationError.html +++ b/docs/OmniAuth/LDAP/Adaptor/AuthenticationError.html @@ -101,8 +101,18 @@ +

    Overview

    +
    +

    Raised when authentication fails

    +
    +
    +
    + + +
    + @@ -114,7 +124,7 @@ diff --git a/docs/OmniAuth/LDAP/Adaptor/ConfigurationError.html b/docs/OmniAuth/LDAP/Adaptor/ConfigurationError.html index cff33a7..360cda2 100644 --- a/docs/OmniAuth/LDAP/Adaptor/ConfigurationError.html +++ b/docs/OmniAuth/LDAP/Adaptor/ConfigurationError.html @@ -101,8 +101,26 @@ +

    Overview

    +
    +

    Raised when configuration is invalid

    +
    +
    +
    + +
    +

    Examples:

    + + +
    raise ConfigurationError, 'missing base'
    + +
    + + +
    + @@ -114,7 +132,7 @@ diff --git a/docs/OmniAuth/LDAP/Adaptor/ConnectionError.html b/docs/OmniAuth/LDAP/Adaptor/ConnectionError.html index 3b8e84a..42ac8da 100644 --- a/docs/OmniAuth/LDAP/Adaptor/ConnectionError.html +++ b/docs/OmniAuth/LDAP/Adaptor/ConnectionError.html @@ -101,8 +101,18 @@ +

    Overview

    +
    +

    Raised on connection-related failures

    +
    +
    +
    + + +
    + @@ -114,7 +124,7 @@ diff --git a/docs/OmniAuth/LDAP/Adaptor/LdapError.html b/docs/OmniAuth/LDAP/Adaptor/LdapError.html index d722a2b..6257c0f 100644 --- a/docs/OmniAuth/LDAP/Adaptor/LdapError.html +++ b/docs/OmniAuth/LDAP/Adaptor/LdapError.html @@ -101,8 +101,25 @@ +

    Overview

    +
    +

    Generic adaptor error super-class

    +
    +
    +
    + + +

    See Also:

    +
      + +
    • classes that inherit from this class
    • + +
    + +
    + @@ -114,7 +131,7 @@ diff --git a/docs/OmniAuth/LDAP/Version.html b/docs/OmniAuth/LDAP/Version.html index 0318f8f..f94cc8b 100644 --- a/docs/OmniAuth/LDAP/Version.html +++ b/docs/OmniAuth/LDAP/Version.html @@ -83,7 +83,21 @@ +

    Overview

    +
    +

    Version namespace for the omniauth-ldap gem

    +

    This module contains the version constant used by rubygems and in code
    +consumers. It intentionally exposes VERSION both inside the Version
    +namespace and as OmniAuth::LDAP::VERSION for compatibility.

    + + +
    +
    +
    + + +

    Constant Summary @@ -93,7 +107,30 @@

    VERSION = - +
    +
    +

    Public semantic version for the gem

    + + +
    +
    +
    + +

    Returns:

    +
      + +
    • + + + (String) + + + +
    • + +
    + +
    "2.3.2"
    @@ -111,7 +148,7 @@

    diff --git a/docs/OmniAuth/Strategies.html b/docs/OmniAuth/Strategies.html index 3931c29..ac1d173 100644 --- a/docs/OmniAuth/Strategies.html +++ b/docs/OmniAuth/Strategies.html @@ -105,7 +105,7 @@

    Defined Under Namespace

    diff --git a/docs/OmniAuth/Strategies/LDAP.html b/docs/OmniAuth/Strategies/LDAP.html index e742c11..4fe48e3 100644 --- a/docs/OmniAuth/Strategies/LDAP.html +++ b/docs/OmniAuth/Strategies/LDAP.html @@ -104,7 +104,38 @@ +

    Overview

    +
    +

    LDAP OmniAuth strategy

    +

    This class implements the OmniAuth::Strategy interface and performs
    +LDAP authentication using an Adaptor object. It supports three
    +primary flows:

    + +
      +
    • Interactive login form (request_phase) where users POST username/password
    • +
    • Callback binding where the strategy attempts to bind as the user
    • +
    • Header-based SSO (trusted upstream) where a header identifies the user
    • +
    + +

    The mapping from LDAP attributes to resulting info fields is
    +configurable via the :mapping option. See map_user for the
    +mapping algorithm.

    + + +
    +
    +
    + + +

    See Also:

    +
      + +
    • OmniAuth::Strategy
    • + +
    + +

    Constant Summary @@ -114,12 +145,53 @@

    OMNIAUTH_GTE_V2 = - +
    +
    +

    Whether the loaded OmniAuth version is >= 2.0.0; used to set default request methods.

    + + +
    +
    +
    + +

    Returns:

    +
      + +
    • + + + (Boolean) + + + +
    • + +
    + +
    Gem::Version.new(OmniAuth::VERSION) >= Gem::Version.new("2.0.0")
    InvalidCredentialsError = - +
    +
    +

    Raised when credentials are invalid or the user cannot be authenticated.

    + + +
    +
    +
    + +
    +

    Examples:

    + + +
    raise InvalidCredentialsError, 'Invalid credentials'
    + +
    + + +
    Class.new(StandardError)
    @@ -143,7 +215,7 @@

  • - .map_user(mapper, object) ⇒ Object + .map_user(mapper, object) ⇒ Hash<String, Object> @@ -157,7 +229,7 @@

    -
    +

    Map LDAP attributes from the directory entry into a simple Hash used for the OmniAuth info hash according to the provided mapper.

  • @@ -189,7 +261,53 @@

    -
    +

    Callback phase: Authenticate user or perform header-based lookup.

    +
    + + + + +
  • + + + #filter(adaptor, username_override = nil) ⇒ Net::LDAP::Filter + + + + + + + + + + + + + +

    Build an LDAP filter for searching/binding the user.

    +
    + +
  • + + +
  • + + + #mapping ⇒ Hash<String, String|Array|Hash> + + + + + + + + + + + + + +

    Default mapping for converting LDAP attributes to OmniAuth info keys.

  • @@ -198,7 +316,7 @@

  • - #filter(adaptor, username_override = nil) ⇒ Object + #request_phase ⇒ Array @@ -212,7 +330,7 @@

    -
    +

    Request phase: Render the login form or redirect to callback for header-auth or direct POSTed credentials.

  • @@ -221,7 +339,7 @@

  • - #request_phase ⇒ Object + #title ⇒ String @@ -235,7 +353,7 @@

    -
    +

    Default title shown on the login form.

  • @@ -254,55 +372,127 @@

    Class Method Details

    - .map_user(mapper, object) ⇒ Object + .map_user(mapper, object) ⇒ Hash<String, Object> + + + + +

    +
    +

    Map LDAP attributes from the directory entry into a simple Hash used
    +for the OmniAuth info hash according to the provided mapper.

    + +

    The mapper supports three types of values:

    +
      +
    • String: a single attribute name. The method will call the attribute
      +reader (downcased symbol) on the object and take the first value.
    • +
    • Array: iterate values and pick the first attribute that exists on the object.
    • +
    • Hash: a mapping of a pattern string to an array of attribute-name lists
      +where each %<n> placeholder in the pattern will be substituted by the
      +first available attribute from the corresponding list.
    • +
    + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + mapper + + + (Hash) + + + + — +

      mapping configuration (see option :mapping)

      +
      + +
    • +
    • + + object + + + (#respond_to?, #[]) + + + + — +

      directory entry (commonly a Net::LDAP::Entry or similar)

      +
      + +
    • + +
    +

    Returns:

    +
      + +
    • + + + (Hash<String, Object>) + + + + — +

      the mapped user info hash

      +
      + +
    • -

    + + +
     
     
    -142
    -143
    -144
    -145
    -146
    -147
    -148
    -149
    -150
    -151
    -152
    -153
    -154
    -155
    -156
    -157
    -158
    -159
    -160
    -161
    -162
    -163
    -164
    -165
    -166
    -167
    -168
    -169
    -170
    -171
    -172
    -173
    -174
    -175
    +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284
    -
    # File 'lib/omniauth/strategies/ldap.rb', line 142
    +      
    # File 'lib/omniauth/strategies/ldap.rb', line 251
     
     def map_user(mapper, object)
       user = {}
    @@ -358,54 +548,109 @@ 

    -

    +
    +
    +

    Callback phase: Authenticate user or perform header-based lookup

    + +

    This method executes on the callback URL and implements the main
    +authentication logic. There are two primary paths:

    + +
      +
    • Header-based lookup: when options[:header_auth] is enabled and a header value is present,
      +we perform a read-only directory lookup for the user and, if found, map attributes and finish.
    • +
    • Password bind: when username/password are provided we attempt a bind as the user using the adaptor.
    • +
    + +

    Errors raised by the LDAP adaptor are captured and turned into OmniAuth failures.

    + + +
    +
    +
    + +

    Returns:

    +
      + +
    • + + + (Object) + + + + — +

      result of calling super from the OmniAuth::Strategy chain

      +
      + +
    • + +
    +

    Raises:

    + + +
     
     
    -81
    -82
    -83
    -84
    -85
    -86
    -87
    -88
    -89
    -90
    -91
    -92
    -93
    -94
    -95
    -96
    -97
    -98
    -99
    -100
    -101
    -102
    -103
    -104
    -105
    -106
    -107
    -108
    -109
    -110
    -111
    -112
    -113
    -114
    -115
    -116
    -117
    -118
    -119
    +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199
    -
    # File 'lib/omniauth/strategies/ldap.rb', line 81
    +      
    # File 'lib/omniauth/strategies/ldap.rb', line 161
     
     def callback_phase
       @adaptor = OmniAuth::LDAP::Adaptor.new(@options)
    @@ -454,30 +699,97 @@ 

    - #filter(adaptor, username_override = nil) ⇒ Object + #filter(adaptor, username_override = nil) ⇒ Net::LDAP::Filter + + +

    +
    +

    Build an LDAP filter for searching/binding the user.

    +

    If the adaptor has a custom filter option set it will be used (with
    +interpolation of %{username}). Otherwise a simple equality filter for
    +the configured uid attribute is used.

    + + +
    +
    +
    +

    Parameters:

    +
      + +
    • + + adaptor + + + (OmniAuth::LDAP::Adaptor) + + + + — +

      the adaptor used to build connection/filters

      +
      + +
    • -

    +
  • + + username_override + + + (String, nil) + + + (defaults to: nil) + + + — +

    optional username to build the filter for (defaults to request username)

    +
    + +
  • + + + +

    Returns:

    +
      + +
    • + + + (Net::LDAP::Filter) + + + + — +

      the constructed filter object

      +
      + +
    • + +
    + +
     
     
    -121
    -122
    -123
    -124
    -125
    -126
    -127
    -128
    -129
    +210 +211 +212 +213 +214 +215 +216 +217 +218
    -
    # File 'lib/omniauth/strategies/ldap.rb', line 121
    +      
    # File 'lib/omniauth/strategies/ldap.rb', line 210
     
     def filter(adaptor, username_override = nil)
       flt = adaptor.filter
    @@ -494,29 +806,50 @@ 

    -

    +

    - #request_phaseObject + #mappingHash<String, String|Array|Hash> + + +

    +
    +

    Default mapping for converting LDAP attributes to OmniAuth info keys.
    +Keys are the resulting info hash keys (strings). Values may be:

    +
      +
    • String: single LDAP attribute name
    • +
    • Array: list of attribute names in priority order
    • +
    • Hash: pattern mapping where pattern keys contain % placeholders +that are substituted from a list of possible attribute names
    • +
    + +
    +
    +
    -

    +

    Returns:

    +
      + +
    • + + + (Hash<String, String|Array|Hash>) + + + +
    • + +
    + +
    + +
     
     
    -53
    -54
    -55
    -56
    -57
    -58
    -59
    -60
    -61
     62
     63
     64
    @@ -531,13 +864,111 @@ 

    73 74 75 -76 -77 -78 -79

    +76
    -
    # File 'lib/omniauth/strategies/ldap.rb', line 53
    +      
    # File 'lib/omniauth/strategies/ldap.rb', line 62
    +
    +option :mapping, {
    +  "name" => "cn",
    +  "first_name" => "givenName",
    +  "last_name" => "sn",
    +  "email" => ["mail", "email", "userPrincipalName"],
    +  "phone" => ["telephoneNumber", "homePhone", "facsimileTelephoneNumber"],
    +  "mobile" => ["mobile", "mobileTelephoneNumber"],
    +  "nickname" => ["uid", "userid", "sAMAccountName"],
    +  "title" => "title",
    +  "location" => {"%0, %1, %2, %3 %4" => [["address", "postalAddress", "homePostalAddress", "street", "streetAddress"], ["l"], ["st"], ["co"], ["postOfficeBox"]]},
    +  "uid" => "dn",
    +  "url" => ["wwwhomepage"],
    +  "image" => "jpegPhoto",
    +  "description" => "description",
    +}
    +
    + + +
    +

    + + #request_phaseArray + + + + + +

    +
    +

    Request phase: Render the login form or redirect to callback for header-auth or direct POSTed credentials

    + +

    This will behave differently depending on OmniAuth version and request method:

    +
      +
    • For OmniAuth >= 2.0 a GET to /auth/:provider should return 404 (so we return a 404 for GET requests).
    • +
    • If header-based SSO is enabled and a trusted header is present we immediately redirect to the callback.
    • +
    • If credentials are POSTed directly to /auth/:provider we redirect to the callback so the test helpers
      +that populate env['omniauth.auth'] can operate on the callback request.
    • +
    + + +
    +
    +
    + +

    Returns:

    +
      + +
    • + + + (Array) + + + + — +

      A Rack response triple from the login form or redirect.

      +
      + +
    • + +
    + +
    + + +
    +
    +
    +
    +120
    +121
    +122
    +123
    +124
    +125
    +126
    +127
    +128
    +129
    +130
    +131
    +132
    +133
    +134
    +135
    +136
    +137
    +138
    +139
    +140
    +141
    +142
    +143
    +144
    +145
    +146
    +
    +
    # File 'lib/omniauth/strategies/ldap.rb', line 120
     
     def request_phase
       # OmniAuth >= 2.0 expects the request phase to be POST-only for /auth/:provider.
    @@ -569,6 +1000,55 @@ 

    +
    + +
    +

    + + #titleString + + + + + +

    +
    +

    Default title shown on the login form.

    + + +
    +
    +
    + +

    Returns:

    +
      + +
    • + + + (String) + + + +
    • + +
    + +
    + + + + +
    +
    +
    +
    +80
    +
    +
    # File 'lib/omniauth/strategies/ldap.rb', line 80
    +
    +option :title, "LDAP Authentication"
    +
    @@ -576,7 +1056,7 @@

    diff --git a/docs/_index.html b/docs/_index.html index f383b5e..f8b8038 100644 --- a/docs/_index.html +++ b/docs/_index.html @@ -87,6 +87,30 @@

    File Listing

  • CITATION
  • +
  • CHANGELOG
  • + + +
  • CODE_OF_CONDUCT
  • + + +
  • CONTRIBUTING
  • + + +
  • FUNDING
  • + + +
  • README
  • + + +
  • RUBOCOP
  • + + +
  • SECURITY
  • + + +
  • LICENSE
  • + +
  • omniauth-ldap-2.3.1.gem
  • @@ -260,7 +284,7 @@

    Namespace Listing A-Z

    diff --git a/docs/file.CHANGELOG.html b/docs/file.CHANGELOG.html index 0333386..bf76fab 100644 --- a/docs/file.CHANGELOG.html +++ b/docs/file.CHANGELOG.html @@ -74,8 +74,16 @@

    Added

    +
      +
    • Documentation cleanup & updates
    • +
    +

    Changed

    +
      +
    • kettle-dev v1.1.54
    • +
    +

    Deprecated

    Removed

    @@ -340,7 +348,7 @@

    diff --git a/docs/file.CITATION.html b/docs/file.CITATION.html index 28f7892..5f34e11 100644 --- a/docs/file.CITATION.html +++ b/docs/file.CITATION.html @@ -82,7 +82,7 @@ diff --git a/docs/file.CODE_OF_CONDUCT.html b/docs/file.CODE_OF_CONDUCT.html index 3d2a52b..6097bfa 100644 --- a/docs/file.CODE_OF_CONDUCT.html +++ b/docs/file.CODE_OF_CONDUCT.html @@ -191,7 +191,7 @@

    Attribution

    diff --git a/docs/file.CONTRIBUTING.html b/docs/file.CONTRIBUTING.html index 56776c1..a6fc6e3 100644 --- a/docs/file.CONTRIBUTING.html +++ b/docs/file.CONTRIBUTING.html @@ -85,14 +85,14 @@

    Help out!

    Executables vs Rake tasks

    -

    Executables shipped by dependencies, such as omniauth-ldap, and stone_checksums, are available
    +

    Executables shipped by dependencies, such as kettle-dev, and stone_checksums, are available
    after running bin/setup. These include:

    • gem_checksums
    • kettle-changelog
    • kettle-commit-msg
    • -
    • omniauth-ldap-setup
    • +
    • kettle-dev-setup
    • kettle-dvcs
    • kettle-pre-release
    • kettle-readme-backers
    • @@ -137,7 +137,13 @@

      Environment Variables for L
      • SKIP_GEM_SIGNING: If set, skip gem signing during build/release
      • GEM_CERT_USER: Username for selecting your public cert in certs/<USER>.pem (defaults to $USER)
      • -
      • SOURCE_DATE_EPOCH: Reproducible build timestamp. kettle-release will set this automatically for the session.
      • +
      • SOURCE_DATE_EPOCH: Reproducible build timestamp. +
          +
        • +kettle-release will set this automatically for the session.
        • +
        • Not needed on bundler >= 2.7.0, as reproducible builds have become the default.
        • +
        +

      Git hooks and commit message helpers (exe/kettle-commit-msg)

      @@ -243,6 +249,7 @@

      Automated process

    • Update version.rb to contain the correct version-to-be-released.
    • Run bundle exec kettle-changelog.
    • Run bundle exec kettle-release.
    • +
    • Stay awake and monitor the release process for any errors, and answer any prompts.
    • Manual process

      @@ -295,7 +302,7 @@

      Manual process

      diff --git a/docs/file.FUNDING.html b/docs/file.FUNDING.html index abf9548..cb07afb 100644 --- a/docs/file.FUNDING.html +++ b/docs/file.FUNDING.html @@ -65,15 +65,15 @@

      Sponsor Me on Github Liberapay Goal Progress Donate on PayPal

      -

      Buy me a coffee Donate on Polar Donate to my FLOSS or refugee efforts at ko-fi.com Donate to my FLOSS or refugee efforts using Patreon

      +

      Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

      -

      🤑 Request for Help

      +

      🤑 A request for help

      Maintainers have teeth and need to pay their dentists.
      -After getting laid off in an RIF in March and filled with many dozens of rejections,
      -I’m now spending ~60+ hours a week building open source tools.
      +After getting laid off in an RIF in March, and encountering difficulty finding a new one,
      +I began spending most of my time building open source tools.
      I’m hoping to be able to pay for my kids’ health insurance this month,
      so if you value the work I am doing, I need your support.
      Please consider sponsoring me or the project.

      @@ -82,18 +82,13 @@

      🤑 Request for Help

      Live Chat on Discord

      -

      To say “thanks for maintaining such a great tool” ☝️ Join the Discord or 👇️ send money.

      +

      To say “thanks!” ☝️ Join the Discord or 👇️ send money.

      -

      Sponsor me on GitHub Sponsors 💌 Sponsor me on Liberapay 💌 Donate on PayPal

      +

      Sponsor me on GitHub Sponsors 💌 Sponsor me on Liberapay 💌 Donate on PayPal

      Another Way to Support Open Source Software

      -
      -

      How wonderful it is that nobody need wait a single moment before starting to improve the world.

      -—Anne Frank

      -
      - -

      I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions — totaling 79 hours of FLOSS coding over just the past seven days, a pretty regular week for me. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats).

      +

      I’m driven by a passion to foster a thriving open-source community – a space where people can tackle complex problems, no matter how small. Revitalizing libraries that have fallen into disrepair, and building new libraries focused on solving real-world challenges, are my passions. I was recently affected by layoffs, and the tech jobs market is unwelcoming. I’m reaching out here because your support would significantly aid my efforts to provide for my family, and my farm (11 🐔 chickens, 2 🐶 dogs, 3 🐰 rabbits, 8 🐈‍ cats).

      If you work at a company that uses my work, please encourage them to support me as a corporate sponsor. My work on gems you use might show up in bundle fund.

      @@ -104,7 +99,7 @@

      Another Way to Support Open diff --git a/docs/file.LICENSE.html b/docs/file.LICENSE.html index 00ba96c..c0f745f 100644 --- a/docs/file.LICENSE.html +++ b/docs/file.LICENSE.html @@ -60,7 +60,7 @@
      MIT License

      Copyright (c) 2025 Peter H. Boling, and omniauth-ldap contributors
      Copyright (c) 2014 David Benko
      Copyright (c) 2011 by Ping Yu and Intridea, Inc.

      Permission is hereby granted, free of charge, to any person obtaining
      a copy of this software and associated documentation files (the
      "Software"), to deal in the Software without restriction, including
      without limitation the rights to use, copy, modify, merge, publish,
      distribute, sublicense, and/or sell copies of the Software, and to
      permit persons to whom the Software is furnished to do so, subject to
      the following conditions:

      The above copyright notice and this permission notice shall be
      included in all copies or substantial portions of the Software.

      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      diff --git a/docs/file.README.html b/docs/file.README.html index bee0537..ed0c75f 100644 --- a/docs/file.README.html +++ b/docs/file.README.html @@ -97,11 +97,11 @@

    -

    Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0 ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5 omniauth Logo (presumed to be) by tomeara, (presumed to be) MIT License

    +

    Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0 ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5 omniauth-ldap Logo by Aboling0, CC BY-SA 4.0

    📁 OmniAuth LDAP

    -

    Version GitHub tag (latest SemVer) License: MIT Downloads Rank Open Source Helpers CodeCov Test Coverage Coveralls Test Coverage CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby Deps Locked Deps Unlocked CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL Apache SkyWalking Eyes License Compatibility Check

    +

    Version GitHub tag (latest SemVer) License: MIT Downloads Rank Open Source Helpers CodeCov Test Coverage Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby Deps Locked Deps Unlocked CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL Apache SkyWalking Eyes License Compatibility Check

    if ci_badges.map(&:color).detect { it != "green"} ☝️ let me know, as I may have missed the discord notification.

    @@ -143,51 +143,6 @@

    🌻 Synopsis

    All of the listed options are required, with the exception of :title, :name_proc, :bind_dn, and :password.

    -

    TLS certificate verification

    - -

    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.

    - -
      -
    • Secure by default: you do not need to set anything extra to verify the LDAP server certificate.
    • -
    • To customize trust or ciphers, supply your own tls_options, which are merged over the safe defaults.
    • -
    • If you truly need to skip verification (not recommended), set disable_verify_certificates: true.
    • -
    - -

    Examples:

    - -
    # Verify server certs (default behavior)
    -use OmniAuth::Strategies::LDAP,
    -  host: ENV["LDAP_HOST"],
    -  port: 636,
    -  encryption: "ssl",  # or "tls"
    -  base: "dc=example,dc=com",
    -  uid:  "uid"
    -
    -# Use a private CA bundle and restrict protocol/ciphers
    -use OmniAuth::Strategies::LDAP,
    -  host: ENV["LDAP_HOST"],
    -  port: 636,
    -  encryption: "ssl",
    -  base: "dc=example,dc=com",
    -  uid:  "uid",
    -  tls_options: {
    -    ca_file: "/etc/ssl/private/my_org_ca.pem",
    -    ssl_version: "TLSv1_2",
    -    ciphers: ["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"],
    -  }
    -
    -# Opt out of verification (NOT recommended – use only in trusted test/dev scenarios)
    -use OmniAuth::Strategies::LDAP,
    -  host: ENV["LDAP_HOST"],
    -  port: 636,
    -  encryption: "ssl",
    -  base: "dc=example,dc=com",
    -  uid:  "uid",
    -  disable_verify_certificates: true
    -
    - -

    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.

    -

    💡 Info you can shake a stick at

    @@ -233,13 +188,13 @@

    💡 Info you can shake a stick at

    @@ -289,6 +244,69 @@

    Compatibility

    Source -Source on Github.com The best SHA: dQw4w9WgXcQ! +Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ!
    Documentation -Current release on RubyDoc.info YARD on Galtzo.com Maintainer Blog GitHub Wiki +Current release on RubyDoc.info YARD on Galtzo.com Maintainer Blog GitLab Wiki GitHub Wiki
    +

    Federated DVCS

    + +
    + Find this repo on federated forges (Coming soon!) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Federated DVCS RepositoryStatusIssuesPRsWikiCIDiscussions
    🧪 omniauth/omniauth-ldap on GitLab +The Truth💚💚💚🐭 Tiny Matrix
    🧊 omniauth/omniauth-ldap on CodeBerg +An Ethical Mirror (Donate)💚💚⭕️ No Matrix
    🐙 omniauth/omniauth-ldap on GitHub +Another Mirror💚💚💚💯 Full Matrix💚
    🎮️ Discord Server +Live Chat on DiscordLet’stalkaboutthislibrary!
    + +
    +

    Enterprise Support Tidelift

    @@ -297,19 +315,24 @@

    Enterprise Support Get help from me on Tidelift

    -- 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies -- 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar] -- 💡Tidelift pays maintainers to maintain the software you depend on!
    📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers +
      +
    • 💡Subscribe for support guarantees covering all your FLOSS dependencies
    • +
    • 💡Tidelift is part of Sonar +
    • +
    • 💡Tidelift pays maintainers to maintain the software you depend on!
      📊@Pointy Haired Boss: An enterprise support subscription is “never gonna let you down”, and supports open source maintainers
    • +
    -Alternatively: +

    Alternatively:

    -- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] -- [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] -- [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] +
      +
    • Live Chat on Discord
    • +
    • Get help from me on Upwork
    • +
    • Get help from me on Codementor
    • +
    @@ -330,33 +353,30 @@

    🔒 Secure Installation

    For Medium or High Security Installations -This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by -[stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with -by following the instructions below. +

    This gem is cryptographically signed, and has verifiable SHA-256 and SHA-512 checksums by +stone_checksums. Be sure the gem you install hasn’t been tampered with +by following the instructions below.

    -Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate: +

    Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:

    -```console -gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem) -``` +
    gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
    +
    -You only need to do that once. Then proceed to install with: +

    You only need to do that once. Then proceed to install with:

    -```console -gem install omniauth-ldap -P HighSecurity -``` +
    gem install omniauth-ldap -P HighSecurity
    +
    -The `HighSecurity` trust profile will verify signed gems, and not allow the installation of unsigned dependencies. +

    The HighSecurity trust profile will verify signed gems, and not allow the installation of unsigned dependencies.

    -If you want to up your security game full-time: +

    If you want to up your security game full-time:

    -```console -bundle config set --global trust-policy MediumSecurity -``` +
    bundle config set --global trust-policy MediumSecurity
    +
    -`MediumSecurity` instead of `HighSecurity` is necessary if not all the gems you use are signed. +

    MediumSecurity instead of HighSecurity is necessary if not all the gems you use are signed.

    -NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine. +

    NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.

    @@ -441,8 +461,8 @@

    Auth Hash UID vs LDAP :uid (

    Why DN for auth.uid?

      -
    • DN is the canonical, globally unique identifier for an LDAP entry and is always present in search results. See LDAPv3 and DN syntax: RFC 4511 (LDAP protocol) and RFC 4514 (String Representation of Distinguished Names).
    • -
    • Attributes like uid (defined in RFC 4519) or sAMAccountName (Active Directory–specific) may be absent, duplicated across parts of the DIT, or vary between directories. Using DN ensures consistent behavior across AD, OpenLDAP, and other servers.
    • +
    • DN is the canonical, globally unique identifier for an LDAP entry and is always present in search results. See LDAPv3 and DN syntax: [RFC 4511][rfc4511] (LDAP protocol) and [RFC 4514][rfc4514] (String Representation of Distinguished Names).
    • +
    • Attributes like uid (defined in [RFC 4519][rfc4519]) or sAMAccountName (Active Directory–specific) may be absent, duplicated across parts of the DIT, or vary between directories. Using DN ensures consistent behavior across AD, OpenLDAP, and other servers.
    • This trade-off favors cross-directory interoperability and stability for apps that need a unique identifier.
    @@ -865,7 +885,7 @@

    Trusted header SSO (REMOTE_U

    🦷 FLOSS Funding

    -

    While these tools are free software and will always be, the project would benefit immensely from some funding.
    +

    While omniauth tools are free software and will always be, the project would benefit immensely from some funding.
    Raising a monthly budget of… “dollars” would make the project more sustainable.

    We welcome both individual and corporate sponsors! We also offer a
    @@ -875,7 +895,7 @@

    🦷 FLOSS Funding

    If you’re working in a company that’s making significant use of omniauth tools we’d
    appreciate it if you suggest to your company to become a omniauth sponsor.

    -

    You can support me in development of OmniAuth tools via
    +

    You can support the development of omniauth tools via
    GitHub Sponsors,
    Liberapay,
    PayPal,
    @@ -904,7 +924,7 @@

    Another way to support open-sourceFloss-Funding.dev: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags

    -

    Sponsor Me on Github Liberapay Goal Progress Donate on PayPal Buy me a coffee Donate on Polar Donate to my FLOSS or refugee efforts at ko-fi.com Donate to my FLOSS or refugee efforts using Patreon

    +

    Sponsor Me on Github Liberapay Goal Progress Donate on PayPal Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

    🔐 Security

    @@ -930,6 +950,8 @@

    Code Coverage

    Coveralls Test Coverage

    +

    QLTY Test Coverage

    +

    🪇 Code of Conduct

    Everyone interacting with this project’s codebases, issue trackers,
    @@ -941,6 +963,8 @@

    🌈 Contributors

    Made with contributors-img.

    +

    Also see GitLab Contributors: https://gitlab.com/omniauth/omniauth-ldap/-/graphs/main

    +
    ⭐️ Star History @@ -978,16 +1002,17 @@

    📌 Versioning

    -📌 Is "Platform Support" part of the public API? More details inside. + 📌 Is "Platform Support" part of the public API? More details inside. -SemVer should, IMO, but doesn't explicitly, say that dropping support for specific Platforms -is a *breaking change* to an API. -It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless. +

    SemVer should, IMO, but doesn’t explicitly, say that dropping support for specific Platforms +is a breaking change to an API, and for that reason the bike shedding is endless.

    -To get a better understanding of how SemVer is intended to work over a project's lifetime, -read this article from the creator of SemVer: +

    To get a better understanding of how SemVer is intended to work over a project’s lifetime, +read this article from the creator of SemVer:

    -- ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred] +
    @@ -1003,7 +1028,7 @@
    • - Copyright (c) 2025 Peter H. Boling, of + Copyright (c) 2023, 2025 Peter H. Boling, of Galtzo.com @@ -1011,12 +1036,6 @@ , and omniauth-ldap contributors.
    • -
    • - Copyright (c) 2014 David Benko -
    • -
    • - Copyright (c) 2011 by Ping Yu and Intridea, Inc. -

    🤑 A request for help

    @@ -1043,7 +1062,7 @@

    Please give the project a star ⭐ ♥ diff --git a/docs/file.REEK.html b/docs/file.REEK.html index 7c4e256..dc28491 100644 --- a/docs/file.REEK.html +++ b/docs/file.REEK.html @@ -61,7 +61,7 @@ diff --git a/docs/file.RUBOCOP.html b/docs/file.RUBOCOP.html index 8f57ad3..cd6380a 100644 --- a/docs/file.RUBOCOP.html +++ b/docs/file.RUBOCOP.html @@ -161,7 +161,7 @@

    Benefits of rubocop_gradual

    diff --git a/docs/file.SECURITY.html b/docs/file.SECURITY.html index 468e000..eb90fe7 100644 --- a/docs/file.SECURITY.html +++ b/docs/file.SECURITY.html @@ -86,12 +86,12 @@

    Additional Support

    If you are interested in support for versions older than the latest release,
    please consider sponsoring the project / maintainer @ https://liberapay.com/pboling/donate,
    -or find other sponsorship links in the README.

    +or find other sponsorship links in the README.

    diff --git a/docs/file.adaptor.html b/docs/file.adaptor.html index 00114a8..a2beb6b 100644 --- a/docs/file.adaptor.html +++ b/docs/file.adaptor.html @@ -131,7 +131,7 @@ diff --git a/docs/file.ldap.html b/docs/file.ldap.html index bb28263..8d7c3d3 100644 --- a/docs/file.ldap.html +++ b/docs/file.ldap.html @@ -94,7 +94,7 @@ diff --git a/docs/file.net-ldap.html b/docs/file.net-ldap.html index 2b8cbfb..586e1ad 100644 --- a/docs/file.net-ldap.html +++ b/docs/file.net-ldap.html @@ -95,7 +95,7 @@ diff --git a/docs/file.net-ntlm.html b/docs/file.net-ntlm.html index bd8b82e..7e02791 100644 --- a/docs/file.net-ntlm.html +++ b/docs/file.net-ntlm.html @@ -76,7 +76,7 @@ diff --git a/docs/file.omniauth-ldap-2.3.1.gem.html b/docs/file.omniauth-ldap-2.3.1.gem.html index f42e8e8..ed3c42f 100644 --- a/docs/file.omniauth-ldap-2.3.1.gem.html +++ b/docs/file.omniauth-ldap-2.3.1.gem.html @@ -61,7 +61,7 @@ diff --git a/docs/file.omniauth-ldap-2.3.2.gem.html b/docs/file.omniauth-ldap-2.3.2.gem.html index ef1c636..f6dc634 100644 --- a/docs/file.omniauth-ldap-2.3.2.gem.html +++ b/docs/file.omniauth-ldap-2.3.2.gem.html @@ -61,7 +61,7 @@ diff --git a/docs/file.omniauth-ldap.html b/docs/file.omniauth-ldap.html index bcf14f4..b4aea69 100644 --- a/docs/file.omniauth-ldap.html +++ b/docs/file.omniauth-ldap.html @@ -70,7 +70,7 @@

    Th diff --git a/docs/file.sasl.html b/docs/file.sasl.html index 7b0b64a..1fafdfe 100644 --- a/docs/file.sasl.html +++ b/docs/file.sasl.html @@ -71,7 +71,7 @@ diff --git a/docs/file.version.html b/docs/file.version.html index 10c4362..dc979da 100644 --- a/docs/file.version.html +++ b/docs/file.version.html @@ -69,7 +69,7 @@ diff --git a/docs/file_list.html b/docs/file_list.html index ba59373..02c1227 100644 --- a/docs/file_list.html +++ b/docs/file_list.html @@ -92,6 +92,46 @@

    File List

    +
  • + +
  • + + +
  • + +
  • + + +
  • + +
  • + + +
  • + +
  • + + +
  • + +
  • + + +
  • + +
  • + + +
  • + +
  • + + +
  • + +
  • + +
  • diff --git a/docs/index.html b/docs/index.html index 6c9eaba..181cee7 100644 --- a/docs/index.html +++ b/docs/index.html @@ -97,11 +97,11 @@
    -

    Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0 ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5 omniauth Logo (presumed to be) by tomeara, (presumed to be) MIT License

    +

    Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0 ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5 omniauth-ldap Logo by Aboling0, CC BY-SA 4.0

    📁 OmniAuth LDAP

    -

    Version GitHub tag (latest SemVer) License: MIT Downloads Rank Open Source Helpers CodeCov Test Coverage Coveralls Test Coverage CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby Deps Locked Deps Unlocked CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL Apache SkyWalking Eyes License Compatibility Check

    +

    Version GitHub tag (latest SemVer) License: MIT Downloads Rank Open Source Helpers CodeCov Test Coverage Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current CI Truffle Ruby CI JRuby Deps Locked Deps Unlocked CI Supported CI Legacy CI Unsupported CI Ancient CI Test Coverage CI Style CodeQL Apache SkyWalking Eyes License Compatibility Check

    if ci_badges.map(&:color).detect { it != "green"} ☝️ let me know, as I may have missed the discord notification.

    @@ -143,51 +143,6 @@

    🌻 Synopsis

    All of the listed options are required, with the exception of :title, :name_proc, :bind_dn, and :password.

    -

    TLS certificate verification

    - -

    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.

    - -
      -
    • Secure by default: you do not need to set anything extra to verify the LDAP server certificate.
    • -
    • To customize trust or ciphers, supply your own tls_options, which are merged over the safe defaults.
    • -
    • If you truly need to skip verification (not recommended), set disable_verify_certificates: true.
    • -
    - -

    Examples:

    - -
    # Verify server certs (default behavior)
    -use OmniAuth::Strategies::LDAP,
    -  host: ENV["LDAP_HOST"],
    -  port: 636,
    -  encryption: "ssl",  # or "tls"
    -  base: "dc=example,dc=com",
    -  uid:  "uid"
    -
    -# Use a private CA bundle and restrict protocol/ciphers
    -use OmniAuth::Strategies::LDAP,
    -  host: ENV["LDAP_HOST"],
    -  port: 636,
    -  encryption: "ssl",
    -  base: "dc=example,dc=com",
    -  uid:  "uid",
    -  tls_options: {
    -    ca_file: "/etc/ssl/private/my_org_ca.pem",
    -    ssl_version: "TLSv1_2",
    -    ciphers: ["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"],
    -  }
    -
    -# Opt out of verification (NOT recommended – use only in trusted test/dev scenarios)
    -use OmniAuth::Strategies::LDAP,
    -  host: ENV["LDAP_HOST"],
    -  port: 636,
    -  encryption: "ssl",
    -  base: "dc=example,dc=com",
    -  uid:  "uid",
    -  disable_verify_certificates: true
    -
    - -

    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.

    -

    💡 Info you can shake a stick at

    @@ -233,13 +188,13 @@

    💡 Info you can shake a stick at

    @@ -289,6 +244,69 @@

    Compatibility

    Source -Source on Github.com The best SHA: dQw4w9WgXcQ! +Source on GitLab.com Source on CodeBerg.org Source on Github.com The best SHA: dQw4w9WgXcQ!
    Documentation -Current release on RubyDoc.info YARD on Galtzo.com Maintainer Blog GitHub Wiki +Current release on RubyDoc.info YARD on Galtzo.com Maintainer Blog GitLab Wiki GitHub Wiki
    +

    Federated DVCS

    + +
    + Find this repo on federated forges (Coming soon!) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Federated DVCS RepositoryStatusIssuesPRsWikiCIDiscussions
    🧪 omniauth/omniauth-ldap on GitLab +The Truth💚💚💚🐭 Tiny Matrix
    🧊 omniauth/omniauth-ldap on CodeBerg +An Ethical Mirror (Donate)💚💚⭕️ No Matrix
    🐙 omniauth/omniauth-ldap on GitHub +Another Mirror💚💚💚💯 Full Matrix💚
    🎮️ Discord Server +Live Chat on DiscordLet’stalkaboutthislibrary!
    + +
    +

    Enterprise Support Tidelift

    @@ -297,19 +315,24 @@

    Enterprise Support Get help from me on Tidelift

    -- 💡Subscribe for support guarantees covering _all_ your FLOSS dependencies -- 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar] -- 💡Tidelift pays maintainers to maintain the software you depend on!
    📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers +
      +
    • 💡Subscribe for support guarantees covering all your FLOSS dependencies
    • +
    • 💡Tidelift is part of Sonar +
    • +
    • 💡Tidelift pays maintainers to maintain the software you depend on!
      📊@Pointy Haired Boss: An enterprise support subscription is “never gonna let you down”, and supports open source maintainers
    • +
    -Alternatively: +

    Alternatively:

    -- [![Live Chat on Discord][✉️discord-invite-img-ftb]][✉️discord-invite] -- [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] -- [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] +
      +
    • Live Chat on Discord
    • +
    • Get help from me on Upwork
    • +
    • Get help from me on Codementor
    • +
    @@ -330,33 +353,30 @@

    🔒 Secure Installation

    For Medium or High Security Installations -This gem is cryptographically signed, and has verifiable [SHA-256 and SHA-512][💎SHA_checksums] checksums by -[stone_checksums][💎stone_checksums]. Be sure the gem you install hasn’t been tampered with -by following the instructions below. +

    This gem is cryptographically signed, and has verifiable SHA-256 and SHA-512 checksums by +stone_checksums. Be sure the gem you install hasn’t been tampered with +by following the instructions below.

    -Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate: +

    Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:

    -```console -gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem) -``` +
    gem cert --add <(curl -Ls https://raw.github.com/galtzo-floss/certs/main/pboling.pem)
    +
    -You only need to do that once. Then proceed to install with: +

    You only need to do that once. Then proceed to install with:

    -```console -gem install omniauth-ldap -P HighSecurity -``` +
    gem install omniauth-ldap -P HighSecurity
    +
    -The `HighSecurity` trust profile will verify signed gems, and not allow the installation of unsigned dependencies. +

    The HighSecurity trust profile will verify signed gems, and not allow the installation of unsigned dependencies.

    -If you want to up your security game full-time: +

    If you want to up your security game full-time:

    -```console -bundle config set --global trust-policy MediumSecurity -``` +
    bundle config set --global trust-policy MediumSecurity
    +
    -`MediumSecurity` instead of `HighSecurity` is necessary if not all the gems you use are signed. +

    MediumSecurity instead of HighSecurity is necessary if not all the gems you use are signed.

    -NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine. +

    NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.

    @@ -441,8 +461,8 @@

    Auth Hash UID vs LDAP :uid (

    Why DN for auth.uid?

      -
    • DN is the canonical, globally unique identifier for an LDAP entry and is always present in search results. See LDAPv3 and DN syntax: RFC 4511 (LDAP protocol) and RFC 4514 (String Representation of Distinguished Names).
    • -
    • Attributes like uid (defined in RFC 4519) or sAMAccountName (Active Directory–specific) may be absent, duplicated across parts of the DIT, or vary between directories. Using DN ensures consistent behavior across AD, OpenLDAP, and other servers.
    • +
    • DN is the canonical, globally unique identifier for an LDAP entry and is always present in search results. See LDAPv3 and DN syntax: [RFC 4511][rfc4511] (LDAP protocol) and [RFC 4514][rfc4514] (String Representation of Distinguished Names).
    • +
    • Attributes like uid (defined in [RFC 4519][rfc4519]) or sAMAccountName (Active Directory–specific) may be absent, duplicated across parts of the DIT, or vary between directories. Using DN ensures consistent behavior across AD, OpenLDAP, and other servers.
    • This trade-off favors cross-directory interoperability and stability for apps that need a unique identifier.
    @@ -865,7 +885,7 @@

    Trusted header SSO (REMOTE_U

    🦷 FLOSS Funding

    -

    While these tools are free software and will always be, the project would benefit immensely from some funding.
    +

    While omniauth tools are free software and will always be, the project would benefit immensely from some funding.
    Raising a monthly budget of… “dollars” would make the project more sustainable.

    We welcome both individual and corporate sponsors! We also offer a
    @@ -875,7 +895,7 @@

    🦷 FLOSS Funding

    If you’re working in a company that’s making significant use of omniauth tools we’d
    appreciate it if you suggest to your company to become a omniauth sponsor.

    -

    You can support me in development of OmniAuth tools via
    +

    You can support the development of omniauth tools via
    GitHub Sponsors,
    Liberapay,
    PayPal,
    @@ -904,7 +924,7 @@

    Another way to support open-sourceFloss-Funding.dev: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags

    -

    Sponsor Me on Github Liberapay Goal Progress Donate on PayPal Buy me a coffee Donate on Polar Donate to my FLOSS or refugee efforts at ko-fi.com Donate to my FLOSS or refugee efforts using Patreon

    +

    Sponsor Me on Github Liberapay Goal Progress Donate on PayPal Buy me a coffee Donate on Polar Donate to my FLOSS efforts at ko-fi.com Donate to my FLOSS efforts using Patreon

    🔐 Security

    @@ -930,6 +950,8 @@

    Code Coverage

    Coveralls Test Coverage

    +

    QLTY Test Coverage

    +

    🪇 Code of Conduct

    Everyone interacting with this project’s codebases, issue trackers,
    @@ -941,6 +963,8 @@

    🌈 Contributors

    Made with contributors-img.

    +

    Also see GitLab Contributors: https://gitlab.com/omniauth/omniauth-ldap/-/graphs/main

    +
    ⭐️ Star History @@ -978,16 +1002,17 @@

    📌 Versioning

    -📌 Is "Platform Support" part of the public API? More details inside. + 📌 Is "Platform Support" part of the public API? More details inside. -SemVer should, IMO, but doesn't explicitly, say that dropping support for specific Platforms -is a *breaking change* to an API. -It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless. +

    SemVer should, IMO, but doesn’t explicitly, say that dropping support for specific Platforms +is a breaking change to an API, and for that reason the bike shedding is endless.

    -To get a better understanding of how SemVer is intended to work over a project's lifetime, -read this article from the creator of SemVer: +

    To get a better understanding of how SemVer is intended to work over a project’s lifetime, +read this article from the creator of SemVer:

    -- ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred] +
    @@ -1003,7 +1028,7 @@
    • - Copyright (c) 2025 Peter H. Boling, of + Copyright (c) 2023, 2025 Peter H. Boling, of Galtzo.com @@ -1011,12 +1036,6 @@ , and omniauth-ldap contributors.
    • -
    • - Copyright (c) 2014 David Benko -
    • -
    • - Copyright (c) 2011 by Ping Yu and Intridea, Inc. -

    🤑 A request for help

    @@ -1043,7 +1062,7 @@

    Please give the project a star ⭐ ♥ diff --git a/docs/method_list.html b/docs/method_list.html index d32ed05..efe13c0 100644 --- a/docs/method_list.html +++ b/docs/method_list.html @@ -144,6 +144,14 @@

    Method List

  • +
    + #mapping + OmniAuth::Strategies::LDAP +
    +
  • + + +
  • #password OmniAuth::LDAP::Adaptor @@ -151,7 +159,7 @@

    Method List

  • -
  • +
  • #password_policy OmniAuth::LDAP::Adaptor @@ -159,7 +167,7 @@

    Method List

  • -
  • +
  • #request_phase OmniAuth::Strategies::LDAP @@ -167,6 +175,14 @@

    Method List

  • +
  • +
    + #title + OmniAuth::Strategies::LDAP +
    +
  • + +
  • #uid diff --git a/docs/top-level-namespace.html b/docs/top-level-namespace.html index ee16cff..38f9eb4 100644 --- a/docs/top-level-namespace.html +++ b/docs/top-level-namespace.html @@ -100,7 +100,7 @@

    Defined Under Namespace

    diff --git a/gemfiles/modular/documentation.gemfile b/gemfiles/modular/documentation.gemfile index 7853390..84c0c7c 100644 --- a/gemfiles/modular/documentation.gemfile +++ b/gemfiles/modular/documentation.gemfile @@ -1,11 +1,14 @@ # frozen_string_literal: true # Documentation -gem "kramdown", "~> 2.5", ">= 2.5.1" # Ruby >= 2.5 -gem "kramdown-parser-gfm", "~> 1.1" # Ruby >= 2.3 +gem "kramdown", "~> 2.5", ">= 2.5.1", require: false # Ruby >= 2.5 +gem "kramdown-parser-gfm", "~> 1.1", require: false # Ruby >= 2.3 gem "yard", "~> 0.9", ">= 0.9.37", require: false +gem "yaml-converter", "~> 0.1", require: false # Ruby >= 3.2 +gem "yard-fence", "~> 0.8", require: false # Ruby >= 3.2 gem "yard-junk", "~> 0.0", ">= 0.0.10", github: "pboling/yard-junk", branch: "next", require: false -gem "yard-relative_markdown_links", "~> 0.5.0" +gem "yard-relative_markdown_links", "~> 0.5.0", require: false +gem "yard-yaml", "~> 0.1", require: false # Ruby >= 3.2 # Std Lib extractions gem "rdoc", "~> 6.11" diff --git a/gemfiles/modular/x_std_libs/r2.3/libs.gemfile b/gemfiles/modular/x_std_libs/r2.3/libs.gemfile index 76539eb..2fee8b6 100644 --- a/gemfiles/modular/x_std_libs/r2.3/libs.gemfile +++ b/gemfiles/modular/x_std_libs/r2.3/libs.gemfile @@ -1,4 +1,3 @@ eval_gemfile "../../erb/r2.3/default.gemfile" eval_gemfile "../../mutex_m/r2.4/v0.1.gemfile" eval_gemfile "../../stringio/r2.4/v0.0.2.gemfile" -eval_gemfile "../../logger/r2/v1.5.gemfile" diff --git a/gemfiles/modular/x_std_libs/r2.4/libs.gemfile b/gemfiles/modular/x_std_libs/r2.4/libs.gemfile index d4bcb14..c1bcbd8 100644 --- a/gemfiles/modular/x_std_libs/r2.4/libs.gemfile +++ b/gemfiles/modular/x_std_libs/r2.4/libs.gemfile @@ -1,4 +1,3 @@ eval_gemfile "../../erb/r2.6/v2.2.gemfile" eval_gemfile "../../mutex_m/r2.4/v0.1.gemfile" eval_gemfile "../../stringio/r2.4/v0.0.2.gemfile" -eval_gemfile "../../logger/r2.4/v1.5.3.gemfile" diff --git a/gemfiles/modular/x_std_libs/r2.6/libs.gemfile b/gemfiles/modular/x_std_libs/r2.6/libs.gemfile index 3245fd4..beac38c 100644 --- a/gemfiles/modular/x_std_libs/r2.6/libs.gemfile +++ b/gemfiles/modular/x_std_libs/r2.6/libs.gemfile @@ -1,4 +1,3 @@ eval_gemfile "../../erb/r2.6/v2.2.gemfile" eval_gemfile "../../mutex_m/r2/v0.3.gemfile" eval_gemfile "../../stringio/r2/v3.0.gemfile" -eval_gemfile "../../logger/r2/v1.5.gemfile" diff --git a/gemfiles/modular/x_std_libs/r2/libs.gemfile b/gemfiles/modular/x_std_libs/r2/libs.gemfile index 0e21572..441c4f0 100644 --- a/gemfiles/modular/x_std_libs/r2/libs.gemfile +++ b/gemfiles/modular/x_std_libs/r2/libs.gemfile @@ -1,4 +1,3 @@ eval_gemfile "../../erb/r2/v3.0.gemfile" eval_gemfile "../../mutex_m/r2/v0.3.gemfile" eval_gemfile "../../stringio/r2/v3.0.gemfile" -eval_gemfile "../../logger/r2/v1.5.gemfile" diff --git a/gemfiles/modular/x_std_libs/r3.1/libs.gemfile b/gemfiles/modular/x_std_libs/r3.1/libs.gemfile index c18fa6e..bdab5bd 100644 --- a/gemfiles/modular/x_std_libs/r3.1/libs.gemfile +++ b/gemfiles/modular/x_std_libs/r3.1/libs.gemfile @@ -1,4 +1,3 @@ eval_gemfile "../../erb/r3.1/v4.0.gemfile" eval_gemfile "../../mutex_m/r3/v0.3.gemfile" eval_gemfile "../../stringio/r3/v3.0.gemfile" -eval_gemfile "../../logger/r3/v1.7.gemfile" diff --git a/gemfiles/modular/x_std_libs/r3/libs.gemfile b/gemfiles/modular/x_std_libs/r3/libs.gemfile index 4cb7b32..c293a3d 100644 --- a/gemfiles/modular/x_std_libs/r3/libs.gemfile +++ b/gemfiles/modular/x_std_libs/r3/libs.gemfile @@ -1,4 +1,3 @@ eval_gemfile "../../erb/r3/v5.0.gemfile" eval_gemfile "../../mutex_m/r3/v0.3.gemfile" eval_gemfile "../../stringio/r3/v3.0.gemfile" -eval_gemfile "../../logger/r3/v1.7.gemfile" diff --git a/gemfiles/modular/x_std_libs/vHEAD.gemfile b/gemfiles/modular/x_std_libs/vHEAD.gemfile index cc6e806..acc5ccb 100644 --- a/gemfiles/modular/x_std_libs/vHEAD.gemfile +++ b/gemfiles/modular/x_std_libs/vHEAD.gemfile @@ -1,4 +1,3 @@ eval_gemfile "../erb/vHEAD.gemfile" eval_gemfile "../mutex_m/vHEAD.gemfile" eval_gemfile "../stringio/vHEAD.gemfile" -eval_gemfile "../logger/vHEAD.gemfile" diff --git a/lib/omniauth-ldap.rb b/lib/omniauth-ldap.rb index f294db4..db45ed8 100644 --- a/lib/omniauth-ldap.rb +++ b/lib/omniauth-ldap.rb @@ -1,3 +1,11 @@ +# Integrate the VersionGem helper into the OmniAuth::LDAP::Version module +# to expose common version-related helper methods. This file is the public +# entry point required by consumers of the gem. +# +# @example +# require 'omniauth-ldap' +# OmniAuth::LDAP::VERSION # => "2.3.2" + require "version_gem" require "omniauth-ldap/version" diff --git a/lib/omniauth-ldap/adaptor.rb b/lib/omniauth-ldap/adaptor.rb index 93617e8..43f5433 100644 --- a/lib/omniauth-ldap/adaptor.rb +++ b/lib/omniauth-ldap/adaptor.rb @@ -10,12 +10,36 @@ module OmniAuth module LDAP + # Adaptor encapsulates the behavior required to connect to an LDAP server + # and perform searches and binds. It maps user-provided configuration into + # a Net::LDAP connection and provides compatibility helpers for different + # net-ldap and SASL versions. The adaptor is intentionally defensive and + # provides a small, stable API used by the OmniAuth strategy. + # + # @example Initialize with minimal config + # adaptor = OmniAuth::LDAP::Adaptor.new(base: 'dc=example,dc=com', host: 'ldap.example.com') + # + # @note Public API: {validate}, {initialize}, {bind_as}, and attr readers such as {connection}, {uid} class Adaptor + # Generic adaptor error super-class + # @see Error classes that inherit from this class class LdapError < StandardError; end + + # Raised when configuration is invalid + # @example + # raise ConfigurationError, 'missing base' class ConfigurationError < StandardError; end + + # Raised when authentication fails class AuthenticationError < StandardError; end + + # Raised on connection-related failures class ConnectionError < StandardError; end + # Valid configuration keys accepted by the adaptor. These correspond to + # the options supported by the gem and are used during initialization. + # + # @return [Array] VALID_ADAPTER_CONFIGURATION_KEYS = [ :hosts, :host, @@ -42,7 +66,9 @@ class ConnectionError < StandardError; end :ssl_version, ] - # A list of needed keys. Possible alternatives are specified using sub-lists. + # Required configuration keys. This may include alternatives as sub-lists + # (e.g., [:hosts, :host] means either key is acceptable). + # @return [Array] MUST_HAVE_KEYS = [ :base, [:encryption, :method], # :method is deprecated @@ -51,6 +77,8 @@ class ConnectionError < StandardError; end [:uid, :filter], ] + # Supported encryption method mapping for configuration readability. + # @return [Hash] ENCRYPTION_METHOD = { simple_tls: :simple_tls, start_tls: :start_tls, @@ -62,9 +90,47 @@ class ConnectionError < StandardError; end tls: :start_tls, } + # @!attribute [rw] bind_dn + # The distinguished name used for binding when provided in configuration. + # @return [String, nil] + # @!attribute [rw] password + # The bind password (may be nil for anonymous binds) + # @return [String, nil] attr_accessor :bind_dn, :password + + # Read-only attributes exposing connection and configuration state. + # @!attribute [r] connection + # The underlying Net::LDAP connection object. + # @return [Net::LDAP] + # @!attribute [r] uid + # The user id attribute used for lookups (e.g., 'sAMAccountName') + # @return [String] + # @!attribute [r] base + # The base DN for searches. + # @return [String] + # @!attribute [r] auth + # The final auth structure used by net-ldap. + # @return [Hash] + # @!attribute [r] filter + # Custom filter pattern when provided in configuration. + # @return [String, nil] + # @!attribute [r] password_policy + # Whether to request LDAP Password Policy controls. + # @return [Boolean] + # @!attribute [r] last_operation_result + # Last operation result object returned by the ldap library (if any) + # @return [Object, nil] + # @!attribute [r] last_password_policy_response + # Last extracted password policy response control (if any) + # @return [Object, nil] attr_reader :connection, :uid, :base, :auth, :filter, :password_policy, :last_operation_result, :last_password_policy_response + # Validate that a minimal configuration is present. Raises ArgumentError when required + # keys are missing. This is a convenience to provide early feedback to callers. + # + # @param configuration [Hash] configuration hash passed to the adaptor + # @raise [ArgumentError] when required keys are missing + # @return [void] def self.validate(configuration = {}) message = [] MUST_HAVE_KEYS.each do |names| @@ -77,6 +143,15 @@ def self.validate(configuration = {}) raise ArgumentError.new(message.join(",") + " MUST be provided") unless message.empty? end + # Create a new adaptor instance backed by a Net::LDAP connection. + # + # The constructor does not immediately open a network connection but + # prepares the Net::LDAP instance according to the provided configuration. + # It also applies timeout settings where supported by the installed net-ldap version. + # + # @param configuration [Hash] user-provided configuration options + # @raise [ArgumentError, ConfigurationError] on invalid configuration + # @return [OmniAuth::LDAP::Adaptor] def initialize(configuration = {}) Adaptor.validate(configuration) @configuration = configuration.dup @@ -128,6 +203,16 @@ def initialize(configuration = {}) #:base => "dc=yourcompany, dc=com", # :filter => "(mail=#{user})", # :password => psw + # + # Attempt to locate a user entry and bind as that entry using the supplied + # password. Returns the entry on success, or false/nil on failure. + # + # @param args [Hash] search and bind options forwarded to net-ldap's search + # @option args [Net::LDAP::Filter,String] :filter LDAP filter to use + # @option args [Integer] :size maximum number of results to fetch + # @option args [String,Proc] :password a password string or callable returning a password + # @return [Net::LDAP::Entry, false, nil] the found entry on successful bind, otherwise false/nil + # @raise [ConnectionError] if the underlying LDAP search fails def bind_as(args = {}) result = false @last_operation_result = nil @@ -179,6 +264,9 @@ def bind_as(args = {}) private + # Build encryption options for Net::LDAP given the configured method + # + # @return [Hash, nil] encryption options or nil for plain (no encryption) def encryption_options translated_method = translate_method return unless translated_method @@ -189,6 +277,10 @@ def encryption_options } end + # Normalize the user-provided encryption/method option and map to known values. + # + # @raise [ConfigurationError] when an unknown method is provided + # @return [Symbol, nil] def translate_method method = @encryption || @method method ||= "plain" @@ -203,6 +295,10 @@ def translate_method ENCRYPTION_METHOD[normalized_method] end + # Build TLS options including backward-compatibility for deprecated keys. + # + # @param translated_method [Symbol] the normalized encryption method + # @return [Hash] a hash suitable for passing as :tls_options def tls_options(translated_method) return {} if translated_method.nil? # (plain) @@ -223,6 +319,10 @@ def tls_options(translated_method) options end + # Build a list of SASL auth structures for each requested mechanism. + # + # @param options [Hash] options such as :username and :password + # @return [Array] list of auth structures def sasl_auths(options = {}) auths = [] sasl_mechanisms = options[:sasl_mechanisms] || @sasl_mechanisms @@ -241,6 +341,9 @@ def sasl_auths(options = {}) auths end + # Prepare SASL DIGEST-MD5 bind details + # @param options [Hash] + # @return [Array] initial_credential and a challenge response proc def sasl_bind_setup_digest_md5(options) bind_dn = options[:username] initial_credential = "" @@ -253,6 +356,9 @@ def sasl_bind_setup_digest_md5(options) [initial_credential, challenge_response] end + # Prepare SASL GSS-SPNEGO bind details + # @param options [Hash] + # @return [Array] initial Type1 message and a nego proc def sasl_bind_setup_gss_spnego(options) bind_dn = options[:username] psw = options[:password] @@ -268,8 +374,9 @@ def sasl_bind_setup_gss_spnego(options) [Net::NTLM::Message::Type1.new.serialize, nego] end - private - + # Default TLS/OpenSSL options used when not explicitly configured. + # + # @return [Hash] def default_options if @disable_verify_certificates # It is important to explicitly set verify_mode for two reasons: @@ -286,6 +393,9 @@ def default_options # # This gem may not always be in the context of Rails so we # do this rather than `.blank?`. + # + # @param hash [Hash] + # @return [Hash] sanitized hash with blank values removed def sanitize_hash_values(hash) hash.delete_if do |_, value| value.nil? || @@ -293,6 +403,10 @@ def sanitize_hash_values(hash) end end + # Convert string keys to symbol keys for options hashes. + # + # @param hash [Hash] + # @return [Hash] def symbolize_hash_keys(hash) hash.each_with_object({}) do |(key, value), result| result[key.to_sym] = value @@ -300,6 +414,12 @@ def symbolize_hash_keys(hash) end # Capture the operation result and extract any Password Policy response control if present. + # + # This method is defensive: if the server or the installed net-ldap gem doesn't + # support controls, the method will swallow errors and leave policy fields nil. + # + # @param conn [Net::LDAP] + # @return [void] def capture_password_policy(conn) return unless @password_policy return unless conn.respond_to?(:get_operation_result) diff --git a/lib/omniauth-ldap/version.rb b/lib/omniauth-ldap/version.rb index 24892f1..ce748c2 100644 --- a/lib/omniauth-ldap/version.rb +++ b/lib/omniauth-ldap/version.rb @@ -1,8 +1,17 @@ module OmniAuth module LDAP + # Version namespace for the omniauth-ldap gem + # + # This module contains the version constant used by rubygems and in code + # consumers. It intentionally exposes VERSION both inside the Version + # namespace and as OmniAuth::LDAP::VERSION for compatibility. module Version + # Public semantic version for the gem + # @return [String] VERSION = "2.3.2" end + # Convenience constant for consumers that expect OmniAuth::LDAP::VERSION + # @return [String] VERSION = Version::VERSION # Make VERSION available in traditional way end end diff --git a/lib/omniauth/strategies/ldap.rb b/lib/omniauth/strategies/ldap.rb index 2b01d40..303c746 100644 --- a/lib/omniauth/strategies/ldap.rb +++ b/lib/omniauth/strategies/ldap.rb @@ -1,14 +1,64 @@ +# frozen_string_literal: true + require "omniauth" require "omniauth/version" +# OmniAuth strategies namespace. +# +# This file implements an LDAP authentication strategy for OmniAuth. +# It provides both an interactive request phase (login form) and a +# callback phase which binds to an LDAP directory to authenticate the +# user or performs a lookup for header-based SSO. +# +# The strategy exposes a number of options (see `option` calls below) +# that control LDAP connection, mapping of LDAP attributes to the +# OmniAuth `info` hash, header-based SSO behavior, and SSL/timeouts. +# +# @example Minimal Rack mounting +# use OmniAuth::Builder do +# provider :ldap, { +# host: 'ldap.example.com', +# base: 'dc=example,dc=com' +# } +# end +# module OmniAuth module Strategies + # LDAP OmniAuth strategy + # + # This class implements the OmniAuth::Strategy interface and performs + # LDAP authentication using an `Adaptor` object. It supports three + # primary flows: + # + # - Interactive login form (request_phase) where users POST username/password + # - Callback binding where the strategy attempts to bind as the user + # - Header-based SSO (trusted upstream) where a header identifies the user + # + # The mapping from LDAP attributes to resulting `info` fields is + # configurable via the `:mapping` option. See `map_user` for the + # mapping algorithm. + # + # @see OmniAuth::Strategy class LDAP + # Whether the loaded OmniAuth version is >= 2.0.0; used to set default request methods. + # @return [Boolean] OMNIAUTH_GTE_V2 = Gem::Version.new(OmniAuth::VERSION) >= Gem::Version.new("2.0.0") + include OmniAuth::Strategy + # Raised when credentials are invalid or the user cannot be authenticated. + # @example + # raise InvalidCredentialsError, 'Invalid credentials' InvalidCredentialsError = Class.new(StandardError) + # Default mapping for converting LDAP attributes to OmniAuth `info` keys. + # Keys are the resulting `info` hash keys (strings). Values may be: + # - String: single LDAP attribute name + # - Array: list of attribute names in priority order + # - Hash: pattern mapping where pattern keys contain % placeholders + # that are substituted from a list of possible attribute names + # + # @return [Hash] option :mapping, { "name" => "cn", "first_name" => "givenName", @@ -24,7 +74,11 @@ class LDAP "image" => "jpegPhoto", "description" => "description", } - option :title, "LDAP Authentication" # default title for authentication form + + # Default title shown on the login form. + # @return [String] + option :title, "LDAP Authentication" + # For OmniAuth >= 2.0 the default allowed request method is POST only. # Ensure the strategy follows that default so GET /auth/:provider returns 404 as expected in tests. if OMNIAUTH_GTE_V2 @@ -32,6 +86,8 @@ class LDAP else option(:request_methods, [:get, :post]) end + + # Default LDAP connection options / behavior option :port, 389 option :method, :plain option :disable_verify_certificates, false @@ -39,6 +95,7 @@ class LDAP option :ssl_version, nil # use OpenSSL default if nil option :uid, "sAMAccountName" option :name_proc, lambda { |n| n } + # Trusted header SSO support (disabled by default) # :header_auth - when true and the header is present, the strategy trusts the upstream gateway # and searches the directory for the user without requiring a user password. @@ -46,10 +103,20 @@ class LDAP # standard Rack "HTTP_" variant automatically. option :header_auth, false option :header_name, "REMOTE_USER" + # Optional timeouts (forwarded to Net::LDAP when supported) option :connect_timeout, nil option :read_timeout, nil + # Request phase: Render the login form or redirect to callback for header-auth or direct POSTed credentials + # + # This will behave differently depending on OmniAuth version and request method: + # - For OmniAuth >= 2.0 a GET to /auth/:provider should return 404 (so we return a 404 for GET requests). + # - If header-based SSO is enabled and a trusted header is present we immediately redirect to the callback. + # - If credentials are POSTed directly to /auth/:provider we redirect to the callback so the test helpers + # that populate `env['omniauth.auth']` can operate on the callback request. + # + # @return [Array] A Rack response triple from the login form or redirect. def request_phase # OmniAuth >= 2.0 expects the request phase to be POST-only for /auth/:provider. # Some test environments (and OmniAuth itself) enforce this by returning 404 on GET. @@ -78,6 +145,19 @@ def request_phase f.to_response end + # Callback phase: Authenticate user or perform header-based lookup + # + # This method executes on the callback URL and implements the main + # authentication logic. There are two primary paths: + # + # - Header-based lookup: when `options[:header_auth]` is enabled and a header value is present, + # we perform a read-only directory lookup for the user and, if found, map attributes and finish. + # - Password bind: when username/password are provided we attempt a bind as the user using the adaptor. + # + # Errors raised by the LDAP adaptor are captured and turned into OmniAuth failures. + # + # @raise [InvalidCredentialsError] when credentials are invalid + # @return [Object] result of calling `super` from the OmniAuth::Strategy chain def callback_phase @adaptor = OmniAuth::LDAP::Adaptor.new(@options) @@ -118,6 +198,15 @@ def callback_phase end end + # Build an LDAP filter for searching/binding the user. + # + # If the adaptor has a custom `filter` option set it will be used (with + # interpolation of `%{username}`). Otherwise a simple equality filter for + # the configured uid attribute is used. + # + # @param adaptor [OmniAuth::LDAP::Adaptor] the adaptor used to build connection/filters + # @param username_override [String, nil] optional username to build the filter for (defaults to request username) + # @return [Net::LDAP::Filter] the constructed filter object def filter(adaptor, username_override = nil) flt = adaptor.filter if flt && !flt.to_s.empty? @@ -128,17 +217,37 @@ def filter(adaptor, username_override = nil) end end - uid { - @user_info["uid"] - } - info { - @user_info - } - extra { - {raw_info: @ldap_user_info} - } + # The uid exposed to OmniAuth consumers. + # + # This block-based DSL is part of OmniAuth::Strategy; document the value + # returned by the block. + # + # @return [String] the user's uid as determined from the mapped info + uid { @user_info["uid"] } + + # The `info` hash returned to OmniAuth consumers. Usually contains name, email, etc. + # @return [Hash] + info { @user_info } + + # Extra information exposed under `extra[:raw_info]` containing the raw LDAP entry. + # @return [Hash{Symbol => Object}] + extra { {raw_info: @ldap_user_info} } class << self + # Map LDAP attributes from the directory entry into a simple Hash used + # for the OmniAuth `info` hash according to the provided `mapper`. + # + # The mapper supports three types of values: + # - String: a single attribute name. The method will call the attribute + # reader (downcased symbol) on the `object` and take the first value. + # - Array: iterate values and pick the first attribute that exists on the object. + # - Hash: a mapping of a pattern string to an array of attribute-name lists + # where each `%` placeholder in the pattern will be substituted by the + # first available attribute from the corresponding list. + # + # @param mapper [Hash] mapping configuration (see option :mapping) + # @param object [#respond_to?, #[]] directory entry (commonly a Net::LDAP::Entry or similar) + # @return [Hash] the mapped user info hash def map_user(mapper, object) user = {} mapper.each do |key, value| @@ -177,20 +286,38 @@ def map_user(mapper, object) protected + # Validate that the incoming request method is allowed. + # + # For OmniAuth >= 2.0 the default is POST only. This method checks the + # Rack env REQUEST_METHOD directly so tests and environments that stub + # request.HTTP_METHOD are handled deterministically. + # + # @return [Boolean] true when the request method is POST def valid_request_method? request.env["REQUEST_METHOD"] == "POST" end + # Determine if the request is missing required credentials. + # + # @return [Boolean] true when username or password are nil/empty def missing_credentials? request_data["username"].nil? || request_data["username"].empty? || request_data["password"].nil? || request_data["password"].empty? end + # Extract request parameters in a way compatible with Rails/Rack. + # + # @return [Hash] parameters hash containing at least "username" and "password" when provided def request_data @env["action_dispatch.request.request_parameters"] || request.params end # Extract a normalized username from a trusted header when enabled. # Returns nil when not configured or not present. + # + # The method will attempt the raw env key (e.g. "REMOTE_USER") and the Rack + # HTTP_ variant (e.g. "HTTP_REMOTE_USER" or "HTTP_X_REMOTE_USER"). + # + # @return [String, nil] normalized username or nil if not present def header_username return unless options[:header_auth] @@ -204,6 +331,10 @@ def header_username # Perform a directory lookup for the given username using the strategy configuration # (bind_dn/password or anonymous). Does not attempt to bind as the user. + # + # @param adaptor [OmniAuth::LDAP::Adaptor] initialized adaptor + # @param username [String] username to look up + # @return [Object, nil] first directory entry found or nil def directory_lookup(adaptor, username) entry = nil search_filter = filter(adaptor, username) @@ -216,6 +347,11 @@ def directory_lookup(adaptor, username) # If the adaptor captured a Password Policy response control, expose a minimal, stable hash # in the Rack env for applications to inspect. + # + # The structure is available at `request.env['omniauth.ldap.password_policy']`. + # + # @param adaptor [OmniAuth::LDAP::Adaptor] + # @return [void] def attach_password_policy_env(adaptor) return unless adaptor.respond_to?(:password_policy) && adaptor.password_policy ctrl = adaptor.respond_to?(:last_password_policy_response) ? adaptor.last_password_policy_response : nil @@ -226,6 +362,10 @@ def attach_password_policy_env(adaptor) end # Best-effort extraction across net-ldap versions; if fields are not available, returns a raw payload. + # + # @param control [Object, nil] the password policy response control if available + # @param operation [Object, nil] the last operation result if available + # @return [Hash] normalized password policy info with keys :raw, :error, :time_before_expiration, :grace_authns_remaining, :oid, :operation def extract_password_policy(control, operation) data = {raw: control} if control diff --git a/omniauth-ldap.gemspec b/omniauth-ldap.gemspec index 257b815..6a7885f 100644 --- a/omniauth-ldap.gemspec +++ b/omniauth-ldap.gemspec @@ -158,6 +158,6 @@ Gem::Specification.new do |spec| # In Ruby 3.5 (HEAD) the CGI library has been pared down, so we also need to depend on gem "cgi" for ruby@head # This is done in the "head" appraisal. # See: https://github.com/vcr/vcr/issues/1057 - spec.add_development_dependency("vcr", ">= 4") # 6.0 claims to support ruby >= 2.3, but fails on ruby 2.4 - spec.add_development_dependency("webmock", ">= 3") # Last version to support ruby >= 2.3 + # spec.add_development_dependency("vcr", ">= 4") # 6.0 claims to support ruby >= 2.3, but fails on ruby 2.4 + # spec.add_development_dependency("webmock", ">= 3") # Last version to support ruby >= 2.3 end