diff --git a/Gemfile b/Gemfile index b9ca625a6908572c2b464c40838a49ecaeb997f7..a943800f584601d85eacbf46c6ea4b6c6a047e36 100644 --- a/Gemfile +++ b/Gemfile @@ -89,8 +89,10 @@ gem 'coverband', '6.1.4', require: false, feature_category: :shared gem 'devise', '~> 4.9.3', feature_category: :system_access gem 'devise-pbkdf2-encryptable', '~> 0.0.0', path: 'vendor/gems/devise-pbkdf2-encryptable' # rubocop:todo Gemfile/MissingFeatureCategory gem 'bcrypt', '~> 3.1', '>= 3.1.14' # rubocop:todo Gemfile/MissingFeatureCategory -gem 'doorkeeper', '~> 5.6', '>= 5.6.6' # rubocop:todo Gemfile/MissingFeatureCategory -gem 'doorkeeper-openid_connect', '~> 1.8', '>= 1.8.7' # rubocop:todo Gemfile/MissingFeatureCategory +gem 'doorkeeper', '~> 5.8', '>= 5.8.0', feature_category: :system_access +gem 'doorkeeper-openid_connect', '~> 1.8', + path: 'vendor/gems/doorkeeper-openid_connect', # See Gem README for why this is vendored + feature_category: :system_access gem 'doorkeeper-device_authorization_grant', '~> 1.0.0', feature_category: :system_access gem 'rexml', '~> 3.3.2' # rubocop:todo Gemfile/MissingFeatureCategory gem 'ruby-saml', '~> 1.17.0', feature_category: :system_access diff --git a/Gemfile.checksum b/Gemfile.checksum index d2ab6768fa3092c6a3c7f37bdf659bc22b394c42..c9ddd2fb569e70d9260ed7143a26b6366621783a 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -127,9 +127,8 @@ {"name":"discordrb-webhooks","version":"3.5.0","platform":"ruby","checksum":"52fba8bce3b08059d4a41a1e73a9a152958e788a9330275450126b44f01c23b1"}, {"name":"docile","version":"1.4.0","platform":"ruby","checksum":"5f1734bde23721245c20c3d723e76c104208e1aa01277a69901ce770f0ebb8d3"}, {"name":"domain_name","version":"0.5.20190701","platform":"ruby","checksum":"000a600454cb4a344769b2f10b531765ea7bd3a304fe47ed12e5ca1eab969851"}, -{"name":"doorkeeper","version":"5.7.1","platform":"ruby","checksum":"8b08f5946c62505be1a32f9094eb99eca32b280e956f515529e33b2b025bd628"}, +{"name":"doorkeeper","version":"5.8.0","platform":"ruby","checksum":"5abc747ee0eaa3140e165b41e937941f05d5ce5bcd8b8ed6718e6711623a8105"}, {"name":"doorkeeper-device_authorization_grant","version":"1.0.3","platform":"ruby","checksum":"94c3ac12a0d50942850ecd58ed64298b397a5e903e8880cb68d4085600932679"}, -{"name":"doorkeeper-openid_connect","version":"1.8.9","platform":"ruby","checksum":"5709a991d113e946e1c7d722eb94af3bcbc0a121ece67edd72ce4d08a93bfcae"}, {"name":"dotenv","version":"2.7.6","platform":"ruby","checksum":"2451ed5e8e43776d7a787e51d6f8903b98e446146c7ad143d5678cc2c409d547"}, {"name":"dry-cli","version":"1.0.0","platform":"ruby","checksum":"28ead169f872954dd08910eb8ead59cf86cd18b4aab321e8eeefe945749569f0"}, {"name":"dry-core","version":"1.0.1","platform":"ruby","checksum":"f32f4245e0f54e787f3708584ed8f7545aaf8dd99072e36f169312468ec5450d"}, diff --git a/Gemfile.lock b/Gemfile.lock index 936e3315eb705f7156d7f633b199eee6b92724b8..48a3a8f6df12f8632b2769b1f692eed078a49d19 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -159,6 +159,13 @@ PATH specs: diff_match_patch (0.1.0) +PATH + remote: vendor/gems/doorkeeper-openid_connect + specs: + doorkeeper-openid_connect (1.8.9) + doorkeeper (>= 5.5, < 5.9) + jwt (>= 2.5) + PATH remote: vendor/gems/gitlab-duo-workflow-service-client specs: @@ -534,13 +541,10 @@ GEM docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.7.1) + doorkeeper (5.8.0) railties (>= 5) doorkeeper-device_authorization_grant (1.0.3) doorkeeper (~> 5.5) - doorkeeper-openid_connect (1.8.9) - doorkeeper (>= 5.5, < 5.8) - jwt (>= 2.5) dotenv (2.7.6) dry-cli (1.0.0) dry-core (1.0.1) @@ -2027,9 +2031,9 @@ DEPENDENCIES diff_match_patch (~> 0.1.0)! diffy (~> 3.4) discordrb-webhooks (~> 3.5) - doorkeeper (~> 5.6, >= 5.6.6) + doorkeeper (~> 5.8, >= 5.8.0) doorkeeper-device_authorization_grant (~> 1.0.0) - doorkeeper-openid_connect (~> 1.8, >= 1.8.7) + doorkeeper-openid_connect (~> 1.8)! duo_api (~> 1.3) ed25519 (~> 1.3.0) elasticsearch-api (= 7.17.11) diff --git a/Gemfile.next.checksum b/Gemfile.next.checksum index 4102eb6f693d9a60945e7ed8a3fb208be62cc825..f5f4c15647c311faee5f4af9e5405a940ccce04f 100644 --- a/Gemfile.next.checksum +++ b/Gemfile.next.checksum @@ -127,9 +127,8 @@ {"name":"discordrb-webhooks","version":"3.5.0","platform":"ruby","checksum":"52fba8bce3b08059d4a41a1e73a9a152958e788a9330275450126b44f01c23b1"}, {"name":"docile","version":"1.4.0","platform":"ruby","checksum":"5f1734bde23721245c20c3d723e76c104208e1aa01277a69901ce770f0ebb8d3"}, {"name":"domain_name","version":"0.5.20190701","platform":"ruby","checksum":"000a600454cb4a344769b2f10b531765ea7bd3a304fe47ed12e5ca1eab969851"}, -{"name":"doorkeeper","version":"5.7.1","platform":"ruby","checksum":"8b08f5946c62505be1a32f9094eb99eca32b280e956f515529e33b2b025bd628"}, +{"name":"doorkeeper","version":"5.8.0","platform":"ruby","checksum":"5abc747ee0eaa3140e165b41e937941f05d5ce5bcd8b8ed6718e6711623a8105"}, {"name":"doorkeeper-device_authorization_grant","version":"1.0.3","platform":"ruby","checksum":"94c3ac12a0d50942850ecd58ed64298b397a5e903e8880cb68d4085600932679"}, -{"name":"doorkeeper-openid_connect","version":"1.8.9","platform":"ruby","checksum":"5709a991d113e946e1c7d722eb94af3bcbc0a121ece67edd72ce4d08a93bfcae"}, {"name":"dotenv","version":"2.7.6","platform":"ruby","checksum":"2451ed5e8e43776d7a787e51d6f8903b98e446146c7ad143d5678cc2c409d547"}, {"name":"drb","version":"2.2.1","platform":"ruby","checksum":"e9d472bf785f558b96b25358bae115646da0dbfd45107ad858b0bc0d935cb340"}, {"name":"dry-cli","version":"1.0.0","platform":"ruby","checksum":"28ead169f872954dd08910eb8ead59cf86cd18b4aab321e8eeefe945749569f0"}, diff --git a/Gemfile.next.lock b/Gemfile.next.lock index 1b814327380577edd6b68fefdef10f07adf255be..6b893f1bab4e16e09352081e5ed82d123e62665c 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -159,6 +159,13 @@ PATH specs: diff_match_patch (0.1.0) +PATH + remote: vendor/gems/doorkeeper-openid_connect + specs: + doorkeeper-openid_connect (1.8.9) + doorkeeper (>= 5.5, < 5.9) + jwt (>= 2.5) + PATH remote: vendor/gems/gitlab-duo-workflow-service-client specs: @@ -543,13 +550,10 @@ GEM docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.7.1) + doorkeeper (5.8.0) railties (>= 5) doorkeeper-device_authorization_grant (1.0.3) doorkeeper (~> 5.5) - doorkeeper-openid_connect (1.8.9) - doorkeeper (>= 5.5, < 5.8) - jwt (>= 2.5) dotenv (2.7.6) drb (2.2.1) dry-cli (1.0.0) @@ -2054,9 +2058,9 @@ DEPENDENCIES diff_match_patch (~> 0.1.0)! diffy (~> 3.4) discordrb-webhooks (~> 3.5) - doorkeeper (~> 5.6, >= 5.6.6) + doorkeeper (~> 5.8, >= 5.8.0) doorkeeper-device_authorization_grant (~> 1.0.0) - doorkeeper-openid_connect (~> 1.8, >= 1.8.7) + doorkeeper-openid_connect (~> 1.8)! duo_api (~> 1.3) ed25519 (~> 1.3.0) elasticsearch-api (= 7.17.11) diff --git a/vendor/gems/doorkeeper-openid_connect/.gitlab-ci.yml b/vendor/gems/doorkeeper-openid_connect/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..77259f8093d385cdfa718c360ea652c038a29650 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/.gitlab-ci.yml @@ -0,0 +1,9 @@ +include: + - local: gems/gem.gitlab-ci.yml + inputs: + gem_name: "doorkeeper-openid_connect" + gem_path_prefix: "vendor/gems/" + bundle_gemfiles: ['gemfiles/doorkeeper_master.gemfile'] + bundle_version: "2.5.11" +variables: + BUNDLE_FROZEN: "false" diff --git a/vendor/gems/doorkeeper-openid_connect/CHANGELOG.md b/vendor/gems/doorkeeper-openid_connect/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..588ff986bd8b14e61a8b53385e92177301033191 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/CHANGELOG.md @@ -0,0 +1,288 @@ +## Unreleased + +- [#PR ID] Add your changelog entry here. + +## v1.8.9 (2024-05-07) + +- Support Doorkeeper 5.7 + +## v1.8.8 (2024-02-26) + +- [#201] Add back typ=JWT to header + +## v1.8.7 (2023-05-18) + +- [#198] Fully qualify `JWT::JWK::Thumbprint` constant with :: (thanks to @stanhu) + +## v1.8.6 (2023-05-12) + +- [#194] Default to RFC 7638 kid fingerprint generation (thanks to @stanhu). + +## v1.8.5 (2023-02-02) + +- [#186] Simplify gem configuration reusing Doorkeeper configuration option DSL (thanks to @nbulaj). +- [#182] Drop support for Ruby 2.6 and Rails 5 (thanks to @sato11). +- [#188] Fix dookeeper-jwt compatibility (thanks to @zavan). + +## v1.8.4 (2023-02-01) + +Note that v1.8.4 changed the default kid fingerprint generation from RFC 7638 to a format +based on the SHA256 digest of the key element. To restore the previous behavior, upgrade to v1.8.6. + +- [#177] Replace `json-jwt` with `ruby-jwt` to align with doorkeeper-jwt (thanks to @kristof-mattei). +- [#185] Don't call active_record_options for Doorkeeper >= 5.6.3 (thanks to @zavan). +- [#183] Stop render consent screen when user is not logged-in (thanks to @nov). + +## v1.8.3 (2022-12-02) + +- [#180] Add PKCE support to OpenID discovery endpoint (thanks to @stanhu). + +## v1.8.2 (2022-07-13) + +- [#168] Allow to use custom doorkeeper access grant model (thanks @nov). +- [#170] Controllers inherit `Doorkeeper::AppliactionMetalController` (thanks @sato11). +- [#171] Correctly override `AuthorizationsController` params (thanks to @nbulaj). + +## v1.8.1 (2022-02-09) + +- [#153] Fix ArgumentError caused by client credential validation introduced in Doorkeeper 5.5.1 (thanks to @CircumnavigatingFlatEarther) +- [#161] Fix .well-known/openid-connect issuer (respond to block if provided) (thanks to @fkowal). +- [#152] Expose oauth-authorization-server in routes (thanks to @mitar) + +## v1.8.0 (2021-05-11) + +No changes from v1.8.0-rc1. + +## v1.8.0-rc1 (2021-04-20) + +### Upgrading + +This gem now requires Doorkeeper 5.5 and Ruby 2.5. + +### Changes + +- [#138] Support form_post response mode (thanks to @linhdangduy) +- [#144] Support block syntax for `issuer` configuration (thanks to @maxxsnake) +- [#145] Register token flows with the strategy instead of the token class (thanks to @paukul) + +## v1.7.5 (2020-12-15) + +### Changes + +- [#126] Add discovery_url_options option for discovery endpoints URL generation (thanks to @phlegx) + +### Bugfixes + +- [#123] Remove reference to ApplicationRecord (thanks to @wheeyls) +- [#124] Clone doorkeeper.grant_flows array before appending 'refresh_token' (thanks to @davidbasalla) +- [#129] Avoid to use the config alias while supporting Doorkeeper 5.2 (thanks to @kymmt90) + +## v1.7.4 (2020-07-06) + +- [#119] Execute end_session_endpoint in the controllers context (thanks to @joeljunstrom) + +## v1.7.3 (2020-07-06) + +- [#111] Add configuration callback `select_account_for_resource_owner` to support the `prompt=select_account` param +- [#112] Add grant_types_supported to discovery response +- [#114] Fix user_info endpoint when used in api mode +- [#116] Support Doorkeeper API (> 5.4) for registering custom grant flows. +- [#117] Fix migration template to use Rails migrations DSL for association. +- [#118] Use fragment urls for implicit flow error redirects (thanks to @joeljunstrom) + +## v1.7.2 (2020-05-20) + +### Changes + +- [#108] Add support for Doorkeeper 5.4 +- [#103] Add support for end_session_endpoint +- [#109] Test against Ruby 2.7 & Rails 6.x + +## v1.7.1 (2020-02-07) + +### Upgrading + +This version adds `on_delete: :cascade` to the migration template for the `oauth_openid_requests` table, in order to fix #82. + +For existing installations, you should add a new migration in your application to drop the existing foreign key and replace it with a new one with `on_delete: :cascade` included. Depending on the database you're using and the size of your application this might bring up some concerns, but in most cases the following should be sufficient: + +```ruby +class UpdateOauthOpenIdRequestsForeignKeys < ActiveRecord::Migration[5.2] + def up + remove_foreign_key(:oauth_openid_requests, column: :access_grant_id) + add_foreign_key(:oauth_openid_requests, :oauth_access_grants, column: :access_grant_id, on_delete: :cascade) + end + + def down + remove_foreign_key(:oauth_openid_requests, column: :access_grant_id) + add_foreign_key(:oauth_openid_requests, :oauth_access_grants, column: :access_grant_id) + end +end +``` + +### Bugfixes + +- [#96] Bump `json-jwt` because of CVE-2019-18848 (thanks to @leleabhinav) +- [#97] Fixes for compatibility with Doorkeeper 5.2 (thanks to @linhdangduy) +- [#98] Cascade deletes from `oauth_openid_requests` to `oauth_access_grants` (thanks to @manojmj92) +- [#99] Fix `audience` claim when application is not set on access token (thanks to @ionut998) + +## v1.7.0 (2019-11-04) + +### Changes + +- [#85] This gem now requires Doorkeeper 5.2, Rails 5, and Ruby 2.4 + +## v1.6.3 (2019-09-24) + +### Changes + +- [#81] Allow silent authentication without user consent (thanks to @jarosan) +- Don't support Doorkeeper >= 5.2 due to breaking changes + +## v1.6.2 (2019-08-09) + +### Bugfixes + +- [#80] Check for client presence in controller, fixes a 500 error when `client_id` is missing (thanks to @cincospenguinos @urnf @isabellechalhoub) + +## v1.6.1 (2019-06-07) + +### Bugfixes + +- [#75] Fix return value for `after_successful_response` (thanks to @daveed) + +### Changes + +- [#72] Add `revocation_endpoint` and `introspection_endpoint` to discovery response (thanks to @scarfacedeb) + +## v1.6.0 (2019-03-06) + +### Changes + +- [#70] This gem now requires Doorkeeper 5.0, and actually has done so since v1.5.4 (thanks to @michaelglass) + +## v1.5.5 (2019-03-03) + +- [#69] Return `crv` parameter for EC keys (thanks to @marco-nicola) + +## v1.5.4 (2019-02-15) + +### Bugfixes + +- [#66] Fix an open redirect vulnerability ([CVE-2019-9837](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9837), thanks to @meagar) +- [#67] Don't delete existing tokens with `prompt=consent` (thanks to @nov) + +### Changes + +- [#62] Support customization of redirect params in `id_token` and `id_token token` responses (thanks to @meagar) + +## v1.5.3 (2019-01-19) + +### Bugfixes + +- [#60] Don't break native authorization in Doorkeeper 5.x + +### Changes + +- [#58] Use versioned migrations for Rails 5.x (thanks to @tvongaza) + +## v1.5.2 (2018-09-04) + +### Changes + +- [#56] The previous release was a bit premature, this fixes some compatibility issues with Doorkeeper 5.x + +## v1.5.1 (2018-09-04) + +### Changes + +- [#55] This gem is now compatible with Doorkeeper 5.x + +## v1.5.0 (2018-06-27) + +### Features + +- [#52] Custom claims can now also be returned directly in the ID token, see the updated README for usage instructions + +## v1.4.0 (2018-05-31) + +### Upgrading + +- Support for Ruby versions older than 2.3 was dropped + +### Features + +- Redirect errors per Section 3.1.2.6 of OpenID Connect 1.0 (by @ryands) +- Set `id_token` when it's nil in token response (it's used in `refresh_token` requests) (by @Miouge1) + +## v1.3.0 (2018-03-05) + +### Features + +- Support for Implicit Flow (`response_type=id_token` and `response_type=id_token token`), + see the updated README for usage instructions (by @nashby, @nhance and @stevenvegt) + +## v1.2.0 (2017-08-31) + +### Upgrading + +- The configuration setting `jws_private_key` was renamed to `signing_key`, you can still use the old name until it's removed in the next major release + +### Features + +- Support for pairwise subject identifiers (by @travisofthenorth) +- Support for EC and HMAC signing algorithms (by @110y) +- Claims now receive an optional third `access_token` argument which allow you to dynamically adjust claim values based on the client's token (by @gigr) + +### Bugfixes + +## v1.1.2 (2017-01-18) + +### Bugfixes + +- Fixes the `undefined local variable or method 'pre_auth'` error + +## v1.1.1 (2017-01-18) + +#### Upgrading + +- The configuration setting `jws_public_key` wasn't actually used, it's deprecated now and will be removed in the next major release +- The undocumented shorthand `to_proc` syntax for defining claims (`claim :user, &:name`) is not supported anymore + +#### Features + +- Claims now receive an optional second `scopes` argument which allow you to dynamically adjust claim values based on the requesting applications' scopes (by @nbibler) +- The `prompt` parameter values `login` and `consent` are now supported +- The configuration setting `protocol` was added (by @gigr) + +#### Bugfixes + +- Standard Claims are now mapped correctly to their default scopes (by @tylerhunt) +- Blank `nonce` parameters are now ignored + +#### Changes + +- `nil` values and empty strings are now removed from the UserInfo and IdToken responses +- Allow `json-jwt` dependency at ~> 1.6. (by @nbibler) +- Configuration blocks no longer internally use `instance_eval` which previously gave undocumented and unexpected `self` access to the caller (by @nbibler) + +## v1.1.0 (2016-11-30) + +This release is a general clean-up and adds support for some advanced OpenID Connect features. + +#### Upgrading + +- This version adds a table to store temporary nonces, use the generator `doorkeeper:openid_connect:migration` to create a migration +- Implement the new configuration callbacks `auth_time_from_resource_owner` and `reauthenticate_resource_owner` to support advanced features + +#### Features + +- Add discovery endpoint ([a16caa8](/../../commit/a16caa8)) +- Add webfinger and keys endpoints for discovery ([f70898b](/../../commit/f70898b)) +- Add supported claims to discovery response ([1d8f9ea](/../../commit/1d8f9ea)) +- Support prompt=none parameter ([c775d8b](/../../commit/c775d8b)) +- Store and return nonces in IdToken responses ([d28ca8c](/../../commit/d28ca8c)) +- Add generator for initializer ([80399fd](/../../commit/80399fd)) +- Support max_age parameter ([aabe3aa](/../../commit/aabe3aa)) +- Respect scope grants in UserInfo response ([25f2170](/../../commit/25f2170)) diff --git a/vendor/gems/doorkeeper-openid_connect/CONTRIBUTING.md b/vendor/gems/doorkeeper-openid_connect/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..5cc59a017b27a851f6e280221eab8591ecfdc083 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/CONTRIBUTING.md @@ -0,0 +1,46 @@ +# Contributing + +## Workflow + +We are using the [Feature Branch Workflow (also known as GitHub Flow)](https://guides.github.com/introduction/flow/), and prefer delivery as pull requests. + +Our first line of defense is the [Travis CI](https://travis-ci.org/doorkeeper-gem/doorkeeper-openid_connect) build defined within [.travis.yml](.travis.yml) and triggered for every pull request. + +Create a feature branch: + +```sh +git checkout -B feature/contributing +``` + +## Creating Good Commits + +The cardinal rule for creating good commits is to ensure there is only one +"logical change" per commit. Why is this an important rule? + +* The smaller the amount of code being changed, the quicker & easier it is to + review & identify potential flaws. + +* If a change is found to be flawed later, it may be necessary to revert the + broken commit. This is much easier to do if there are not other unrelated + code changes entangled with the original commit. + +* When troubleshooting problems using Git's bisect capability, small well + defined changes will aid in isolating exactly where the code problem was + introduced. + +* When browsing history using Git annotate/blame, small well defined changes + also aid in isolating exactly where & why a piece of code came from. + +Things to avoid when creating commits: + +* Mixing whitespace changes with functional code changes. +* Mixing two unrelated functional changes. +* Sending large new features in a single giant commit. + +## Release process + +- Bump version in `lib/doorkeeper/openid_connect/version.rb`. +- Update `CHANGELOG.md`. +- Commit all changes. +- Tag release and publish gem with `rake release`. +- [Publish a new release on GitHub](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/releases/new), using the created tag and the new entries in `CHANGELOG.md`. diff --git a/vendor/gems/doorkeeper-openid_connect/Gemfile b/vendor/gems/doorkeeper-openid_connect/Gemfile new file mode 100644 index 0000000000000000000000000000000000000000..9a2cbd3fa5b25802e1e14c10c53fe1bfeeef61ad --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/Gemfile @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +# use Rails version specified by environment +ENV['rails'] ||= '6.0.0' +gem 'rails', "~> #{ENV['rails']}" +gem 'rails-controller-testing' + +gem 'rubocop', '~> 1.6' +gem 'rubocop-performance', require: false +gem 'rubocop-rails', require: false +gem 'rubocop-rspec', require: false + +gemspec diff --git a/vendor/gems/doorkeeper-openid_connect/LICENSE.txt b/vendor/gems/doorkeeper-openid_connect/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..31b068d048f0c45856da5790614cee1bffa56585 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/LICENSE.txt @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2014 PlayOn! Sports + +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/vendor/gems/doorkeeper-openid_connect/README.md b/vendor/gems/doorkeeper-openid_connect/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9fde3a9515cb986e3812df81ebd30124aab3009b --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/README.md @@ -0,0 +1,342 @@ +# Doorkeeper::OpenidConnect + +This is a fork of [doorkeeper-openid_connect](https://github.com/doorkeeper-gem/doorkeeper-openid_connect) to support: + +- Doorkeeper version 5.8.0 +- This gem can be unvendored once [PR 213](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/pull/213) is merged and released. + +[](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/actions) +[](https://codeclimate.com/github/doorkeeper-gem/doorkeeper-openid_connect) +[](https://rubygems.org/gems/doorkeeper-openid_connect) + +#### :warning: **This project is looking for maintainers, see [this issue](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/issues/89).** + +This library implements an [OpenID Connect](http://openid.net/connect/) authentication provider for Rails applications on top of the [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper) OAuth 2.0 framework. + +OpenID Connect is a single-sign-on and identity layer with a [growing list of server and client implementations](http://openid.net/developers/libraries/). If you're looking for a client in Ruby check out [omniauth_openid_connect](https://github.com/m0n9oose/omniauth_openid_connect/). + +## Table of Contents + +- [Status](#status) + - [Known Issues](#known-issues) + - [Example Applications](#example-applications) +- [Installation](#installation) +- [Configuration](#configuration) + - [Scopes](#scopes) + - [Claims](#claims) + - [Routes](#routes) + - [Nonces](#nonces) + - [Internationalization (I18n)](#internationalization-i18n) +- [Development](#development) +- [License](#license) +- [Sponsors](#sponsors) + +## Status + +The following parts of [OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) are currently supported: + +- [Authentication using the Authorization Code Flow](http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth) +- [Authentication using the Implicit Flow](http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth) +- [Requesting Claims using Scope Values](http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) +- [UserInfo Endpoint](http://openid.net/specs/openid-connect-core-1_0.html#UserInfo) +- [Normal Claims](http://openid.net/specs/openid-connect-core-1_0.html#NormalClaims) +- [OAuth 2.0 Form Post Response Mode](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html) + +In addition we also support most of [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) for automatic configuration discovery. + +Take a look at the [DiscoveryController](app/controllers/doorkeeper/openid_connect/discovery_controller.rb) for more details on supported features. + +### Known Issues + +- Doorkeeper's API mode (`Doorkeeper.configuration.api_only`) is not properly supported yet + +### Example Applications + +- [GitLab](https://gitlab.com/gitlab-org/gitlab-ce) ([original MR](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8018)) +- [Testing app for this gem](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/tree/master/spec/dummy) + +## Installation + +Make sure your application is already set up with [Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper#installation). + +Add this line to your application's `Gemfile` and run `bundle install`: + +```ruby +gem 'doorkeeper-openid_connect' +``` + +Run the installation generator to update routes and create the initializer: + +```sh +rails generate doorkeeper:openid_connect:install +``` + +Generate a migration for Active Record (other ORMs are currently not supported): + +```sh +rails generate doorkeeper:openid_connect:migration +rake db:migrate +``` + +If you're upgrading from an earlier version, check [CHANGELOG.md](CHANGELOG.md) for upgrade instructions. + +## Configuration + +Make sure you've [configured Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper#configuration) before continuing. + +Verify your settings in `config/initializers/doorkeeper.rb`: + +- `resource_owner_authenticator` + - This callback needs to returns a falsey value if the current user can't be determined: + + ```ruby + resource_owner_authenticator do + if current_user + current_user + else + redirect_to(new_user_session_url) + nil + end + end + ``` + +- `grant_flows` + - If you want to use `id_token` or `id_token token` response types you need to add `implicit_oidc` to `grant_flows`: + + ```ruby + grant_flows %w(authorization_code implicit_oidc) + ``` + +The following settings are required in `config/initializers/doorkeeper_openid_connect.rb`: + +- `issuer` + - Identifier for the issuer of the response (i.e. your application URL). The value is a case sensitive URL using the `https` scheme that contains scheme, host, and optionally, port number and path components and no query or fragment components. + - You can either pass a string value, or a block to generate the issuer dynamically based on the `resource_owner` and `application` or [request](app/controllers/doorkeeper/openid_connect/discovery_controller.rb#L123) passed to the block. +- `subject` + - Identifier for the resource owner (i.e. the authenticated user). A locally unique and never reassigned identifier within the issuer for the end-user, which is intended to be consumed by the client. The value is a case-sensitive string and must not exceed 255 ASCII characters in length. + - The database ID of the user is an acceptable choice if you don't mind leaking that information. + - If you want to provide a different subject identifier to each client, use [pairwise subject identifier](http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes) with configurations like below. + + ```ruby + # config/initializers/doorkeeper_openid_connect.rb + Doorkeeper::OpenidConnect.configure do + # ... + subject_types_supported [:pairwise] + + subject do |resource_owner, application| + Digest::SHA256.hexdigest("#{resource_owner.id}#{URI.parse(application.redirect_uri).host}#{'your_secret_salt'}") + end + # ... + end + ``` + +- `signing_key` + - Private key to be used for [JSON Web Signature](https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31). + - You can generate a private key with the `openssl` command, see e.g. [Generate an RSA keypair using OpenSSL](https://en.wikibooks.org/wiki/Cryptography/Generate_a_keypair_using_OpenSSL). + - You should not commit the key to your repository, but use an external file (in combination with `File.read`) and/or the [dotenv-rails](https://github.com/bkeepers/dotenv) gem (in combination with `ENV[...]`). +- `signing_algorithm` + - The encryption type of the private key which defaults to `:rs256`. The list of supported algorithms can be found [here](https://github.com/nov/json-jwt/wiki/JWE#supported-algorithms) +- `resource_owner_from_access_token` + - Defines how to translate the Doorkeeper access token to a resource owner model. + +The following settings are optional, but recommended for better client compatibility: + +- `auth_time_from_resource_owner` + - Returns the time of the user's last login, this can be a `Time`, `DateTime`, or any other class that responds to `to_i` + - Required to support the `max_age` parameter and the `auth_time` claim. +- `reauthenticate_resource_owner` + - Defines how to trigger reauthentication for the current user (e.g. display a password prompt, or sign-out the user and redirect to the login form). + - Required to support the `max_age` and `prompt=login` parameters. + - The block is executed in the controller's scope, so you have access to methods like `params`, `redirect_to` etc. +- `select_account_for_resource_owner` + - Defines how to trigger account selection to choose the current login user. + - Required to support the `prompt=select_account` parameter. + - The block is executed in the controller's scope, so you have access to methods like `params`, `redirect_to` etc. + +The following settings are optional: + +- `expiration` + - Expiration time after which the ID Token must not be accepted for processing by clients. + - The default is 120 seconds + +- `protocol` + - The protocol to use when generating URIs for the discovery endpoints. + - The default is `https` for production, and `http` for all other environments + - Note that the OIDC specification mandates HTTPS, so you shouldn't change this + for production environments unless you have a really good reason! + +- `end_session_endpoint` + - The URL that the user is redirected to after ending the session on the client. + - Used by implementations like <https://github.com/IdentityModel/oidc-client-js>. + - The block is executed in the controller's scope, so you have access to your route helpers. + +- `discovery_url_options` + - The URL options for every available endpoint to use when generating the endpoint URL in the + discovery response. Available endpoints: `authorization`, `token`, `revocation`, + `introspection`, `userinfo`, `jwks`, `webfinger`. + - This option requires option keys with an available endpoint and + [URL options](https://api.rubyonrails.org/v6.0.3.3/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for) + as value. + - The default is to use the request host, just like all the other URLs in the discovery response. + - This is useful when you want endpoints to use a different URL than other requests. + For example, if your Doorkeeper server is behind a firewall with other servers, you might want + other servers to use an "internal" URL to communicate with Doorkeeper, but you want to present + an "external" URL to end-users for authentication requests. Note that this setting does not + actually change the URL that your Doorkeeper server responds on - that is outside the scope of + Doorkeeper. + + ```ruby + # config/initializers/doorkeeper_openid_connect.rb + Doorkeeper::OpenidConnect.configure do + # ... + discovery_url_options do |request| + { + authorization: { host: 'host.example.com' }, + jwks: { protocol: request.ssl? ? :https : :http } + } + end + # ... + end + ``` + +### Scopes + +To perform authentication over OpenID Connect, an OAuth client needs to request the `openid` scope. This scope needs to be enabled using either `optional_scopes` in the global Doorkeeper configuration in `config/initializers/doorkeeper.rb`, or by adding it to any OAuth application's `scope` attribute. + +> Note that any application defining its own scopes won't inherit the scopes defined in the initializer, so you might have to update existing applications as well. +> +> See [Using Scopes](https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes) in the Doorkeeper wiki for more information. + +### Claims + +Claims can be defined in a `claims` block inside `config/initializers/doorkeeper_openid_connect.rb`: + +```ruby +Doorkeeper::OpenidConnect.configure do + claims do + claim :email do |resource_owner| + resource_owner.email + end + + claim :full_name do |resource_owner| + "#{resource_owner.first_name} #{resource_owner.last_name}" + end + + claim :preferred_username, scope: :openid do |resource_owner, scopes, access_token| + # Pass the resource_owner's preferred_username if the application has + # `profile` scope access. Otherwise, provide a more generic alternative. + scopes.exists?(:profile) ? resource_owner.preferred_username : "summer-sun-9449" + end + + claim :groups, response: [:id_token, :user_info] do |resource_owner| + resource_owner.groups + end + end +end +``` + +Each claim block will be passed: + +- the `resource_owner`, which is the return value of `resource_owner_authenticator` in your initializer +- the `scopes` granted by the access token, which is an instance of `Doorkeeper::OAuth::Scopes` +- the `access_token` itself, which is an instance of `Doorkeeper::AccessToken` + +By default all custom claims are only returned from the `UserInfo` endpoint and not included in the ID token. You can optionally pass a `response:` keyword with one or both of the symbols `:id_token` or `:user_info` to specify where the claim should be returned. + +You can also pass a `scope:` keyword argument on each claim to specify which OAuth scope should be required to access the claim. If you define any of the defined [Standard Claims](http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) they will by default use their [corresponding scopes](http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) (`profile`, `email`, `address` and `phone`), and any other claims will by default use the `profile` scope. Again, to use any of these scopes you need to enable them as described above. + +### Routes + +The installation generator will update your `config/routes.rb` to define all required routes: + +``` ruby +Rails.application.routes.draw do + use_doorkeeper_openid_connect + # your routes +end +``` + +This will mount the following routes: + +``` +GET /oauth/userinfo +POST /oauth/userinfo +GET /oauth/discovery/keys +GET /.well-known/openid-configuration +GET /.well-known/webfinger +``` + +With the exception of the hard-coded `/.well-known` paths (see [RFC 5785](https://tools.ietf.org/html/rfc5785)) you can customize routes in the same way as with Doorkeeper, please refer to [this page on their wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-routes#version--05-1). + +### Nonces + +To support clients who send nonces you have to tweak Doorkeeper's authorization view so the parameter is passed on. + +If you don't already have custom templates, run this generator in your Rails application to add them: + +```sh +rails generate doorkeeper:views +``` + +Then tweak the template as follows: + +```patch +--- i/app/views/doorkeeper/authorizations/new.html.erb ++++ w/app/views/doorkeeper/authorizations/new.html.erb +@@ -26,6 +26,7 @@ + <%= hidden_field_tag :state, @pre_auth.state %> + <%= hidden_field_tag :response_type, @pre_auth.response_type %> + <%= hidden_field_tag :scope, @pre_auth.scope %> ++ <%= hidden_field_tag :nonce, @pre_auth.nonce %> + <%= submit_tag t('doorkeeper.authorizations.buttons.authorize'), class: "btn btn-success btn-lg btn-block" %> + <% end %> + <%= form_tag oauth_authorization_path, method: :delete do %> +@@ -34,6 +35,7 @@ + <%= hidden_field_tag :state, @pre_auth.state %> + <%= hidden_field_tag :response_type, @pre_auth.response_type %> + <%= hidden_field_tag :scope, @pre_auth.scope %> ++ <%= hidden_field_tag :nonce, @pre_auth.nonce %> + <%= submit_tag t('doorkeeper.authorizations.buttons.deny'), class: "btn btn-danger btn-lg btn-block" %> + <% end %> + </div> +``` + +### Internationalization (I18n) + +We use Rails locale files for error messages and scope descriptions, see [config/locales/en.yml](config/locales/en.yml). You can override these by adding them to your own translations in `config/locale`. + +## Development + +Run `bundle install` to setup all development dependencies. + +To run all specs: + +```sh +bundle exec rake spec +``` + +To generate and run migrations in the test application: + +```sh +bundle exec rake migrate +``` + +To run the local engine server: + +```sh +bundle exec rake server +``` + +By default, the latest Rails version is used. To use a specific version run: + +``` +rails=4.2.0 bundle update +``` + +## License + +Doorkeeper::OpenidConnect is released under the [MIT License](http://www.opensource.org/licenses/MIT). + +## Sponsors + +Initial development of this project was sponsored by [PlayOn! Sports](https://github.com/playon). diff --git a/vendor/gems/doorkeeper-openid_connect/Rakefile b/vendor/gems/doorkeeper-openid_connect/Rakefile new file mode 100644 index 0000000000000000000000000000000000000000..a6fe1e73c4d57664927aff2a5217d1792b35b070 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/Rakefile @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +ENV['RAILS_ENV'] ||= 'test' + +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new + +task default: :spec +task test: :spec + +desc 'Generate and run migrations in the test application' +task :migrate do + Dir.chdir('spec/dummy') do + system('bin/rails generate doorkeeper:openid_connect:migration') + system('bin/rake db:migrate') + end +end + +desc 'Run server in the test application' +task :server do + Dir.chdir('spec/dummy') do + system('bin/rails server') + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/app/controllers/concerns/doorkeeper/openid_connect/authorizations_extension.rb b/vendor/gems/doorkeeper-openid_connect/app/controllers/concerns/doorkeeper/openid_connect/authorizations_extension.rb new file mode 100644 index 0000000000000000000000000000000000000000..6a906b7d1a76218442435733ec17de06abf115be --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/app/controllers/concerns/doorkeeper/openid_connect/authorizations_extension.rb @@ -0,0 +1,12 @@ +module Doorkeeper + module OpenidConnect + module AuthorizationsExtension + private + + def pre_auth_param_fields + super.append(:nonce) + end + end + end +end + diff --git a/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/discovery_controller.rb b/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/discovery_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..f834139c596a45ca5495cd525c8d6db5a4f21b7b --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/discovery_controller.rb @@ -0,0 +1,146 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + class DiscoveryController < ::Doorkeeper::ApplicationMetalController + include Doorkeeper::Helpers::Controller + + WEBFINGER_RELATION = 'http://openid.net/specs/connect/1.0/issuer' + + def provider + render json: provider_response + end + + def webfinger + render json: webfinger_response + end + + def keys + render json: keys_response + end + + private + + def provider_response + doorkeeper = ::Doorkeeper.configuration + openid_connect = ::Doorkeeper::OpenidConnect.configuration + + { + issuer: issuer, + authorization_endpoint: oauth_authorization_url(authorization_url_options), + token_endpoint: oauth_token_url(token_url_options), + revocation_endpoint: oauth_revoke_url(revocation_url_options), + introspection_endpoint: respond_to?(:oauth_introspect_url) ? oauth_introspect_url(introspection_url_options) : nil, + userinfo_endpoint: oauth_userinfo_url(userinfo_url_options), + jwks_uri: oauth_discovery_keys_url(jwks_url_options), + end_session_endpoint: instance_exec(&openid_connect.end_session_endpoint), + + scopes_supported: doorkeeper.scopes, + + # TODO: support id_token response type + response_types_supported: doorkeeper.authorization_response_types, + response_modes_supported: response_modes_supported(doorkeeper), + grant_types_supported: grant_types_supported(doorkeeper), + + # TODO: look into doorkeeper-jwt_assertion for these + # 'client_secret_jwt', + # 'private_key_jwt' + token_endpoint_auth_methods_supported: %w[client_secret_basic client_secret_post], + + subject_types_supported: openid_connect.subject_types_supported, + + id_token_signing_alg_values_supported: [ + ::Doorkeeper::OpenidConnect.signing_algorithm + ], + + claim_types_supported: [ + 'normal', + + # TODO: support these + # 'aggregated', + # 'distributed', + ], + + claims_supported: %w[ + iss + sub + aud + exp + iat + ] | openid_connect.claims.to_h.keys, + + code_challenge_methods_supported: code_challenge_methods_supported(doorkeeper), + }.compact + end + + def grant_types_supported(doorkeeper) + grant_types_supported = doorkeeper.grant_flows.dup + grant_types_supported << 'refresh_token' if doorkeeper.refresh_token_enabled? + grant_types_supported + end + + def response_modes_supported(doorkeeper) + doorkeeper.authorization_response_flows.flat_map(&:response_mode_matches).uniq + end + + def code_challenge_methods_supported(doorkeeper) + return unless doorkeeper.access_grant_model.pkce_supported? + + %w[plain S256] + end + + def webfinger_response + { + subject: params.require(:resource), + links: [ + { + rel: WEBFINGER_RELATION, + href: root_url(webfinger_url_options), + } + ] + } + end + + def keys_response + signing_key = Doorkeeper::OpenidConnect.signing_key_normalized + + { + keys: [ + signing_key.merge( + use: 'sig', + alg: Doorkeeper::OpenidConnect.signing_algorithm + ) + ] + } + end + + def protocol + Doorkeeper::OpenidConnect.configuration.protocol.call + end + + def discovery_url_options + Doorkeeper::OpenidConnect.configuration.discovery_url_options.call(request) + end + + def discovery_url_default_options + { + protocol: protocol + } + end + + def issuer + if Doorkeeper::OpenidConnect.configuration.issuer.respond_to?(:call) + Doorkeeper::OpenidConnect.configuration.issuer.call(request).to_s + else + Doorkeeper::OpenidConnect.configuration.issuer + end + end + + %i[authorization token revocation introspection userinfo jwks webfinger].each do |endpoint| + define_method :"#{endpoint}_url_options" do + discovery_url_default_options.merge(discovery_url_options[endpoint.to_sym] || {}) + end + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/userinfo_controller.rb b/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/userinfo_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..c6ace1aab2a7d131e7343379e821a8c589bac64b --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/app/controllers/doorkeeper/openid_connect/userinfo_controller.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + class UserinfoController < ::Doorkeeper::ApplicationMetalController + before_action -> { doorkeeper_authorize! :openid } + + def show + render json: Doorkeeper::OpenidConnect::UserInfo.new(doorkeeper_token), status: :ok + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/bin/console b/vendor/gems/doorkeeper-openid_connect/bin/console new file mode 100755 index 0000000000000000000000000000000000000000..8c3eaafde17c761e21bf2bd88e2bbcfadba8cd0c --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/bin/console @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'bundler/setup' +Bundler.require :default + +require 'doorkeeper/openid_connect' + +require 'pry' +Pry.start diff --git a/vendor/gems/doorkeeper-openid_connect/bin/setup b/vendor/gems/doorkeeper-openid_connect/bin/setup new file mode 100755 index 0000000000000000000000000000000000000000..dce67d860af47a4eb630117ce03624bae45dcf26 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/vendor/gems/doorkeeper-openid_connect/config/locales/en.yml b/vendor/gems/doorkeeper-openid_connect/config/locales/en.yml new file mode 100644 index 0000000000000000000000000000000000000000..1bed506b2cf19142aac85a474e901e8bab8f5253 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/config/locales/en.yml @@ -0,0 +1,23 @@ +en: + doorkeeper: + scopes: + openid: 'Authenticate your account' + profile: 'View your profile information' + email: 'View your email address' + address: 'View your physical address' + phone: 'View your phone number' + errors: + messages: + login_required: 'The authorization server requires end-user authentication' + consent_required: 'The authorization server requires end-user consent' + interaction_required: 'The authorization server requires end-user interaction' + account_selection_required: 'The authorization server requires end-user account selection' + openid_connect: + errors: + messages: + # Configuration error messages + resource_owner_from_access_token_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.resource_owner_from_access_token missing configuration.' + auth_time_from_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.auth_time_from_resource_owner missing configuration.' + reauthenticate_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.reauthenticate_resource_owner missing configuration.' + select_account_for_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.select_account_for_resource_owner missing configuration.' + subject_not_configured: 'ID Token generation failed due to Doorkeeper::OpenidConnect.configure.subject missing configuration.' diff --git a/vendor/gems/doorkeeper-openid_connect/doorkeeper-openid_connect.gemspec b/vendor/gems/doorkeeper-openid_connect/doorkeeper-openid_connect.gemspec new file mode 100644 index 0000000000000000000000000000000000000000..bb050b8a6b4cf2909d8fce226eb7b3cbb99517b9 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/doorkeeper-openid_connect.gemspec @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +$LOAD_PATH.push File.expand_path('lib', __dir__) +require 'doorkeeper/openid_connect/version' + +Gem::Specification.new do |spec| + spec.name = 'doorkeeper-openid_connect' + spec.version = Doorkeeper::OpenidConnect::VERSION + spec.authors = ['Sam Dengler', 'Markus Koller', 'Nikita Bulai'] + spec.email = ['sam.dengler@playonsports.com', 'markus-koller@gmx.ch', 'bulajnikita@gmail.com'] + spec.homepage = 'https://github.com/doorkeeper-gem/doorkeeper-openid_connect' + spec.summary = 'OpenID Connect extension for Doorkeeper.' + spec.description = 'OpenID Connect extension for Doorkeeper.' + spec.license = 'MIT' + + spec.files = Dir[ + "{app,config,lib}/**/*", + "CHANGELOG.md", + "LICENSE.txt", + "README.md", + ] + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ['lib'] + + spec.required_ruby_version = '>= 2.7' + + spec.add_runtime_dependency 'doorkeeper', '>= 5.5', '< 5.9' + spec.add_runtime_dependency 'jwt', '>= 2.5' + + spec.add_development_dependency 'conventional-changelog', '~> 1.2' + spec.add_development_dependency 'factory_bot' + spec.add_development_dependency 'pry-byebug' + spec.add_development_dependency 'rspec-rails' + spec.add_development_dependency 'sqlite3', '>= 1.3.6' +end diff --git a/vendor/gems/doorkeeper-openid_connect/gemfiles/doorkeeper_master.gemfile b/vendor/gems/doorkeeper-openid_connect/gemfiles/doorkeeper_master.gemfile new file mode 100644 index 0000000000000000000000000000000000000000..5157472158ef624c7ddbd05184b9a89653b2d116 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/gemfiles/doorkeeper_master.gemfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rails', '~> 7.0.0' +gem 'rails-controller-testing' +gem 'doorkeeper', git: 'https://github.com/doorkeeper-gem/doorkeeper.git' + +gemspec path: '../' diff --git a/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.0.gemfile b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.0.gemfile new file mode 100644 index 0000000000000000000000000000000000000000..39898608de60e967b6b91a4216e0860cde4455b1 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.0.gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rails', '~> 6.0.0' +gem 'rails-controller-testing' + +gemspec path: '../' diff --git a/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.1.gemfile b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.1.gemfile new file mode 100644 index 0000000000000000000000000000000000000000..df88b047af292d1124fee9c46be860844e7c4af6 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_6.1.gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rails', '~> 6.1.0' +gem 'rails-controller-testing' + +gemspec path: '../' diff --git a/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_7.0.gemfile b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_7.0.gemfile new file mode 100644 index 0000000000000000000000000000000000000000..4032a5772ee3390642a9f97a6b417809cc892b78 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/gemfiles/rails_7.0.gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rails', '~> 7.0.0' +gem 'rails-controller-testing' + +gemspec path: '../' diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_request.rb new file mode 100644 index 0000000000000000000000000000000000000000..e6054508cc04c7c616ce02cdbe2c1a31549345a8 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_request.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Doorkeeper + module OAuth + class IdTokenRequest + attr_accessor :pre_auth, :auth, :resource_owner + + def initialize(pre_auth, resource_owner) + @pre_auth = pre_auth + @resource_owner = resource_owner + end + + def authorize + @auth = Authorization::Token.new(pre_auth, resource_owner) + if @auth.respond_to?(:issue_token!) + @auth.issue_token! + else + @auth.issue_token + end + response + end + + def deny + pre_auth.error = :access_denied + pre_auth.error_response + end + + private + + def response + id_token = Doorkeeper::OpenidConnect::IdToken.new(auth.token, pre_auth.nonce) + + IdTokenResponse.new(pre_auth, auth, id_token) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_response.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_response.rb new file mode 100644 index 0000000000000000000000000000000000000000..a555f2d2d60e1961951893d996caeda126790f73 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_response.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Doorkeeper + module OAuth + class IdTokenResponse < BaseResponse + include OAuth::Helpers + + attr_accessor :pre_auth, :auth, :id_token + + def initialize(pre_auth, auth, id_token) + @pre_auth = pre_auth + @auth = auth + @id_token = id_token + end + + def redirectable? + true + end + + def body + { + expires_in: auth.token.expires_in_seconds, + state: pre_auth.state, + id_token: id_token.as_jws_token + } + end + + def redirect_uri + Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, body) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_request.rb new file mode 100644 index 0000000000000000000000000000000000000000..cfcfb4ee01bbd4e18b297eed48e7608d0fd3115c --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_request.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Doorkeeper + module OAuth + class IdTokenTokenRequest < IdTokenRequest + private + + def response + id_token_token = Doorkeeper::OpenidConnect::IdTokenToken.new(auth.token, pre_auth.nonce) + + IdTokenTokenResponse.new(pre_auth, auth, id_token_token) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_response.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_response.rb new file mode 100644 index 0000000000000000000000000000000000000000..ac212d5b5340ab9a6e3155cec55a59926ed40028 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/oauth/id_token_token_response.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Doorkeeper + module OAuth + class IdTokenTokenResponse < IdTokenResponse + def body + super.merge({ + access_token: auth.token.token, + token_type: auth.token.token_type + }) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect.rb new file mode 100644 index 0000000000000000000000000000000000000000..4d0de3c3803ccf0d6d474b36fdf85e72aaa70e31 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'doorkeeper' +require 'active_model' +require 'jwt' + +require 'doorkeeper/request' +require 'doorkeeper/request/id_token' +require 'doorkeeper/request/id_token_token' +require 'doorkeeper/oauth/id_token_request' +require 'doorkeeper/oauth/id_token_token_request' +require 'doorkeeper/oauth/id_token_response' +require 'doorkeeper/oauth/id_token_token_response' + +require 'doorkeeper/openid_connect/claims_builder' +require 'doorkeeper/openid_connect/claims/claim' +require 'doorkeeper/openid_connect/claims/normal_claim' +require 'doorkeeper/openid_connect/config' +require 'doorkeeper/openid_connect/engine' +require 'doorkeeper/openid_connect/errors' +require 'doorkeeper/openid_connect/id_token' +require 'doorkeeper/openid_connect/id_token_token' +require 'doorkeeper/openid_connect/user_info' +require 'doorkeeper/openid_connect/version' + +require 'doorkeeper/openid_connect/helpers/controller' + +require 'doorkeeper/openid_connect/oauth/authorization/code' +require 'doorkeeper/openid_connect/oauth/authorization_code_request' +require 'doorkeeper/openid_connect/oauth/password_access_token_request' +require 'doorkeeper/openid_connect/oauth/pre_authorization' +require 'doorkeeper/openid_connect/oauth/token_response' + +require 'doorkeeper/openid_connect/orm/active_record' + +require 'doorkeeper/openid_connect/rails/routes' + +module Doorkeeper + module OpenidConnect + def self.signing_algorithm + configuration.signing_algorithm.to_s.upcase.to_sym + end + + def self.signing_key + key = + if %i[HS256 HS384 HS512].include?(signing_algorithm) + configuration.signing_key + else + OpenSSL::PKey.read(configuration.signing_key) + end + ::JWT::JWK.new(key, { kid_generator: ::JWT::JWK::Thumbprint }) + end + + def self.signing_key_normalized + signing_key.export + end + + Doorkeeper::GrantFlow.register( + :id_token, + response_type_matches: 'id_token', + response_mode_matches: %w[fragment form_post], + response_type_strategy: Doorkeeper::Request::IdToken, + ) + + Doorkeeper::GrantFlow.register( + 'id_token token', + response_type_matches: 'id_token token', + response_mode_matches: %w[fragment form_post], + response_type_strategy: Doorkeeper::Request::IdTokenToken, + ) + + Doorkeeper::GrantFlow.register_alias( + 'implicit_oidc', as: ['implicit', 'id_token', 'id_token token'] + ) + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/aggregated_claim.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/aggregated_claim.rb new file mode 100644 index 0000000000000000000000000000000000000000..98732f49a22a6e942fdebbe82a81865aa30b6e01 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/aggregated_claim.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module Claims + class AggregatedClaim < Claim + attr_accessor :jwt + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/claim.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/claim.rb new file mode 100644 index 0000000000000000000000000000000000000000..a0cfa8d4f66126508c26971280ff09de9cd2afaa --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/claim.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module Claims + class Claim + attr_accessor :name, :response, :scope + + # http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims + # http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims + STANDARD_CLAIMS = { + profile: %i[ + name family_name given_name middle_name nickname preferred_username + profile picture website gender birthdate zoneinfo locale updated_at + ], + email: %i[email email_verified], + address: %i[address], + phone: %i[phone_number phone_number_verified], + }.freeze + + def initialize(options = {}) + @name = options[:name].to_sym + @response = Array.wrap(options[:response]) + @scope = options[:scope].to_sym if options[:scope] + + # use default scope for Standard Claims + @scope ||= STANDARD_CLAIMS.find do |_scope, claims| + claims.include? @name + end.try(:first) + + # use profile scope as default fallback + @scope ||= :profile + end + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/distributed_claim.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/distributed_claim.rb new file mode 100644 index 0000000000000000000000000000000000000000..3a0d4f874d54e9a9015a9e014dfe3dfd4a740ebd --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/distributed_claim.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module Claims + class DistributedClaim < Claim + attr_accessor :endpoint, :access_token + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/normal_claim.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/normal_claim.rb new file mode 100644 index 0000000000000000000000000000000000000000..16b012665518254e5fcdc4c25652dc8322632311 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims/normal_claim.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module Claims + class NormalClaim < Claim + attr_reader :generator + + def initialize(options = {}) + super(options) + @generator = options[:generator] + end + + def type + :normal + end + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims_builder.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims_builder.rb new file mode 100644 index 0000000000000000000000000000000000000000..69df8aaaae02e95a240646dc076b632c1966277d --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/claims_builder.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'ostruct' + +module Doorkeeper + module OpenidConnect + class ClaimsBuilder + def self.generate(access_token, response) + resource_owner = Doorkeeper::OpenidConnect.configuration.resource_owner_from_access_token.call(access_token) + + Doorkeeper::OpenidConnect.configuration.claims.to_h.map do |name, claim| + if access_token.scopes.exists?(claim.scope) && claim.response.include?(response) + [name, claim.generator.call(resource_owner, access_token.scopes, access_token)] + end + end.compact.to_h + end + + def initialize(&block) + @claims = OpenStruct.new + instance_eval(&block) + end + + def build + @claims + end + + def normal_claim(name, response: [:user_info], scope: nil, &block) + @claims[name] = + Claims::NormalClaim.new( + name: name, + response: response, + scope: scope, + generator: block + ) + end + alias claim normal_claim + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/config.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/config.rb new file mode 100644 index 0000000000000000000000000000000000000000..6ebce486d238f86369408f45309bf48bd6e5105c --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/config.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + def self.configure(&block) + if Doorkeeper.configuration.orm != :active_record + raise Errors::InvalidConfiguration, 'Doorkeeper OpenID Connect currently only supports the ActiveRecord ORM adapter' + end + + @config = Config::Builder.new(&block).build + end + + def self.configuration + @config || (raise Errors::MissingConfiguration) + end + + class Config + class Builder + def initialize(&block) + @config = Config.new + instance_eval(&block) + end + + def build + @config + end + + def jws_public_key(*_args) + puts 'DEPRECATION WARNING: `jws_public_key` is not needed anymore and will be removed in a future version, please remove it from config/initializers/doorkeeper_openid_connect.rb' + end + + def jws_private_key(*args) + puts 'DEPRECATION WARNING: `jws_private_key` has been replaced by `signing_key` and will be removed in a future version, please remove it from config/initializers/doorkeeper_openid_connect.rb' + signing_key(*args) + end + end + + mattr_reader(:builder_class) { Config::Builder } + + extend ::Doorkeeper::Config::Option + + option :issuer + option :signing_key + option :signing_algorithm, default: :rs256 + option :subject_types_supported, default: [:public] + + option :resource_owner_from_access_token, default: lambda { |*_| + raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.resource_owner_from_access_token_not_configured') + } + + option :auth_time_from_resource_owner, default: lambda { |*_| + raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.auth_time_from_resource_owner_not_configured') + } + + option :reauthenticate_resource_owner, default: lambda { |*_| + raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.reauthenticate_resource_owner_not_configured') + } + + option :select_account_for_resource_owner, default: lambda { |*_| + raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.select_account_for_resource_owner_not_configured') + } + + option :subject, default: lambda { |*_| + raise Errors::InvalidConfiguration, I18n.translate('doorkeeper.openid_connect.errors.messages.subject_not_configured') + } + + option :expiration, default: 120 + + option :claims, builder_class: ClaimsBuilder + + option :protocol, default: lambda { |*_| + ::Rails.env.production? ? :https : :http + } + + option :end_session_endpoint, default: lambda { |*_| + nil + } + + option :discovery_url_options, default: lambda { |*_| + {} + } + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/engine.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/engine.rb new file mode 100644 index 0000000000000000000000000000000000000000..6eb5e3ea0965c0f0f3f9565acf6e049a9ff91432 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/engine.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + class Engine < ::Rails::Engine + initializer 'doorkeeper.openid_connect.routes' do + Doorkeeper::OpenidConnect::Rails::Routes.install! + end + + config.to_prepare do + Doorkeeper::AuthorizationsController.prepend Doorkeeper::OpenidConnect::AuthorizationsExtension + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/errors.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/errors.rb new file mode 100644 index 0000000000000000000000000000000000000000..ca7823b24a02a3ead739eeeb3f5e4f350155b244 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/errors.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module Errors + class OpenidConnectError < StandardError + def type + self.class.name.demodulize.underscore.to_sym + end + end + + # internal errors + class InvalidConfiguration < OpenidConnectError; end + class MissingConfiguration < OpenidConnectError + def initialize + super('Configuration for Doorkeeper OpenID Connect missing. Do you have doorkeeper_openid_connect initializer?') + end + end + + # OAuth 2.0 errors + # https://tools.ietf.org/html/rfc6749#section-4.1.2.1 + class InvalidRequest < OpenidConnectError; end + + # OpenID Connect 1.0 errors + # http://openid.net/specs/openid-connect-core-1_0.html#AuthError + class LoginRequired < OpenidConnectError; end + class ConsentRequired < OpenidConnectError; end + class InteractionRequired < OpenidConnectError; end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/helpers/controller.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/helpers/controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..d3e8396120a041fb9c1758b3f3ce111e16c35069 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/helpers/controller.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module Helpers + module Controller + private + + # FIXME: remove after Doorkeeper will merge it + def current_resource_owner + return @current_resource_owner if defined?(@current_resource_owner) + + super + end + + def authenticate_resource_owner! + super.tap do |owner| + next unless oidc_authorization_request? + + handle_oidc_prompt_param!(owner) + handle_oidc_max_age_param!(owner) + end + rescue Errors::OpenidConnectError => e + handle_oidc_error!(e) + end + + def oidc_authorization_request? + controller_path == Doorkeeper::Rails::Routes.mapping[:authorizations][:controllers] && + action_name == 'new' && + pre_auth.valid? && + pre_auth.scopes.include?('openid') + end + + def handle_oidc_error!(exception) + # clear the previous response body to avoid a DoubleRenderError + self.response_body = nil + + # FIXME: workaround for Rails 5, see https://github.com/rails/rails/issues/25106 + @_response_body = nil + + error_response = if exception.type == :invalid_request + ::Doorkeeper::OAuth::InvalidRequestResponse.new( + name: exception.type, + state: params[:state], + redirect_uri: params[:redirect_uri], + response_on_fragment: pre_auth.response_on_fragment?, + ) + else + ::Doorkeeper::OAuth::ErrorResponse.new( + name: exception.type, + state: params[:state], + redirect_uri: params[:redirect_uri], + response_on_fragment: pre_auth.response_on_fragment?, + ) + end + + response.headers.merge!(error_response.headers) + + # NOTE: Assign error_response to @authorize_response then use redirect_or_render method that are defined at + # doorkeeper's authorizations_controller. + # - https://github.com/doorkeeper-gem/doorkeeper/blob/v5.5.0/app/controllers/doorkeeper/authorizations_controller.rb#L110 + # - https://github.com/doorkeeper-gem/doorkeeper/blob/v5.5.0/app/controllers/doorkeeper/authorizations_controller.rb#L52 + @authorize_response = error_response + redirect_or_render(@authorize_response) + end + + def handle_oidc_prompt_param!(owner) + prompt_values ||= params[:prompt].to_s.split(/ +/).uniq + + prompt_values.each do |prompt| + case prompt + when 'none' + raise Errors::InvalidRequest if (prompt_values - ['none']).any? + raise Errors::LoginRequired unless owner + raise Errors::ConsentRequired if oidc_consent_required? + when 'login' + reauthenticate_oidc_resource_owner(owner) if owner + when 'consent' + render :new if owner + when 'select_account' + select_account_for_oidc_resource_owner(owner) + else + raise Errors::InvalidRequest + end + end + end + + def handle_oidc_max_age_param!(owner) + max_age = params[:max_age].to_i + return unless max_age > 0 && owner + + auth_time = instance_exec( + owner, + &Doorkeeper::OpenidConnect.configuration.auth_time_from_resource_owner + ) + + if !auth_time || (Time.zone.now - auth_time) > max_age + reauthenticate_oidc_resource_owner(owner) + end + end + + def return_without_oidc_prompt_param(prompt_value) + return_to = URI.parse(request.path) + return_to.query = request.query_parameters.tap do |params| + params['prompt'] = params['prompt'].to_s.sub(/\b#{prompt_value}\s*\b/, '').strip + params.delete('prompt') if params['prompt'].blank? + end.to_query + return_to.to_s + end + + def reauthenticate_oidc_resource_owner(owner) + return_to = return_without_oidc_prompt_param('login') + + instance_exec( + owner, + return_to, + &Doorkeeper::OpenidConnect.configuration.reauthenticate_resource_owner + ) + + raise Errors::LoginRequired unless performed? + end + + def oidc_consent_required? + !skip_authorization? && !matching_token? + end + + def select_account_for_oidc_resource_owner(owner) + return_to = return_without_oidc_prompt_param('select_account') + + instance_exec( + owner, + return_to, + &Doorkeeper::OpenidConnect.configuration.select_account_for_resource_owner + ) + end + end + end + end + + Helpers::Controller.prepend OpenidConnect::Helpers::Controller +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token.rb new file mode 100644 index 0000000000000000000000000000000000000000..69dfb0c92bb5582f500e649fd19e85fec1dfee02 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + class IdToken + include ActiveModel::Validations + + attr_reader :nonce + + def initialize(access_token, nonce = nil) + @access_token = access_token + @nonce = nonce + @resource_owner = Doorkeeper::OpenidConnect.configuration.resource_owner_from_access_token.call(access_token) + @issued_at = Time.zone.now + end + + def claims + { + iss: issuer, + sub: subject, + aud: audience, + exp: expiration, + iat: issued_at, + nonce: nonce, + auth_time: auth_time + }.merge ClaimsBuilder.generate(@access_token, :id_token) + end + + def as_json(*_) + claims.reject { |_, value| value.nil? || value == '' } + end + + def as_jws_token + ::JWT.encode(as_json, + Doorkeeper::OpenidConnect.signing_key.keypair, + Doorkeeper::OpenidConnect.signing_algorithm.to_s, + { typ: 'JWT', kid: Doorkeeper::OpenidConnect.signing_key.kid } + ).to_s + end + + private + + def issuer + if Doorkeeper::OpenidConnect.configuration.issuer.respond_to?(:call) + Doorkeeper::OpenidConnect.configuration.issuer.call(@resource_owner, @access_token.application).to_s + else + Doorkeeper::OpenidConnect.configuration.issuer + end + end + + def subject + Doorkeeper::OpenidConnect.configuration.subject.call(@resource_owner, @access_token.application).to_s + end + + def audience + @access_token.application.try(:uid) + end + + def expiration + (@issued_at.utc + Doorkeeper::OpenidConnect.configuration.expiration).to_i + end + + def issued_at + @issued_at.utc.to_i + end + + def auth_time + Doorkeeper::OpenidConnect.configuration.auth_time_from_resource_owner.call(@resource_owner).try(:to_i) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token_token.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token_token.rb new file mode 100644 index 0000000000000000000000000000000000000000..6e78fea88cd297b30f282eb05279532784d3e77c --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/id_token_token.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + class IdTokenToken < IdToken + def claims + super.merge(at_hash: at_hash) + end + + private + + # The at_hash is build according to the following standard: + # + # http://openid.net/specs/openid-connect-implicit-1_0.html#IDToken + # + # at_hash: + # REQUIRED. Access Token hash value. If the ID Token is issued with an + # access_token in an Implicit Flow, this is REQUIRED, which is the case + # for this subset of OpenID Connect. Its value is the base64url encoding + # of the left-most half of the hash of the octets of the ASCII + # representation of the access_token value, where the hash algorithm + # used is the hash algorithm used in the alg Header Parameter of the + # ID Token's JOSE Header. For instance, if the alg is RS256, hash the + # access_token value with SHA-256, then take the left-most 128 bits and + # base64url-encode them. The at_hash value is a case-sensitive string. + def at_hash + sha256 = Digest::SHA256.new + token = @access_token.token + hashed_token = sha256.digest(token) + first_half = hashed_token[0...hashed_token.length / 2] + Base64.urlsafe_encode64(first_half).tr('=', '') + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization/code.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization/code.rb new file mode 100644 index 0000000000000000000000000000000000000000..f04bb0412ac90199f71b9faeb8f53d6b383d2367 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization/code.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module OAuth + module Authorization + module Code + if Doorkeeper::OAuth::Authorization::Code.method_defined?(:issue_token!) + def issue_token! + super.tap do |access_grant| + create_openid_request(access_grant) if pre_auth.nonce.present? + end + end + + alias issue_token issue_token! + else + # FIXME: drop this after dropping support of Doorkeeper < 5.4 + def issue_token + super.tap do |access_grant| + create_openid_request(access_grant) if pre_auth.nonce.present? + end + end + end + + private + + def create_openid_request(access_grant) + ::Doorkeeper::OpenidConnect::Request.create!( + access_grant: access_grant, + nonce: pre_auth.nonce + ) + end + end + end + end + end + + OAuth::Authorization::Code.prepend OpenidConnect::OAuth::Authorization::Code +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization_code_request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization_code_request.rb new file mode 100644 index 0000000000000000000000000000000000000000..1044d6638507187ca5dd298903ad169a6a5797d8 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/authorization_code_request.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module OAuth + module AuthorizationCodeRequest + private + + def after_successful_response + super + + nonce = + if (openid_request = grant.openid_request) + openid_request.destroy! + openid_request.nonce + end + + id_token = Doorkeeper::OpenidConnect::IdToken.new(access_token, nonce) + @response.id_token = id_token + end + end + end + end + + OAuth::AuthorizationCodeRequest.prepend OpenidConnect::OAuth::AuthorizationCodeRequest +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/password_access_token_request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/password_access_token_request.rb new file mode 100644 index 0000000000000000000000000000000000000000..9e00f639ad89e1bdfe9a0c6d1a4827465fecaeaa --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/password_access_token_request.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module OAuth + module PasswordAccessTokenRequest + attr_reader :nonce + + if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.1') + def initialize(server, client, credentials, resource_owner, parameters = {}) + super + @nonce = parameters[:nonce] + end + else + def initialize(server, client, resource_owner, parameters = {}) + super + @nonce = parameters[:nonce] + end + end + + private + + def after_successful_response + id_token = Doorkeeper::OpenidConnect::IdToken.new(access_token, nonce) + @response.id_token = id_token + super + end + end + end + end + + OAuth::PasswordAccessTokenRequest.prepend OpenidConnect::OAuth::PasswordAccessTokenRequest +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/pre_authorization.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/pre_authorization.rb new file mode 100644 index 0000000000000000000000000000000000000000..231f065a26836af46cf8503701f7d3f4a2012e98 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/pre_authorization.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module OAuth + module PreAuthorization + attr_reader :nonce + + def initialize(server, attrs = {}, resource_owner = nil) + super + @nonce = attrs[:nonce] + end + + # NOTE: Auto get default response_mode of specified response_type if response_mode is not + # yet present. We can delete this method after Doorkeeper's minimize version support it. + def response_on_fragment? + return response_mode == 'fragment' if response_mode.present? + + grant_flow = server.authorization_response_flows.detect do |flow| + flow.matches_response_type?(response_type) + end + + grant_flow&.default_response_mode == 'fragment' + end + end + end + end + + OAuth::PreAuthorization.prepend OpenidConnect::OAuth::PreAuthorization +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/token_response.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/token_response.rb new file mode 100644 index 0000000000000000000000000000000000000000..9aa3c4139619dc218454b6b08b4b493e8bcb017d --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/oauth/token_response.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module OAuth + module TokenResponse + attr_accessor :id_token + + def body + if token.includes_scope? 'openid' + id_token = self.id_token || Doorkeeper::OpenidConnect::IdToken.new(token) + + super + .merge(id_token: id_token.as_jws_token) + .reject { |_, value| value.blank? } + else + super + end + end + end + end + end + + OAuth::TokenResponse.prepend OpenidConnect::OAuth::TokenResponse +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record.rb new file mode 100644 index 0000000000000000000000000000000000000000..e9005ab6ed946db5bdfc685a63a5516baaa4923a --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'active_support/lazy_load_hooks' + +module Doorkeeper + module OpenidConnect + autoload :AccessGrant, "doorkeeper/openid_connect/orm/active_record/access_grant" + autoload :Request, "doorkeeper/openid_connect/orm/active_record/request" + + module Orm + module ActiveRecord + def run_hooks + super + + if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.0') + Doorkeeper.config.access_grant_model.prepend Doorkeeper::OpenidConnect::AccessGrant + else + Doorkeeper::AccessGrant.prepend Doorkeeper::OpenidConnect::AccessGrant + end + + if Doorkeeper.configuration.respond_to?(:active_record_options) && Doorkeeper.configuration.active_record_options[:establish_connection] + [Doorkeeper::OpenidConnect::Request].each do |c| + c.send :establish_connection, Doorkeeper.configuration.active_record_options[:establish_connection] + end + end + end + + def initialize_models! + super + ActiveSupport.on_load(:active_record) do + require 'doorkeeper/openid_connect/orm/active_record/access_grant' + require 'doorkeeper/openid_connect/orm/active_record/request' + + if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.0') + Doorkeeper.config.access_grant_model.prepend Doorkeeper::OpenidConnect::AccessGrant + else + Doorkeeper::AccessGrant.prepend Doorkeeper::OpenidConnect::AccessGrant + end + + if Doorkeeper.configuration.active_record_options[:establish_connection] + [Doorkeeper::OpenidConnect::Request].each do |c| + c.send :establish_connection, Doorkeeper.configuration.active_record_options[:establish_connection] + end + end + end + end + end + end + end + + Orm::ActiveRecord.singleton_class.send :prepend, OpenidConnect::Orm::ActiveRecord +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb new file mode 100644 index 0000000000000000000000000000000000000000..3e51f45e63dd55d176028de98b2002d0aef11ffc --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module AccessGrant + def self.prepended(base) + base.class_eval do + has_one :openid_request, + class_name: 'Doorkeeper::OpenidConnect::Request', + foreign_key: 'access_grant_id', + inverse_of: :access_grant, + dependent: :delete + end + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/request.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/request.rb new file mode 100644 index 0000000000000000000000000000000000000000..009ba7bd752d76c3a1864f9ebff7eaf9d93ff9e2 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/orm/active_record/request.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + class Request < ::ActiveRecord::Base + self.table_name = "#{table_name_prefix}oauth_openid_requests#{table_name_suffix}".to_sym + + validates :access_grant_id, :nonce, presence: true + + if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.0') + belongs_to :access_grant, + class_name: Doorkeeper.config.access_grant_class.to_s, + inverse_of: :openid_request + else + belongs_to :access_grant, + class_name: 'Doorkeeper::AccessGrant', + inverse_of: :openid_request + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes.rb new file mode 100644 index 0000000000000000000000000000000000000000..2a44c27f6164a883649d417a09dc0ff15fb4f804 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'doorkeeper/openid_connect/rails/routes/mapping' +require 'doorkeeper/openid_connect/rails/routes/mapper' + +module Doorkeeper + module OpenidConnect + module Rails + class Routes + module Helper + def use_doorkeeper_openid_connect(options = {}, &block) + Doorkeeper::OpenidConnect::Rails::Routes.new(self, &block).generate_routes!(options) + end + end + + def self.install! + ActionDispatch::Routing::Mapper.include Doorkeeper::OpenidConnect::Rails::Routes::Helper + end + + attr_accessor :routes + + def initialize(routes, &block) + @routes = routes + @block = block + end + + def generate_routes!(options) + @mapping = Mapper.new.map(&@block) + routes.scope options[:scope] || 'oauth', as: 'oauth' do + map_route(:userinfo, :userinfo_routes) + map_route(:discovery, :discovery_routes) + end + + routes.scope as: 'oauth' do + map_route(:discovery, :discovery_well_known_routes) + end + end + + private + + def map_route(name, method) + return if @mapping.skipped?(name) + + mapping = @mapping[name] + + routes.scope controller: mapping[:controllers], as: mapping[:as] do + send method + end + end + + def userinfo_routes + routes.get :show, path: 'userinfo', as: '' + routes.post :show, path: 'userinfo', as: nil + end + + def discovery_routes + routes.scope path: 'discovery' do + routes.get :keys + end + end + + def discovery_well_known_routes + routes.scope path: '.well-known' do + routes.get :provider, path: 'openid-configuration' + routes.get :provider, path: 'oauth-authorization-server' + routes.get :webfinger + end + end + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapper.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapper.rb new file mode 100644 index 0000000000000000000000000000000000000000..1931edcc7f0f4b67dfd0b472bf14e31d0194f9bd --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapper.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module Rails + class Routes + class Mapper + def initialize(mapping = Mapping.new) + @mapping = mapping + end + + def map(&block) + instance_eval(&block) if block + @mapping + end + + def controllers(controller_names = {}) + @mapping.controllers.merge!(controller_names) + end + + def skip_controllers(*controller_names) + @mapping.skips = controller_names + end + + def as(alias_names = {}) + @mapping.as.merge!(alias_names) + end + end + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapping.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapping.rb new file mode 100644 index 0000000000000000000000000000000000000000..307f4045017dc171a770bc85d2cae65a8abc5002 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/rails/routes/mapping.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + module Rails + class Routes + class Mapping + attr_accessor :controllers, :as, :skips + + def initialize + @controllers = { + userinfo: 'doorkeeper/openid_connect/userinfo', + discovery: 'doorkeeper/openid_connect/discovery' + } + + @as = { + userinfo: :userinfo, + discovery: :discovery + } + + @skips = [] + end + + def [](routes) + { + controllers: @controllers[routes], + as: @as[routes] + } + end + + def skipped?(controller) + @skips.include?(controller) + end + end + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/user_info.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/user_info.rb new file mode 100644 index 0000000000000000000000000000000000000000..9b82334c111ecb0a9fff00ccd477a4c748ce7941 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/user_info.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + class UserInfo + include ActiveModel::Validations + + def initialize(access_token) + @access_token = access_token + end + + def claims + { + sub: subject + }.merge ClaimsBuilder.generate(@access_token, :user_info) + end + + def as_json(*_) + claims.reject { |_, value| value.nil? || value == '' } + end + + private + + def subject + Doorkeeper::OpenidConnect.configuration.subject.call(resource_owner, application).to_s + end + + def resource_owner + @resource_owner ||= Doorkeeper::OpenidConnect.configuration.resource_owner_from_access_token.call(@access_token) + end + + def application + @application ||= @access_token.application + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/version.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/version.rb new file mode 100644 index 0000000000000000000000000000000000000000..4a17095e367f50cc7f81d6ac0056d46d1cd3f4c0 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/openid_connect/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + VERSION = '1.8.9' + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token.rb new file mode 100644 index 0000000000000000000000000000000000000000..1c6967001ac257b9a304f93edf6925d3fd388b65 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'doorkeeper/request/strategy' + +module Doorkeeper + module Request + class IdToken < Strategy + delegate :current_resource_owner, to: :server + + def pre_auth + server.context.send(:pre_auth) + end + + def request + @request ||= OAuth::IdTokenRequest.new(pre_auth, current_resource_owner) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token_token.rb b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token_token.rb new file mode 100644 index 0000000000000000000000000000000000000000..100d6a18f1ed99800b85e0ad7e999a8edead5d6b --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/doorkeeper/request/id_token_token.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'doorkeeper/request/strategy' + +module Doorkeeper + module Request + class IdTokenToken < Strategy + delegate :current_resource_owner, to: :server + + def pre_auth + server.context.send(:pre_auth) + end + + def request + @request ||= OAuth::IdTokenTokenRequest.new(pre_auth, current_resource_owner) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/install_generator.rb b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/install_generator.rb new file mode 100644 index 0000000000000000000000000000000000000000..8d3a46693328f2ff23e5d9dd6273575b757ac5b7 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/install_generator.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Doorkeeper + module OpenidConnect + class InstallGenerator < ::Rails::Generators::Base + include ::Rails::Generators::Migration + source_root File.expand_path('templates', __dir__) + desc 'Installs Doorkeeper OpenID Connect.' + + def install + template 'initializer.rb', 'config/initializers/doorkeeper_openid_connect.rb' + copy_file File.expand_path('../../../../config/locales/en.yml', __dir__), 'config/locales/doorkeeper_openid_connect.en.yml' + route 'use_doorkeeper_openid_connect' + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/migration_generator.rb b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/migration_generator.rb new file mode 100644 index 0000000000000000000000000000000000000000..50fecec6189ddd511733967e797af71c5b1e25de --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/migration_generator.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'rails/generators/active_record' + +module Doorkeeper + module OpenidConnect + class MigrationGenerator < ::Rails::Generators::Base + include ::Rails::Generators::Migration + source_root File.expand_path('templates', __dir__) + desc 'Installs Doorkeeper OpenID Connect migration file.' + + def install + migration_template( + 'migration.rb.erb', + 'db/migrate/create_doorkeeper_openid_connect_tables.rb', + migration_version: migration_version + ) + end + + def self.next_migration_number(dirname) + ActiveRecord::Generators::Base.next_migration_number(dirname) + end + + private + + def migration_version + if ActiveRecord::VERSION::MAJOR >= 5 + "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]" + end + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/initializer.rb b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/initializer.rb new file mode 100644 index 0000000000000000000000000000000000000000..4c322760115abb574035e53d921b5498511355ea --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/initializer.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +Doorkeeper::OpenidConnect.configure do + issuer do |resource_owner, application| + 'issuer string' + end + + signing_key <<~KEY + -----BEGIN RSA PRIVATE KEY----- + .... + -----END RSA PRIVATE KEY----- + KEY + + subject_types_supported [:public] + + resource_owner_from_access_token do |access_token| + # Example implementation: + # User.find_by(id: access_token.resource_owner_id) + end + + auth_time_from_resource_owner do |resource_owner| + # Example implementation: + # resource_owner.current_sign_in_at + end + + reauthenticate_resource_owner do |resource_owner, return_to| + # Example implementation: + # store_location_for resource_owner, return_to + # sign_out resource_owner + # redirect_to new_user_session_url + end + + # Depending on your configuration, a DoubleRenderError could be raised + # if render/redirect_to is called at some point before this callback is executed. + # To avoid the DoubleRenderError, you could add these two lines at the beginning + # of this callback: (Reference: https://github.com/rails/rails/issues/25106) + # self.response_body = nil + # @_response_body = nil + select_account_for_resource_owner do |resource_owner, return_to| + # Example implementation: + # store_location_for resource_owner, return_to + # redirect_to account_select_url + end + + subject do |resource_owner, application| + # Example implementation: + # resource_owner.id + + # or if you need pairwise subject identifier, implement like below: + # Digest::SHA256.hexdigest("#{resource_owner.id}#{URI.parse(application.redirect_uri).host}#{'your_secret_salt'}") + end + + # Protocol to use when generating URIs for the discovery endpoint, + # for example if you also use HTTPS in development + # protocol do + # :https + # end + + # Expiration time on or after which the ID Token MUST NOT be accepted for processing. (default 120 seconds). + # expiration 600 + + # Example claims: + # claims do + # normal_claim :_foo_ do |resource_owner| + # resource_owner.foo + # end + + # normal_claim :_bar_ do |resource_owner| + # resource_owner.bar + # end + # end +end diff --git a/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/migration.rb.erb b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/migration.rb.erb new file mode 100644 index 0000000000000000000000000000000000000000..05dac3eece5049cc2cc901693c4ea84627f094f1 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/lib/generators/doorkeeper/openid_connect/templates/migration.rb.erb @@ -0,0 +1,15 @@ +class CreateDoorkeeperOpenidConnectTables < ActiveRecord::Migration<%= migration_version %> + def change + create_table :oauth_openid_requests do |t| + t.references :access_grant, null: false, index: true + t.string :nonce, null: false + end + + add_foreign_key( + :oauth_openid_requests, + :oauth_access_grants, + column: :access_grant_id, + on_delete: :cascade + ) + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/controllers/discovery_controller_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/controllers/discovery_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..68a0341275da328af5eb6f45e5ddbfe76794f65f --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/controllers/discovery_controller_spec.rb @@ -0,0 +1,316 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::DiscoveryController, type: :controller do + describe '#provider' do + it 'returns the provider configuration' do + get :provider + data = JSON.parse(response.body) + + expect(data.sort).to match({ + 'issuer' => 'dummy', + 'authorization_endpoint' => 'http://test.host/oauth/authorize', + 'token_endpoint' => 'http://test.host/oauth/token', + 'revocation_endpoint' => 'http://test.host/oauth/revoke', + 'introspection_endpoint' => 'http://test.host/oauth/introspect', + 'userinfo_endpoint' => 'http://test.host/oauth/userinfo', + 'jwks_uri' => 'http://test.host/oauth/discovery/keys', + + 'scopes_supported' => ['openid'], + 'response_types_supported' => ['code', 'token', 'id_token', 'id_token token'], + 'response_modes_supported' => %w[query fragment form_post], + 'grant_types_supported' => %w[authorization_code client_credentials implicit_oidc], + + 'token_endpoint_auth_methods_supported' => %w[client_secret_basic client_secret_post], + + 'subject_types_supported' => [ + 'public', + ], + + 'id_token_signing_alg_values_supported' => [ + 'RS256', + ], + + 'claim_types_supported' => [ + 'normal', + ], + + 'claims_supported' => %w[ + iss + sub + aud + exp + iat + name + variable_name + created_at + updated_at + token_id + both_responses + id_token_response + user_info_response + ], + + 'code_challenge_methods_supported' => %w[ + plain + S256 + ], + }.sort) + end + + context 'when refresh_token grant type is enabled' do + before { Doorkeeper.configure { use_refresh_token } } + + it 'add refresh_token to grant_types_supported' do + get :provider + data = JSON.parse(response.body) + + expect(data['grant_types_supported']).to eq %w[authorization_code client_credentials refresh_token] + end + end + + context 'when issuer block' do + before { Doorkeeper::OpenidConnect.configure { issuer do |r, a| "test-issuer" end } } + + it 'return blocks result' do + get :provider + data = JSON.parse(response.body) + + expect(data['issuer']).to eq "test-issuer" + end + end + + context 'when grant_flows is configed with only client_credentials' do + before { Doorkeeper.configure { grant_flows %w[client_credentials] } } + + it 'return empty response_modes_supported' do + get :provider + data = JSON.parse(response.body) + + expect(data['response_modes_supported']).to eq [] + end + end + + context 'when grant_flows is configed only implicit flow' do + before { Doorkeeper.configure { grant_flows %w[implicit_oidc] } } + + it 'return fragment and form_post as response_modes_supported' do + get :provider + data = JSON.parse(response.body) + + expect(data['response_modes_supported']).to eq %w[fragment form_post] + end + end + + context 'when grant_flows is configed with authorization_code and implicit flow' do + before { Doorkeeper.configure { grant_flows %w[authorization_code implicit_oidc] } } + + it 'return query, fragment and form_post as response_modes_supported' do + get :provider + data = JSON.parse(response.body) + + expect(data['response_modes_supported']).to eq %w[query fragment form_post] + end + end + + it 'uses the protocol option for generating URLs' do + Doorkeeper::OpenidConnect.configure do + protocol { :testing } + end + + get :provider + data = JSON.parse(response.body) + + expect(data['authorization_endpoint']).to eq 'testing://test.host/oauth/authorize' + end + + context 'when the discovery_url_options option is set for all endpoints' do + before do + Doorkeeper::OpenidConnect.configure do + discovery_url_options do |request| + { + authorization: { host: 'alternate-authorization.host' }, + token: { host: 'alternate-token.host' }, + revocation: { host: 'alternate-revocation.host' }, + introspection: { host: 'alternate-introspection.host' }, + userinfo: { host: 'alternate-userinfo.host' }, + jwks: { host: 'alternate-jwks.host' } + } + end + end + end + + it 'uses the discovery_url_options option when generating the endpoint urls' do + get :provider + data = JSON.parse(response.body) + + expect(data['authorization_endpoint']).to eq 'http://alternate-authorization.host/oauth/authorize' + expect(data['token_endpoint']).to eq 'http://alternate-token.host/oauth/token' + expect(data['revocation_endpoint']).to eq 'http://alternate-revocation.host/oauth/revoke' + expect(data['introspection_endpoint']).to eq 'http://alternate-introspection.host/oauth/introspect' + expect(data['userinfo_endpoint']).to eq 'http://alternate-userinfo.host/oauth/userinfo' + expect(data['jwks_uri']).to eq 'http://alternate-jwks.host/oauth/discovery/keys' + end + end + + context 'when the discovery_url_options option is only set for some endpoints' do + before do + Doorkeeper::OpenidConnect.configure do + discovery_url_options do |request| + { authorization: { host: 'alternate-authorization.host' } } + end + end + end + + it 'does not use the discovery_url_options option when generating other URLs' do + get :provider + data = JSON.parse(response.body) + + { + 'token_endpoint' => 'http://test.host/oauth/token', + 'revocation_endpoint' => 'http://test.host/oauth/revoke', + 'introspection_endpoint' => 'http://test.host/oauth/introspect', + 'userinfo_endpoint' => 'http://test.host/oauth/userinfo', + 'jwks_uri' => 'http://test.host/oauth/discovery/keys', + }.each do |endpoint, expected_url| + expect(data[endpoint]).to eq expected_url + end + end + end + + it 'does not return an end session endpoint if none is configured' do + get :provider + data = JSON.parse(response.body) + + expect(data.key?('end_session_endpoint')).to be(false) + end + + it 'uses the configured end session endpoint with self as context' do + Doorkeeper::OpenidConnect.configure do + end_session_endpoint -> { logout_url } + end + + def controller.logout_url + 'http://test.host/logout' + end + + get :provider + data = JSON.parse(response.body) + + expect(data['end_session_endpoint']).to eq 'http://test.host/logout' + end + + context 'when token inspection is disallowed' do + let(:doorkeeper_config) { Doorkeeper.config } + let!(:allow_token_introspection) { doorkeeper_config.allow_token_introspection } + + before do + allow(doorkeeper_config).to receive(:allow_token_introspection).and_return(false) + Rails.application.reload_routes! + end + + after do + allow(doorkeeper_config).to receive(:allow_token_introspection).and_return(allow_token_introspection) + Rails.application.reload_routes! + end + + it 'does not return introspection_endpoint' do + get :provider + data = JSON.parse(response.body) + + expect(data.key?('introspection_endpoint')).to be(false) + end + end + end + + describe '#webfinger' do + it 'requires the resource parameter' do + expect do + get :webfinger + end.to raise_error ActionController::ParameterMissing + end + + it 'returns the OpenID Connect relation' do + get :webfinger, params: { resource: 'user@example.com' } + data = JSON.parse(response.body) + + expect(data.sort).to eq({ + 'subject' => 'user@example.com', + 'links' => [ + 'rel' => 'http://openid.net/specs/connect/1.0/issuer', + 'href' => 'http://test.host/', + ], + }.sort) + end + + context 'when the discovery_url_options option is set for webfinger endpoint' do + before do + Doorkeeper::OpenidConnect.configure do + discovery_url_options do |request| + { webfinger: { host: 'alternate-webfinger.host' } } + end + end + end + + it 'uses the discovery_url_options option when generating the webfinger endpoint url' do + get :webfinger, params: { resource: 'user@example.com' } + data = JSON.parse(response.body) + + expect(data['links'].first['href']).to eq 'http://alternate-webfinger.host/' + end + end + + context 'when the discovery_url_options option uses the request for an endpoint' do + before do + Doorkeeper::OpenidConnect.configure do + discovery_url_options do |request| + { + authorization: { host: 'alternate-authorization.host', + protocol: request.ssl? ? :https : :testing } + } + end + end + end + + it 'uses the discovery_url_options option when generating the webfinger endpoint url' do + get :provider + data = JSON.parse(response.body) + + expect(data['authorization_endpoint']).to eq 'testing://alternate-authorization.host/oauth/authorize' + end + end + end + + describe '#keys' do + subject { get :keys } + + shared_examples 'a key response' do |options| + expected_parameters = options[:expected_parameters] + + it "includes only #{expected_parameters.join(', ')} parameters" do + subject + data = JSON.parse(response.body) + key = data['keys'].first + + expect(key.keys.map(&:to_sym)).to match_array(expected_parameters) + end + end + + context 'when using an RSA key' do + it_behaves_like 'a key response', expected_parameters: %i[kty kid e n use alg] + end + + context 'when using an EC key' do + before { configure_ec } + + it_behaves_like 'a key response', expected_parameters: %i[kty kid crv x y use alg] + end + + context 'when using an HMAC key' do + before { configure_hmac } + + it_behaves_like 'a key response', expected_parameters: %i[kty kid use alg] + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorizations_controller_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorizations_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..7f1da7da590a94a983126d31f10c851e4b3d86f5 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorizations_controller_spec.rb @@ -0,0 +1,433 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::AuthorizationsController, type: :controller do + let(:user) { create :user } + let(:application) { create :application, scopes: default_scopes } + let(:default_scopes) { 'openid profile' } + let(:token_attributes) { { application_id: application.id, resource_owner_id: user.id, scopes: default_scopes } } + + def authorize!(params = {}) + get :new, params: { + response_type: 'code', + response_mode: '', + current_user: user.id, + client_id: application.uid, + scope: default_scopes, + redirect_uri: application.redirect_uri, + }.merge(params) + end + + def build_redirect_uri(params = {}, type: 'query') + case type + when 'query' + Doorkeeper::OAuth::Authorization::URIBuilder.uri_with_query(application.redirect_uri, params) + when 'fragment' + Doorkeeper::OAuth::Authorization::URIBuilder.uri_with_fragment(application.redirect_uri, params) + else + raise ArgumentError, "Unsupported uri type #{type}" + end + end + + def expect_authorization_form! + expect(response).to be_successful + expect(response).to render_template('doorkeeper/authorizations/new') + end + + def expect_successful_callback! + expect(response).to be_redirect + expect(response.location).to match(/^#{Regexp.quote application.redirect_uri}\?code=[-\w]+$/) + end + + describe '#authenticate_resource_owner!' do + it 'redirects to login form when not logged in' do + authorize! current_user: nil + + expect(response).to redirect_to '/login' + end + + context 'with OIDC requests' do + before do + expect(controller).to receive(:handle_oidc_prompt_param!) + expect(controller).to receive(:handle_oidc_max_age_param!) + end + + it 'renders the authorization form if logged in' do + authorize! + + expect_authorization_form! + end + end + + context 'with non-OIDC requests' do + before do + expect(controller).not_to receive(:handle_oidc_prompt_param!) + expect(controller).not_to receive(:handle_oidc_max_age_param!) + end + + it 'when action is not :new' do + get :show, params: { + response_type: 'code', + current_user: user.id, + client_id: application.uid, + scope: default_scopes, + redirect_uri: application.redirect_uri, + } + + expect(response).to render_template('doorkeeper/authorizations/show') + end + + context 'when pre_authorization is invalid' do + it 'render error when client_id is missing' do + authorize!(client_id: nil) + + expect(response).to be_successful + expect(response).to render_template('doorkeeper/authorizations/error') + end + + it 'render error when response_type is missing' do + authorize!(response_type: nil) + + expect(response).to be_successful + expect(response).to render_template('doorkeeper/authorizations/error') + end + end + + it 'when openid scope is not present' do + authorize!(scope: 'profile') + + expect_authorization_form! + end + end + end + + describe '#handle_oidc_prompt_param!' do + it 'is ignored when the openid scope is not present' do + authorize! scope: 'profile', prompt: 'invalid' + + expect_authorization_form! + end + + context 'with a prompt=none parameter' do + context 'and a matching token' do + before do + create :access_token, token_attributes + end + + it 'redirects to the callback if logged in' do + authorize! prompt: 'none' + + expect_successful_callback! + end + + context 'when another prompt value is present' do + let(:error_params) do + { + 'error' => 'invalid_request', + 'error_description' => 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.', + } + end + let(:request_param) { { prompt: 'none login' } } + + it 'redirect as the query uri with an invalid_request error' do + authorize! request_param + + expect(response).to redirect_to build_redirect_uri(error_params) + end + + it 'redirect as the fragment style uri when response_type is implicit flow request' do + allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc']) + + authorize! request_param.merge(response_type: 'id_token token') + + expect(response).to redirect_to build_redirect_uri(error_params, type: 'fragment') + end + + it 'set @authorize_response variable and render form_post template and when the form_post response_mode is specified' do + allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc']) + + authorize! request_param.merge(response_type: 'id_token token', response_mode: 'form_post') + + authorize_response = controller.instance_variable_get :@authorize_response + expect(authorize_response.body.to_json).to eq(error_params.to_json) + expect(response).to render_template(:form_post) + end + end + + context 'when not logged in' do + let(:error_params) do + { + 'error' => 'login_required', + 'error_description' => 'The authorization server requires end-user authentication', + 'state' => 'somestate', + } + end + let(:request_param) { { current_user: nil } } + + it 'returns a login_required error' do + authorize! request_param.merge(prompt: 'none', state: 'somestate') + + expect(response).to redirect_to build_redirect_uri(error_params) + end + + it 'redirect as the fragment style uri when response_type is implicit flow request' do + allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc']) + + authorize! request_param.merge(response_type: 'id_token token', prompt: 'none', state: 'somestate') + + expect(response).to redirect_to build_redirect_uri(error_params, type: 'fragment') + end + + it 'set @authorize_response variable and render form_post template and when the form_post response_mode is specified' do + allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc']) + + authorize! request_param.merge(response_type: 'id_token token', response_mode: 'form_post', prompt: 'none', state: 'somestate') + + authorize_response = controller.instance_variable_get :@authorize_response + expect(authorize_response.body.to_json).to eq(error_params.to_json) + expect(response).to render_template(:form_post) + end + end + end + + context 'and no matching token' do + it 'redirects to the callback if skip_authorization is set to true' do + allow(controller).to receive(:skip_authorization?).and_return(true) + + authorize! prompt: 'none' + expect_successful_callback! + end + + context 'when not logged in' do + let(:error_params) do + { + 'error' => 'login_required', + 'error_description' => 'The authorization server requires end-user authentication', + 'state' => 'somestate', + } + end + let(:request_param) { { current_user: nil } } + + it 'returns the login_required error when not logged in' do + authorize! request_param.merge(prompt: 'none', state: 'somestate') + + expect(response).to redirect_to build_redirect_uri(error_params) + end + + it 'uses the fragment style uris when redirecting an error for implicit flow request' do + allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc']) + + authorize! request_param.merge(response_type: 'id_token token', prompt: 'none', state: 'somestate') + + expect(response).to redirect_to build_redirect_uri(error_params, type: 'fragment') + end + + it 'set @authorize_response variable and render form_post template and when the form_post response_mode is specified' do + allow(Doorkeeper.configuration).to receive(:grant_flows).and_return(['implicit_oidc']) + + authorize! request_param.merge(response_type: 'id_token token', response_mode: 'form_post', prompt: 'none', state: 'somestate') + + authorize_response = controller.instance_variable_get :@authorize_response + expect(authorize_response.body.to_json).to eq(error_params.to_json) + expect(response).to render_template(:form_post) + end + end + + it 'returns a consent_required error when logged in' do + authorize! prompt: 'none' + + error_params = { + 'error' => 'consent_required', + 'error_description' => 'The authorization server requires end-user consent', + } + + expect(response).to redirect_to build_redirect_uri(error_params) + end + end + end + + context 'with a prompt=login parameter' do + it 'redirects to the sign in form if not logged in' do + authorize! prompt: 'login', current_user: nil + + expect(response).to redirect_to('/login') + end + + it 'reauthenticates the user if logged in' do + authorize! prompt: 'login' + + expect(response).to redirect_to('/reauthenticate') + end + end + + context 'with a prompt=consent parameter' do + it 'redirects to the sign in form if not logged in' do + authorize! prompt: 'consent', current_user: nil + + expect(response).to redirect_to('/login') + end + + it 'renders the authorization form even if a matching token is present' do + create :access_token, token_attributes + authorize! prompt: 'consent' + + expect_authorization_form! + end + end + + context 'with a prompt=select_account parameter' do + it 'redirects to the select account screen' do + authorize! prompt: 'select_account' + + expect(response).to redirect_to('/select_account') + end + end + + context 'with an unknown prompt parameter' do + it 'returns an invalid_request error' do + authorize! prompt: 'maybe' + + error_params = { + 'error' => 'invalid_request', + 'error_description' => 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.', + } + + expect(response).to redirect_to build_redirect_uri(error_params) + end + + it 'does not redirect to an invalid redirect_uri' do + authorize! prompt: 'maybe', redirect_uri: 'https://evilapp.com' + + expect(response).not_to be_redirect + end + end + end + + describe '#handle_oidc_max_age_param!' do + context 'with an invalid max_age parameter' do + it 'renders the authorization form' do + %w[0 -1 -23 foobar].each do |max_age| + authorize! max_age: max_age + + expect_authorization_form! + end + end + end + + context 'with a max_age=10 parameter' do + it 'renders the authorization form if the users last login was within 10 seconds' do + user.update! current_sign_in_at: 5.seconds.ago + authorize! max_age: 10 + + expect_authorization_form! + end + + it 'reauthenticates the user if the last login was longer than 10 seconds ago' do + user.update! current_sign_in_at: 5.minutes.ago + authorize! max_age: 10 + + expect(response).to redirect_to '/reauthenticate' + end + + it 'reauthenticates the user if the last login is unknown' do + user.update! current_sign_in_at: nil + authorize! max_age: 10 + + expect(response).to redirect_to '/reauthenticate' + end + end + end + + describe '#reauthenticate_oidc_resource_owner' do + let(:performed) { true } + + before do + allow(subject).to receive(:performed?) { performed } + allow(subject.request).to receive(:path).and_return('/oauth/authorize') + allow(subject.request).to receive(:query_parameters) { + { client_id: 'foo', prompt: 'login consent select_account' }.with_indifferent_access + } + end + + def reauthenticate! + passed_args = nil + + Doorkeeper::OpenidConnect.configure do + reauthenticate_resource_owner do |*args| + passed_args = args + end + end + + subject.send :reauthenticate_oidc_resource_owner, user + passed_args + end + + it 'calls reauthenticate_resource_owner with the current user and the return path' do + resource_owner, return_to = reauthenticate! + + expect(resource_owner).to eq user + expect(return_to).to eq '/oauth/authorize?client_id=foo&prompt=consent+select_account' + end + + it 'removes login from the prompt parameter and keeps other values' do + _, return_to = reauthenticate! + return_params = Rack::Utils.parse_query(URI.parse(return_to).query) + + expect(return_params['prompt']).to eq 'consent select_account' + end + + context 'with a reauthenticator that does not generate a response' do + let(:performed) { false } + + it 'raises a login_required error' do + expect do + reauthenticate! + end.to raise_error(Doorkeeper::OpenidConnect::Errors::LoginRequired) + end + end + end + + describe '#select_account_for_resource_owner' do + before do + allow(subject.request).to receive(:path).and_return('/oauth/authorize') + allow(subject.request).to receive(:query_parameters) { + { client_id: 'foo', prompt: 'login consent select_account' }.with_indifferent_access + } + end + + def select_account! + passed_args = nil + + Doorkeeper::OpenidConnect.configure do + select_account_for_resource_owner do |*args| + passed_args = args + end + end + + subject.send :select_account_for_oidc_resource_owner, user + passed_args + end + + it 'calls select_account_for_resource_owner with the current user and the return path' do + resource_owner, return_to = select_account! + + expect(resource_owner).to eq user + expect(return_to).to eq '/oauth/authorize?client_id=foo&prompt=login+consent' + end + + it 'removes select_account from the prompt parameter and keeps other values' do + _, return_to = select_account! + return_params = Rack::Utils.parse_query(URI.parse(return_to).query) + + expect(return_params['prompt']).to eq 'login consent' + end + end + + describe '#pre_auth' do + it 'permits nonce parameter' do + authorize! nonce: '123456' + expect(assigns(:pre_auth).nonce).to eq '123456' + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorized_applications_controller_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorized_applications_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..f5e43afc519d81ce534dd3316409c8e23caaeffb --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/controllers/doorkeeper/authorized_applications_controller_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::AuthorizedApplicationsController, type: :controller do + let(:access_token) { create :access_token } + + describe '#index' do + it 'does not run the extended #authenticate_resource_owner!' do + expect do + get :index + end.not_to raise_error + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/controllers/userinfo_controller_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/controllers/userinfo_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..ba7007ae5c163c62dc0df5c6b4a3b155e0a732b0 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/controllers/userinfo_controller_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::UserinfoController, type: :controller do + let(:client) { create :application } + let(:user) { create :user, name: 'Joe' } + let(:token) { create :access_token, application: client, resource_owner_id: user.id } + + describe '#show' do + context 'with a valid access token authorized for the openid scope' do + let(:token) { create :access_token, application: client, resource_owner_id: user.id, scopes: 'openid' } + + it 'returns the basic user information as JSON' do + get :show, params: { access_token: token.token } + + expect(response.status).to eq 200 + expect(JSON.parse(response.body)).to eq({ + 'sub' => user.id.to_s, + 'variable_name' => 'openid-name', + 'created_at' => user.created_at.to_i, + 'token_id' => token.id, + 'both_responses' => 'both', + 'user_info_response' => 'user_info', + }) + end + end + + context 'with a valid access token authorized for the openid and profile scopes' do + let(:token) { create :access_token, application: client, resource_owner_id: user.id, scopes: 'openid profile' } + + it 'returns the full user information as JSON' do + get :show, params: { access_token: token.token } + + expect(response.status).to eq 200 + expect(JSON.parse(response.body)).to eq({ + 'sub' => user.id.to_s, + 'name' => 'Joe', + 'variable_name' => 'profile-name', + 'created_at' => user.created_at.to_i, + 'updated_at' => user.updated_at.to_i, + 'token_id' => token.id, + 'both_responses' => 'both', + 'user_info_response' => 'user_info', + }) + end + end + + context 'with a valid access token not authorized for the openid scope' do + it 'returns an error' do + get :show, params: { access_token: token.token } + + expect(response.status).to eq 403 + end + end + + context 'without a valid access token' do + it 'returns an error' do + get :show, params: { access_token: 'foobar' } + + expect(response.status).to eq 401 + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/Rakefile b/vendor/gems/doorkeeper-openid_connect/spec/dummy/Rakefile new file mode 100644 index 0000000000000000000000000000000000000000..488c551fee2cd158e9f36f0366afd08c9522c2b2 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/Rakefile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative 'config/application' + +Rails.application.load_tasks diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/config/manifest.js b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/config/manifest.js new file mode 100644 index 0000000000000000000000000000000000000000..bb109908b29eb87e126cdc1a5b3aab84607a509b --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/config/manifest.js @@ -0,0 +1,3 @@ + +//= link_tree ../images +//= link_directory ../stylesheets .css diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/images/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/images/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/javascripts/application.js b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/javascripts/application.js new file mode 100644 index 0000000000000000000000000000000000000000..e54c6461cc303fa0c721e5431b1066b87c7ee56e --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/javascripts/application.js @@ -0,0 +1,13 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// +//= require_tree . diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/stylesheets/application.css b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/stylesheets/application.css new file mode 100644 index 0000000000000000000000000000000000000000..0ebd7fe8299ebee6f56fa726f834e4264d27d39d --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/assets/stylesheets/application.css @@ -0,0 +1,15 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + */ diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/channel.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/channel.rb new file mode 100644 index 0000000000000000000000000000000000000000..9aec2305390f808ce1accaed3fccddefb742cb69 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/channel.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/connection.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/connection.rb new file mode 100644 index 0000000000000000000000000000000000000000..8d6c2a1bf4bbe843bcd32ca6237eecfe73c9012c --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/channels/application_cable/connection.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/application_controller.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/application_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..280cc28ce21a03e69b50ee7eedb87c6f36a80df7 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/application_controller.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class ApplicationController < ActionController::Base + protect_from_forgery with: :exception +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/concerns/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/controllers/concerns/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/helpers/application_helper.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/helpers/application_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..15b06f0f67929529e41d73299adb008f8a9e7086 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/helpers/application_helper.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +module ApplicationHelper +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/jobs/application_job.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/jobs/application_job.rb new file mode 100644 index 0000000000000000000000000000000000000000..d92ffddcb5288f618f89df28148c17052bf143b7 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/jobs/application_job.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +class ApplicationJob < ActiveJob::Base +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/mailers/application_mailer.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/mailers/application_mailer.rb new file mode 100644 index 0000000000000000000000000000000000000000..d84cb6e71e954ad890132d7db2834afd364cd18d --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/mailers/application_mailer.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/application_record.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/application_record.rb new file mode 100644 index 0000000000000000000000000000000000000000..71fbba5b32873f53ea6e713ea0219acda01a9286 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/application_record.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/concerns/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/concerns/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/user.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/user.rb new file mode 100644 index 0000000000000000000000000000000000000000..53124f5cce8cedd33876510e6c12687fab8de181 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/app/models/user.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class User < ActiveRecord::Base + def self.authenticate!(name, password) + User.where(name: name, password: password).first + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/bundle b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/bundle new file mode 100755 index 0000000000000000000000000000000000000000..2dbb71769eb0492801d34e71b50794e639041575 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/bundle @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) +load Gem.bin_path('bundler', 'bundle') diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rails b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rails new file mode 100755 index 0000000000000000000000000000000000000000..a31728ab9778f998cfcbce903d930e94ed287e3b --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rake b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rake new file mode 100755 index 0000000000000000000000000000000000000000..c199955006061df3143975173ccad6d7fa3cb83a --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/rake @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/setup b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/setup new file mode 100755 index 0000000000000000000000000000000000000000..31400462308caacaba0fa49d1cc33cdf056584c6 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/setup @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'pathname' +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! 'bin/rails db:setup' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/update b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/update new file mode 100755 index 0000000000000000000000000000000000000000..1d6aa6a5c935e6c91ff19525e86c498b5250849c --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/bin/update @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'pathname' +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a way to update your development environment automatically. + # Add necessary update steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + puts "\n== Updating database ==" + system! 'bin/rails db:migrate' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config.ru b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config.ru new file mode 100644 index 0000000000000000000000000000000000000000..842bccc3402da2e8f1e3e6cf12da39170ca422cc --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config.ru @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# This file is used by Rack-based servers to start the application. + +require_relative 'config/environment' + +run Rails.application diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/application.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/application.rb new file mode 100644 index 0000000000000000000000000000000000000000..f56092cf5d4fc62d93ff8561be0d9ca5480e9751 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/application.rb @@ -0,0 +1,16 @@ +require_relative 'boot' + +# Pick the frameworks you want: +require "active_record/railtie" +require "action_controller/railtie" +require "action_view/railtie" + +Bundler.require(*Rails.groups) + +module Dummy + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/boot.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/boot.rb new file mode 100644 index 0000000000000000000000000000000000000000..c9aef85d4041faa346d7b6375cedaa1163ae2b43 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/boot.rb @@ -0,0 +1,5 @@ +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) + +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/database.yml b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/database.yml new file mode 100644 index 0000000000000000000000000000000000000000..5403ee52818c4a4484690fdfcc5be1d227edce18 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/database.yml @@ -0,0 +1,26 @@ +# SQLite version 3.x +# gem install sqlite3 +# +# Ensure the SQLite 3 gem is defined in your Gemfile +# gem 'sqlite3' +# +development: + adapter: sqlite3 + pool: 5 + timeout: 5000 + database: db/development.sqlite3 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: sqlite3 + pool: 5 + timeout: 5000 + database: db/test.sqlite3 + +production: + adapter: sqlite3 + pool: 5 + timeout: 5000 + database: db/production.sqlite3 diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environment.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environment.rb new file mode 100644 index 0000000000000000000000000000000000000000..426333bb46978d897be4cc6fac77b9fcaacf59d0 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environments/test.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environments/test.rb new file mode 100644 index 0000000000000000000000000000000000000000..1df1a5931abab163ffe0a0552d14a510bb3b5cd0 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/environments/test.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper.rb new file mode 100644 index 0000000000000000000000000000000000000000..a41b1222231a23d9b254088d33bbf6fb673bbca2 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +Doorkeeper.configure do + optional_scopes :openid + + resource_owner_authenticator do + if params[:current_user].present? + User.find(params[:current_user]) + else + redirect_to('/login') + nil + end + end + + grant_flows %w[authorization_code client_credentials implicit_oidc] +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper_openid_connect.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper_openid_connect.rb new file mode 100644 index 0000000000000000000000000000000000000000..a38197294791824c9fd1292fa3c3ce570ba6e19a --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/initializers/doorkeeper_openid_connect.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +Doorkeeper::OpenidConnect.configure do + issuer 'dummy' + + signing_key <<~EOL + -----BEGIN RSA PRIVATE KEY----- + MIIEpgIBAAKCAQEAsjdnSA6UWUQQHf6BLIkIEUhMRNBJC1NN/pFt1EJmEiI88GS0 + ceROO5B5Ooo9Y3QOWJ/n+u1uwTHBz0HCTN4wgArWd1TcqB5GQzQRP4eYnWyPfi4C + feqAHzQp+v4VwbcK0LW4FqtW5D0dtrFtI281FDxLhARzkhU2y7fuYhL8fVw5rUhE + 8uwvHRZ5CEZyxf7BSHxIvOZAAymhuzNLATt2DGkDInU1BmF75tEtBJAVLzWG/j4L + PZh1EpSdfezqaXQlcy9PJi916UzTl0P7Yy+ulOdUsMlB6yo8qKTY1+AbZ5jzneHb + GDU/O8QjYvii1WDmJ60t0jXicmOkGrOhruOptwIDAQABAoIBAQChYNwMeu9IugJi + NsEf4+JDTBWMRpOuRrwcpfIvQAUPrKNEB90COPvCoju0j9OxCDmpdPtq1K/zD6xx + khlw485FVAsKufSp4+g6GJ75yT6gZtq1JtKo1L06BFFzb7uh069eeP7+wB6JxPHw + KlAqwxvsfADhxeolQUKCTMb3Vjv/Aw2cO/nn6RAOeftw2aDmFy8Xl+oTUtSxyib0 + YCdU9cK8MxsxDdmowwHp04xRTm/wfG5hLEn7HMz1PP86iP9BiFsCqTId9dxEUTS1 + K+VAt9FbxRAq5JlBocxUMHNxLigb94Ca2FOMR7F6l/tronLfHD801YoObF0fN9qW + Cgw4aTO5AoGBAOR79hiZVM7/l1cBid7hKSeMWKUZ/nrwJsVfNpu1H9xt9uDu+79U + mcGfM7pm7L2qCNGg7eeWBHq2CVg/XQacRNtcTlomFrw4tDXUkFN1hE56t1iaTs9m + dN9IDr6jFgf6UaoOxxoPT9Q1ZtO46l043Nzrkoz8cBEBaBY20bUDwCYjAoGBAMet + tt1ImGF1cx153KbOfjl8v54VYUVkmRNZTa1E821nL/EMpoONSqJmRVsX7grLyPL1 + QyZe245NOvn63YM0ng0rn2osoKsMVJwYBEYjHL61iF6dPtW5p8FIs7auRnC3NrG0 + XxHATZ4xhHD0iIn14iXh0XIhUVk+nGktHU1gbmVdAoGBANniwKdqqS6RHKBTDkgm + Dhnxw6MGa+CO3VpA1xGboxuRHeoY3KfzpIC5MhojBsZDvQ8zWUwMio7+w2CNZEfm + g99wYiOjyPCLXocrAssj+Rzh97AdzuQHf5Jh4/W2Dk9jTbdPSl02ltj2Z+2lnJFz + pWNjnqimHrSI09rDQi5NulJjAoGBAImquujVpDmNQFCSNA7NTzlTSMk09FtjgCZW + 67cKUsqa2fLXRfZs84gD+s1TMks/NMxNTH6n57e0h3TSAOb04AM0kDQjkKJdXfhA + lrHEg4z4m4yf3TJ9Tat09HJ+tRIBPzRFp0YVz23Btg4qifiUDdcQWdbWIb/l6vCY + qhsu4O4BAoGBANbceYSDYRdT7a5QjJGibkC90Z3vFe4rDTBgZWg7xG0cpSU4JNg7 + SFR3PjWQyCg7aGGXiooCM38YQruACTj0IFub24MFRA4ZTXvrACvpsVokJlQiG0Z4 + tuQKYki41JvYqPobcq/rLE/AM7PKJftW35nqFuj0MrsUwPacaVwKBf5J + -----END RSA PRIVATE KEY----- + EOL + + subject_types_supported [:public] + + resource_owner_from_access_token do |access_token| + User.find_by(id: access_token.resource_owner_id) + end + + auth_time_from_resource_owner do |resource_owner| + resource_owner.current_sign_in_at + end + + reauthenticate_resource_owner do |_resource_owner, _return_to| + redirect_to '/reauthenticate' + end + + select_account_for_resource_owner do |_resource_owner, _return_to| + redirect_to '/select_account' + end + + subject do |resource_owner| + resource_owner.id + end + + claims do + claim :name do |user| + user.name + end + + claim :variable_name, scope: :openid do |user, scopes| + scopes.exists?(:profile) ? 'profile-name' : 'openid-name' + end + + claim :created_at, scope: :openid do |user| + user.created_at.to_i + end + + claim :updated_at do |user| + user.updated_at.to_i + end + + claim :token_id, scope: :openid do |user, scopes, token| + token.id + end + + claim(:both_responses, scope: :openid, response: [:id_token, :user_info]) { 'both' } + claim(:id_token_response, scope: :openid, response: [:id_token]) { 'id_token' } + claim(:user_info_response, scope: :openid, response: :user_info) { 'user_info' } + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/locales/doorkeeper_openid_connect.en.yml b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/locales/doorkeeper_openid_connect.en.yml new file mode 100644 index 0000000000000000000000000000000000000000..1bed506b2cf19142aac85a474e901e8bab8f5253 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/locales/doorkeeper_openid_connect.en.yml @@ -0,0 +1,23 @@ +en: + doorkeeper: + scopes: + openid: 'Authenticate your account' + profile: 'View your profile information' + email: 'View your email address' + address: 'View your physical address' + phone: 'View your phone number' + errors: + messages: + login_required: 'The authorization server requires end-user authentication' + consent_required: 'The authorization server requires end-user consent' + interaction_required: 'The authorization server requires end-user interaction' + account_selection_required: 'The authorization server requires end-user account selection' + openid_connect: + errors: + messages: + # Configuration error messages + resource_owner_from_access_token_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.resource_owner_from_access_token missing configuration.' + auth_time_from_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.auth_time_from_resource_owner missing configuration.' + reauthenticate_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.reauthenticate_resource_owner missing configuration.' + select_account_for_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.select_account_for_resource_owner missing configuration.' + subject_not_configured: 'ID Token generation failed due to Doorkeeper::OpenidConnect.configure.subject missing configuration.' diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/routes.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/routes.rb new file mode 100644 index 0000000000000000000000000000000000000000..e182346eb5312c1b395fdd8d3344bcd60d4afc8a --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + use_doorkeeper + use_doorkeeper_openid_connect + + root 'dummy#index' +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/secrets.yml b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/secrets.yml new file mode 100644 index 0000000000000000000000000000000000000000..77b0f4db7a46773e80a1399f1c4b77efebebaa51 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/config/secrets.yml @@ -0,0 +1,22 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key is used for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! + +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +# You can use `rails secret` to generate a secure secret key. + +# Make sure the secrets in this file are kept private +# if you're sharing your code publicly. + +development: + secret_key_base: 047f8d91118b6fad743ccac15928b306d1880d9d104377eb1f7aeed909ce852c0a214074742163a6e0bc814482c8cdeae470c5edfc75eee37c8da6ccbbae4199 + +test: + secret_key_base: 88becc3eb1c84af38da6deea4627f29f2bd41ba79dd279a0e379a41a82f18316f6f5221c73182adca329df8be13fd7c115804a82246989f1314e93d7efc745d3 + +# Do not keep production secrets in the repository, +# instead read values from the environment. +production: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20111122132257_create_users.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20111122132257_create_users.rb new file mode 100644 index 0000000000000000000000000000000000000000..3991429575b71e4731461e7d9c89d1ef068a0bab --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20111122132257_create_users.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class CreateUsers < ActiveRecord::Migration[4.2] + def change + create_table :users do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb new file mode 100644 index 0000000000000000000000000000000000000000..67d3728c6c49f5d1fa9d61b19062c8918be89e20 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddPasswordToUsers < ActiveRecord::Migration[4.2] + def change + add_column :users, :password, :string + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb new file mode 100644 index 0000000000000000000000000000000000000000..91bdbf507464bd2662d14df2865ad9a0c57dacdf --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +class CreateDoorkeeperTables < ActiveRecord::Migration[4.2] + def change + create_table :oauth_applications do |t| + t.string :name, null: false + t.string :uid, null: false + t.string :secret, null: false + t.text :redirect_uri, null: false + t.string :scopes, null: false, default: '' + t.timestamps null: false + end + + add_index :oauth_applications, :uid, unique: true + + create_table :oauth_access_grants do |t| + t.integer :resource_owner_id, null: false + t.references :application, null: false + t.string :token, null: false + t.integer :expires_in, null: false + t.text :redirect_uri, null: false + t.datetime :created_at, null: false + t.datetime :revoked_at + t.string :scopes + end + + add_index :oauth_access_grants, :token, unique: true + add_foreign_key( + :oauth_access_grants, + :oauth_applications, + column: :application_id, + ) + + create_table :oauth_access_tokens do |t| + t.integer :resource_owner_id + t.references :application + + # If you use a custom token generator you may need to change this column + # from string to text, so that it accepts tokens larger than 255 + # characters. More info on custom token generators in: + # https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator + # + # t.text :token, null: false + t.string :token, null: false + + t.string :refresh_token + t.integer :expires_in + t.datetime :revoked_at + t.datetime :created_at, null: false + t.string :scopes + end + + add_index :oauth_access_tokens, :token, unique: true + add_index :oauth_access_tokens, :resource_owner_id + add_index :oauth_access_tokens, :refresh_token, unique: true + add_foreign_key( + :oauth_access_tokens, + :oauth_applications, + column: :application_id, + ) + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb new file mode 100644 index 0000000000000000000000000000000000000000..d4eda38df0f1c138729fedb44084ccd19d30198e --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddOwnerToApplication < ActiveRecord::Migration[4.2] + def change + add_column :oauth_applications, :owner_id, :integer, null: true + add_column :oauth_applications, :owner_type, :string, null: true + add_index :oauth_applications, [:owner_id, :owner_type] + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb new file mode 100644 index 0000000000000000000000000000000000000000..ffad61b260a8a96a6d01779e601d3838d57bd40a --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddPreviousRefreshTokenToAccessTokens < ActiveRecord::Migration[4.2] + def change + add_column( + :oauth_access_tokens, + :previous_refresh_token, + :string, + default: '', + null: false + ) + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20161102204540_add_current_sign_in_at_to_users.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20161102204540_add_current_sign_in_at_to_users.rb new file mode 100644 index 0000000000000000000000000000000000000000..6b5d2ba96f1e1c94eaf80d396c8d459c956fe539 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20161102204540_add_current_sign_in_at_to_users.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddCurrentSignInAtToUsers < ActiveRecord::Migration[4.2] + def change + add_column :users, :current_sign_in_at, :datetime + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20180904152859_add_confidential_to_applications.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20180904152859_add_confidential_to_applications.rb new file mode 100644 index 0000000000000000000000000000000000000000..784af8828f5c3d4d0d787fbc8489b9e4c9595424 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20180904152859_add_confidential_to_applications.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddConfidentialToApplications < ActiveRecord::Migration[5.0] + def change + add_column( + :oauth_applications, + :confidential, + :boolean, + null: false, + default: true + ) + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20221122044143_enable_pkce.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20221122044143_enable_pkce.rb new file mode 100644 index 0000000000000000000000000000000000000000..96b4e1f7a3f24c800633e15b90ec7452975430d0 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/migrate/20221122044143_enable_pkce.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class EnablePkce < ActiveRecord::Migration[6.0] + def change + add_column :oauth_access_grants, :code_challenge, :string, null: true + add_column :oauth_access_grants, :code_challenge_method, :string, null: true + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/schema.rb b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/schema.rb new file mode 100644 index 0000000000000000000000000000000000000000..8c4e100b4804a93bff5279b21f0eee9db4c703de --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/db/schema.rb @@ -0,0 +1,76 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `rails +# db:schema:load`. When creating a new database, `rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 2022_11_22_044143) do + + create_table "oauth_access_grants", force: :cascade do |t| + t.integer "resource_owner_id", null: false + t.integer "application_id", null: false + t.string "token", null: false + t.integer "expires_in", null: false + t.text "redirect_uri", null: false + t.datetime "created_at", null: false + t.datetime "revoked_at" + t.string "scopes" + t.string "code_challenge" + t.string "code_challenge_method" + t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true + end + + create_table "oauth_access_tokens", force: :cascade do |t| + t.integer "resource_owner_id" + t.integer "application_id" + t.string "token", null: false + t.string "refresh_token" + t.integer "expires_in" + t.datetime "revoked_at" + t.datetime "created_at", null: false + t.string "scopes" + t.string "previous_refresh_token", default: "", null: false + t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true + t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id" + t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true + end + + create_table "oauth_applications", force: :cascade do |t| + t.string "name", null: false + t.string "uid", null: false + t.string "secret", null: false + t.text "redirect_uri", null: false + t.string "scopes", default: "", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "owner_id" + t.string "owner_type" + t.boolean "confidential", default: true, null: false + t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type" + t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true + end + + create_table "oauth_openid_requests", force: :cascade do |t| + t.integer "access_grant_id", null: false + t.string "nonce", null: false + t.index ["access_grant_id"], name: "index_oauth_openid_requests_on_access_grant_id" + end + + create_table "users", force: :cascade do |t| + t.string "name" + t.datetime "created_at" + t.datetime "updated_at" + t.string "password" + t.datetime "current_sign_in_at" + end + + add_foreign_key "oauth_access_grants", "oauth_applications", column: "application_id" + add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id" + add_foreign_key "oauth_openid_requests", "oauth_access_grants", column: "access_grant_id", on_delete: :cascade +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/lib/assets/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/lib/assets/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/log/.keep b/vendor/gems/doorkeeper-openid_connect/spec/dummy/log/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/404.html b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/404.html new file mode 100644 index 0000000000000000000000000000000000000000..b612547fc21d079889046e65d1fb135ec6921eaa --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/404.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<html> +<head> + <title>The page you were looking for doesn't exist (404)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <style> + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + margin: 0; + } + + div.dialog { + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + div.dialog > p { + margin: 0 0 1em; + padding: 1em; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + </style> +</head> + +<body> + <!-- This file lives in public/404.html --> + <div class="dialog"> + <div> + <h1>The page you were looking for doesn't exist.</h1> + <p>You may have mistyped the address or the page may have moved.</p> + </div> + <p>If you are the application owner check the logs for more information.</p> + </div> +</body> +</html> diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/422.html b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/422.html new file mode 100644 index 0000000000000000000000000000000000000000..a21f82b3bdb817ecbc43f74c6fe360300739418a --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/422.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<html> +<head> + <title>The change you wanted was rejected (422)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <style> + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + margin: 0; + } + + div.dialog { + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + div.dialog > p { + margin: 0 0 1em; + padding: 1em; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + </style> +</head> + +<body> + <!-- This file lives in public/422.html --> + <div class="dialog"> + <div> + <h1>The change you wanted was rejected.</h1> + <p>Maybe you tried to change something you didn't have access to.</p> + </div> + <p>If you are the application owner check the logs for more information.</p> + </div> +</body> +</html> diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/500.html b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/500.html new file mode 100644 index 0000000000000000000000000000000000000000..061abc587dcac4cdb1d62a890e4fd4bb20b8cb61 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/500.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> +<head> + <title>We're sorry, but something went wrong (500)</title> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <style> + body { + background-color: #EFEFEF; + color: #2E2F30; + text-align: center; + font-family: arial, sans-serif; + margin: 0; + } + + div.dialog { + width: 95%; + max-width: 33em; + margin: 4em auto 0; + } + + div.dialog > div { + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #BBB; + border-top: #B00100 solid 4px; + border-top-left-radius: 9px; + border-top-right-radius: 9px; + background-color: white; + padding: 7px 12% 0; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + + h1 { + font-size: 100%; + color: #730E15; + line-height: 1.5em; + } + + div.dialog > p { + margin: 0 0 1em; + padding: 1em; + background-color: #F7F7F7; + border: 1px solid #CCC; + border-right-color: #999; + border-left-color: #999; + border-bottom-color: #999; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-top-color: #DADADA; + color: #666; + box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); + } + </style> +</head> + +<body> + <!-- This file lives in public/500.html --> + <div class="dialog"> + <div> + <h1>We're sorry, but something went wrong.</h1> + </div> + <p>If you are the application owner check the logs for more information.</p> + </div> +</body> +</html> diff --git a/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/favicon.ico b/vendor/gems/doorkeeper-openid_connect/spec/dummy/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/vendor/gems/doorkeeper-openid_connect/spec/factories.rb b/vendor/gems/doorkeeper-openid_connect/spec/factories.rb new file mode 100644 index 0000000000000000000000000000000000000000..2b30682e1de8e1eaece636380ddb50f356c1ea37 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/factories.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :access_grant, class: 'Doorkeeper::AccessGrant' do + resource_owner_id { create(:user).id } + application + redirect_uri { 'https://app.com/callback' } + expires_in { 100 } + scopes { 'public write' } + end + + factory :access_token, class: 'Doorkeeper::AccessToken' do + resource_owner_id { create(:user).id } + application + expires_in { 2.hours } + + factory :clientless_access_token do + application { nil } + end + end + + factory :application, class: 'Doorkeeper::Application' do + sequence(:name) { |n| "Application #{n}" } + redirect_uri { 'https://app.com/callback' } + end + + factory :user do + current_sign_in_at { Time.zone.at(23) } + end + + factory :openid_request, class: 'Doorkeeper::OpenidConnect::Request' do + access_grant + sequence(:nonce, &:to_s) + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/claims/claim_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/claims/claim_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..24e66e8228f3c2c8a8044d8de12eaf212db7069b --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/claims/claim_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::Claims::Claim do + subject { described_class.new name: 'username', scope: 'profile' } + + describe '#initialize' do + it 'uses the given name' do + expect(subject.name).to eq :username + end + + it 'uses the given scope' do + expect(subject.scope).to eq :profile + end + + it 'falls back to the default scope for standard claims' do + expect(described_class.new(name: 'family_name').scope).to eq :profile + expect(described_class.new(name: :family_name).scope).to eq :profile + expect(described_class.new(name: 'email').scope).to eq :email + expect(described_class.new(name: :email).scope).to eq :email + expect(described_class.new(name: 'address').scope).to eq :address + expect(described_class.new(name: :address).scope).to eq :address + expect(described_class.new(name: 'phone_number').scope).to eq :phone + expect(described_class.new(name: :phone_number).scope).to eq :phone + end + + it 'falls back to the profile scope for non-standard claims' do + expect(described_class.new(name: 'unknown').scope).to eq :profile + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/config_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/config_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..5de7af5d14a6438266491fc9c7faa88ca9779d01 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/config_spec.rb @@ -0,0 +1,232 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect, 'configuration' do + subject { described_class.configuration } + + describe '#configure' do + it 'fails if not set to :active_record' do + # stub ORM setup to avoid Doorkeeper exceptions + allow(Doorkeeper).to receive(:setup_orm_adapter) + allow(Doorkeeper).to receive(:setup_orm_models) + allow(Doorkeeper).to receive(:setup_application_owner) + + Doorkeeper.configure do + orm :mongoid + end + + expect do + described_class.configure {} + end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration + end + end + + describe 'jws_private_key' do + it 'delegates to signing_key' do + value = 'private_key' + described_class.configure do + jws_private_key value + end + expect(subject.signing_key).to eq(value) + end + end + + describe 'signing_key' do + it 'sets the value that is accessible via signing_key' do + value = 'private_key' + described_class.configure do + signing_key value + end + expect(subject.signing_key).to eq(value) + end + end + + describe 'issuer' do + it 'sets the value that is accessible via issuer' do + value = 'issuer' + described_class.configure do + issuer value + end + expect(subject.issuer).to eq(value) + end + + it 'sets the block that is accessible via issuer' do + block = proc {} + described_class.configure do + issuer(&block) + end + expect(subject.issuer).to eq(block) + end + end + + describe 'resource_owner_from_access_token' do + it 'sets the block that is accessible via resource_owner_from_access_token' do + block = proc {} + described_class.configure do + resource_owner_from_access_token(&block) + end + expect(subject.resource_owner_from_access_token).to eq(block) + end + + it 'fails if unset' do + described_class.configure {} + + expect do + subject.resource_owner_from_access_token.call + end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration + end + end + + describe 'auth_time_from_resource_owner' do + it 'sets the block that is accessible via auth_time_from_resource_owner' do + block = proc {} + described_class.configure do + auth_time_from_resource_owner(&block) + end + expect(subject.auth_time_from_resource_owner).to eq(block) + end + + it 'fails if unset' do + described_class.configure {} + + expect do + subject.auth_time_from_resource_owner.call + end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration + end + end + + describe 'reauthenticate_resource_owner' do + it 'sets the block that is accessible via reauthenticate_resource_owner' do + block = proc {} + described_class.configure do + reauthenticate_resource_owner(&block) + end + expect(subject.reauthenticate_resource_owner).to eq(block) + end + + it 'fails if unset' do + described_class.configure {} + + expect do + subject.reauthenticate_resource_owner.call + end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration + end + end + + describe 'select_account_for_resource_owner' do + it 'sets the block that is accessible via select_account_for_resource_owner' do + block = proc {} + described_class.configure do + select_account_for_resource_owner(&block) + end + expect(subject.select_account_for_resource_owner).to eq(block) + end + + it 'fails if unset' do + described_class.configure {} + + expect do + subject.select_account_for_resource_owner.call + end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration + end + end + + describe 'subject' do + it 'sets the block that is accessible via subject' do + block = proc {} + described_class.configure do + subject(&block) + end + expect(subject.subject).to eq(block) + end + + it 'fails if unset' do + described_class.configure {} + + expect do + subject.subject.call + end.to raise_error Doorkeeper::OpenidConnect::Errors::InvalidConfiguration + end + end + + describe 'expiration' do + it 'sets the value that is accessible via expiration' do + value = 'expiration' + described_class.configure do + expiration value + end + expect(subject.expiration).to eq(value) + end + end + + describe 'claims' do + it 'sets the claims configuration that is accessible via claims' do + described_class.configure do + claims do + end + end + expect(subject.claims).not_to be_nil + end + end + + describe 'protocol' do + it 'defaults to https in production' do + expect(::Rails.env).to receive(:production?).and_return(true) + + expect(subject.protocol.call).to eq(:https) + end + + it 'defaults to http in other environments' do + expect(::Rails.env).to receive(:production?).and_return(false) + + expect(subject.protocol.call).to eq(:http) + end + + it 'can be set to other protocols' do + described_class.configure do + protocol { :ftp } + end + + expect(subject.protocol.call).to eq(:ftp) + end + end + + describe 'end_session_endpoint' do + it 'defaults to nil' do + expect(subject.end_session_endpoint.call).to be_nil + end + + it 'can be set to a custom url' do + described_class.configure do + end_session_endpoint { 'http://test.host/logout' } + end + + expect(subject.end_session_endpoint.call).to eq('http://test.host/logout') + end + end + + describe 'discovery_url_options' do + it 'defaults to empty hash' do + expect(subject.discovery_url_options.call).to be_kind_of(Hash) + expect(subject.discovery_url_options.call).to be_empty + end + + it 'can be set to other hosts' do + Doorkeeper::OpenidConnect.configure do + discovery_url_options do |request| + { + authorization: { host: 'alternate-authorization-host' }, + token: { host: 'alternate-token-host' }, + revocation: { host: 'alternate-revocation-host' }, + introspection: { host: 'alternate-introspection-host' }, + userinfo: { host: 'alternate-userinfo-host' }, + jwks: { host: 'alternate-jwks-host' } + } + end + end + + expect(subject.discovery_url_options.call[:authorization]).to eq(host: 'alternate-authorization-host') + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..2e9e6722670f4cf22e496e2292f635e7589ef033 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_spec.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::IdToken do + subject { described_class.new(access_token, nonce) } + + let(:access_token) { create :access_token, resource_owner_id: user.id, scopes: 'openid' } + let(:user) { create :user } + let(:nonce) { '123456' } + + before do + allow(Time).to receive(:now) { Time.zone.at 60 } + end + + describe '#nonce' do + it 'returns the stored nonce' do + expect(subject.nonce).to eq '123456' + end + end + + describe '#claims' do + it 'returns all default claims' do + expect(subject.claims).to eq( + iss: 'dummy', + sub: user.id.to_s, + aud: access_token.application.uid, + exp: 180, + iat: 60, + nonce: nonce, + auth_time: 23, + both_responses: 'both', + id_token_response: 'id_token', + ) + end + + context 'when application is not set on the access token' do + before do + access_token.application = nil + end + + it 'returns all default claims except audience' do + expect(subject.claims).to eq( + iss: 'dummy', + sub: user.id.to_s, + aud: nil, + exp: 180, + iat: 60, + nonce: nonce, + auth_time: 23, + both_responses: 'both', + id_token_response: 'id_token', + ) + end + end + end + + describe '#as_json' do + it 'returns claims with nil values and empty strings removed' do + allow(subject).to receive(:issuer).and_return(nil) + allow(subject).to receive(:subject).and_return('') + allow(subject).to receive(:audience).and_return(' ') + + json = subject.as_json + + expect(json).not_to include :iss + expect(json).not_to include :sub + expect(json).to include :aud + end + end + + describe '#as_jws_token' do + shared_examples 'a jws token' do + it 'returns claims encoded as JWT' do + algorithms = [Doorkeeper::OpenidConnect.signing_algorithm.to_s] + + data, headers = ::JWT.decode subject.as_jws_token, Doorkeeper::OpenidConnect.signing_key.keypair, true, { algorithms: algorithms } + + expect(data.to_hash).to eq subject.as_json.stringify_keys + expect(headers["kid"]).to eq Doorkeeper::OpenidConnect.signing_key.kid + expect(headers["alg"]).to eq Doorkeeper::OpenidConnect.signing_algorithm.to_s + end + end + + it_behaves_like 'a jws token' + + context 'when signing_algorithm is EC' do + before { configure_ec } + + it_behaves_like 'a jws token' + end + + context 'when signing_algorithm is HMAC' do + before { configure_hmac } + + it_behaves_like 'a jws token' + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_token_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_token_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..597fff64008def43cb0c406156af1f00b4f99912 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/id_token_token_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::IdTokenToken do + subject { described_class.new(access_token, nonce) } + + let(:access_token) { create :access_token, resource_owner_id: user.id, scopes: 'openid' } + let(:user) { create :user } + let(:nonce) { '123456' } + + before do + allow(Time).to receive(:now) { Time.zone.at 60 } + end + + describe '#claims' do + it 'returns all default claims' do + # access token is from http://openid.net/specs/openid-connect-core-1_0.html + # so we can test `at_hash` value + access_token.update(token: 'jHkWEdUXMU1BwAsC4vtUsZwnNvTIxEl0z9K3vx5KF0Y') + + expect(subject.claims).to eq({ + iss: 'dummy', + sub: user.id.to_s, + aud: access_token.application.uid, + exp: 180, + iat: 60, + nonce: nonce, + auth_time: 23, + at_hash: '77QmUPtjPfzWtF2AnpK9RQ', + both_responses: 'both', + id_token_response: 'id_token', + }) + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization/code_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization/code_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..0062c109c67795cb102c6f9071570adcc68cd24f --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization/code_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::OAuth::Authorization::Code do + subject { Doorkeeper::OAuth::Authorization::Code.new pre_auth, resource_owner } + + let(:resource_owner) { create :user } + let(:access_grant) { create :access_grant } + let(:pre_auth) { double } + let(:client) { double } + + describe '#issue_token' do + before do + allow(pre_auth).to receive(:client) { client } + allow(pre_auth).to receive(:redirect_uri).and_return('redirect_uri') + allow(pre_auth).to receive(:scopes).and_return('scopes') + allow(pre_auth).to receive(:nonce).and_return('123456') + allow(pre_auth).to receive(:code_challenge).and_return('987654') + allow(pre_auth).to receive(:code_challenge_method).and_return('plain') + allow(pre_auth).to receive(:custom_access_token_attributes).and_return({}) + allow(client).to receive(:id).and_return('client_id') + + allow(Doorkeeper::AccessGrant).to receive(:create!) { access_grant } + allow(Doorkeeper::OpenidConnect::Request).to receive(:create!) + end + + it 'stores the nonce' do + subject.issue_token + + expect(Doorkeeper::OpenidConnect::Request).to have_received(:create!).with({ + access_grant: access_grant, + nonce: '123456' + }) + end + + it 'does not store the nonce if not present' do + allow(pre_auth).to receive(:nonce).and_return(nil) + subject.issue_token + + expect(Doorkeeper::OpenidConnect::Request).not_to have_received(:create!) + end + + it 'does not store the nonce if blank' do + allow(pre_auth).to receive(:nonce).and_return(' ') + subject.issue_token + + expect(Doorkeeper::OpenidConnect::Request).not_to have_received(:create!) + end + + it 'returns the created grant' do + expect(subject.issue_token).to be_a Doorkeeper::AccessGrant + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization_code_request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization_code_request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..8e5b242391faef63daef214e445bce521adfd616 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/authorization_code_request_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::OAuth::AuthorizationCodeRequest do + subject do + Doorkeeper::OAuth::AuthorizationCodeRequest.new(server, grant, client).tap do |request| + request.instance_variable_set '@response', response + request.instance_variable_set('@access_token', token) + end + end + + let(:server) { double } + let(:client) { double } + let(:grant) { create :access_grant, openid_request: openid_request } + let(:openid_request) { create :openid_request, nonce: '123456' } + let(:token) { create :access_token } + let(:response) { Doorkeeper::OAuth::TokenResponse.new token } + + describe '#after_successful_response' do + it 'adds the ID token to the response' do + subject.send :after_successful_response + + expect(response.id_token).to be_a Doorkeeper::OpenidConnect::IdToken + expect(response.id_token.nonce).to eq '123456' + end + + it 'destroys the OpenID request record' do + grant.save! + + expect do + subject.send :after_successful_response + end.to change { Doorkeeper::OpenidConnect::Request.count }.by(-1) + end + + it 'skips the nonce if not present' do + grant.openid_request.nonce = nil + subject.send :after_successful_response + + expect(response.id_token.nonce).to be_nil + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3dd93cc42d2ed009df1309b10fe2edcf70c92663 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_request_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OAuth::IdTokenRequest do + subject do + described_class.new(pre_auth, owner) + end + + let :application do + FactoryBot.create(:application, scopes: 'public') + end + + let :pre_auth do + server = Doorkeeper.configuration + allow(server).to receive(:grant_flows).and_return(['implicit_oidc']) + + client = Doorkeeper::OAuth::Client.new(application) + + attributes = { + client_id: client.uid, + response_type: 'id_token', + redirect_uri: 'https://app.com/callback', + scope: 'public', + nonce: '12345', + } + + pre_auth = Doorkeeper::OAuth::PreAuthorization.new(server, attributes) + pre_auth.authorizable? # triggers loading of pre_auth.client + pre_auth + end + + let(:owner) { build_stubbed(:user) } + + # just to make sure self created pre_auth is authorizable + it 'pre_auth should be valid' do + expect(pre_auth).to be_authorizable + end + + it 'creates an access token' do + expect do + subject.authorize + end.to change { Doorkeeper::AccessToken.count }.by(1) + end + + it 'returns id_token response' do + expect(subject.authorize).to be_a(Doorkeeper::OAuth::IdTokenResponse) + end + + context 'token reuse' do + it 'creates a new token if there are no matching tokens' do + allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) + expect do + subject.authorize + end.to change { Doorkeeper::AccessToken.count }.by(1) + end + + it 'creates a new token if scopes do not match' do + allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) + create(:access_token, application_id: pre_auth.client.id, + resource_owner_id: owner.id, scopes: '') + expect do + subject.authorize + end.to change { Doorkeeper::AccessToken.count }.by(1) + end + + it 'skips token creation if there is a matching one' do + allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true) + allow(application.scopes).to receive(:has_scopes?).and_return(true) + allow(application.scopes).to receive(:all?).and_return(true) + + create(:access_token, application_id: pre_auth.client.id, + resource_owner_id: owner.id, scopes: 'public') + + expect { subject.authorize }.not_to(change { Doorkeeper::AccessToken.count }) + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_response_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_response_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..0381f921b2e24c495293b41eca7b1344114ff9c1 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_response_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OAuth::IdTokenResponse do + subject { described_class.new(pre_auth, auth, id_token) } + + let(:token) { create :access_token } + let(:application) do + create(:application, scopes: 'public') + end + + let(:pre_auth) do + double( + :pre_auth, + client: application, + redirect_uri: 'http://tst.com/cb', + state: 'state', + scopes: Doorkeeper::OAuth::Scopes.from_string('public'), + error: nil, + authorizable?: true, + nonce: '12345' + ) + end + + let(:owner) { build_stubbed(:user) } + + let(:auth) do + Doorkeeper::OAuth::Authorization::Token.new(pre_auth, owner).tap do |c| + if c.respond_to?(:issue_token!) + c.issue_token! + else + c.issue_token + end + end + end + let(:id_token) { Doorkeeper::OpenidConnect::IdToken.new(token, pre_auth) } + + describe '#body' do + it 'return body response for id_token' do + expect(subject.body).to eq({ + expires_in: auth.token.expires_in_seconds, + state: pre_auth.state, + id_token: id_token.as_jws_token + }) + end + end + + describe '#redirect_uri' do + it 'includes expires_in, id_token and state' do + expect(subject.redirect_uri).to include("#{pre_auth.redirect_uri}#expires_in=#{auth.token.expires_in_seconds}&" \ + "state=#{pre_auth.state}&" \ + "id_token=#{id_token.as_jws_token}") + end + + it 'does not include access_token' do + expect(subject.redirect_uri).not_to include('access_token') + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..760459531c3e06161feb79a2c562908c35396a19 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_request_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OAuth::IdTokenTokenRequest do + subject do + described_class.new(pre_auth, owner) + end + + let :application do + FactoryBot.create(:application, scopes: 'public') + end + + let :pre_auth do + server = Doorkeeper.configuration + allow(server).to receive(:grant_flows).and_return(['implicit_oidc']) + + client = Doorkeeper::OAuth::Client.new(application) + + attributes = { + client_id: client.uid, + response_type: 'id_token token', + redirect_uri: 'https://app.com/callback', + scope: 'public', + nonce: '12345', + } + + pre_auth = Doorkeeper::OAuth::PreAuthorization.new(server, attributes) + pre_auth.authorizable? + pre_auth + end + + let(:owner) { build_stubbed(:user) } + + # just to make sure self created pre_auth is authorizable + it 'pre_auth should be valid' do + expect(pre_auth).to be_authorizable + end + + it 'creates an access token' do + expect do + subject.authorize + end.to change { Doorkeeper::AccessToken.count }.by(1) + end + + it 'returns id_token token response' do + expect(subject.authorize).to be_a(Doorkeeper::OAuth::IdTokenTokenResponse) + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_response_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_response_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..56f7724e6f24ac62ef1d226f511daf2ab0724b69 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/id_token_token_response_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OAuth::IdTokenTokenResponse do + subject { described_class.new(pre_auth, auth, id_token) } + + let(:token) { create :access_token } + let(:application) do + create(:application, scopes: 'public') + end + let(:pre_auth) do + double( + :pre_auth, + client: application, + redirect_uri: 'http://tst.com/cb', + state: 'state', + scopes: Doorkeeper::OAuth::Scopes.from_string('public'), + error: nil, + authorizable?: true, + nonce: '12345' + ) + end + let(:owner) { build_stubbed(:user) } + let(:auth) do + Doorkeeper::OAuth::Authorization::Token.new(pre_auth, owner).tap do |c| + if c.respond_to?(:issue_token!) + c.issue_token! + else + c.issue_token + end + end + end + let(:id_token) { Doorkeeper::OpenidConnect::IdToken.new(token, pre_auth) } + + describe '#body' do + it 'return body response for id_token and access_token' do + expect(subject.body).to eq({ + expires_in: auth.token.expires_in_seconds, + state: pre_auth.state, + id_token: id_token.as_jws_token, + access_token: auth.token.token, + token_type: auth.token.token_type + }) + end + end + + describe '#redirect_uri' do + it 'includes id_token, info of access_token and state' do + expect(subject.redirect_uri).to include("#{pre_auth.redirect_uri}#expires_in=#{auth.token.expires_in_seconds}&" \ + "state=#{pre_auth.state}&" \ + "id_token=#{id_token.as_jws_token}&" \ + "access_token=#{auth.token.token}&token_type=#{auth.token.token_type}") + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/password_access_token_request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/password_access_token_request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..2c235e7523156be46764fe7416a07d1de1054e7a --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/password_access_token_request_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::OAuth::PasswordAccessTokenRequest do + if Gem.loaded_specs['doorkeeper'].version >= Gem::Version.create('5.5.1') + subject { Doorkeeper::OAuth::PasswordAccessTokenRequest.new server, client, credentials, resource_owner, { nonce: '123456' } } + else + subject { Doorkeeper::OAuth::PasswordAccessTokenRequest.new server, client, resource_owner, { nonce: '123456' } } + end + + let(:server) { double } + let(:client) { double } + let(:credentials) { } + let(:resource_owner) { create :user } + let(:token) { create :access_token } + let(:response) { Doorkeeper::OAuth::TokenResponse.new token } + + describe '#initialize' do + it 'stores the nonce attribute' do + expect(subject.nonce).to eq '123456' + end + end + + describe '#after_successful_response' do + it 'adds the ID token to the response' do + subject.instance_variable_set '@response', response + subject.instance_variable_set '@access_token', token + subject.send :after_successful_response + + expect(response.id_token).to be_a Doorkeeper::OpenidConnect::IdToken + expect(response.id_token.nonce).to eq '123456' + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/pre_authorization_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/pre_authorization_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c9807a4691243e8c1beec064fae3005bb11ff8cc --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/pre_authorization_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::OAuth::PreAuthorization do + subject { Doorkeeper::OAuth::PreAuthorization.new server, attrs } + + let(:server) { Doorkeeper.configuration } + let(:attrs) {} + + describe '#initialize' do + context 'with nonce parameter' do + let(:attrs) { { nonce: '123456' } } + + it 'stores the nonce attribute' do + expect(subject.nonce).to eq '123456' + end + end + end + + describe '#error_response' do + context 'with response_type = code' do + let(:attrs) { { response_type: 'code', redirect_uri: 'client.com/callback' } } + + it 'redirects to redirect_uri with query parameter' do + expect(subject.error_response.redirect_uri).to match(/#{attrs[:redirect_uri]}\?/) + end + end + + context 'with response_type = token' do + let(:attrs) { { response_type: 'token', redirect_uri: 'client.com/callback' } } + + it 'redirects to redirect_uri with fragment' do + expect(subject.error_response.redirect_uri).to match(/#{attrs[:redirect_uri]}#/) + end + end + + context 'with response_type = id_token' do + let(:attrs) { { response_type: 'id_token', redirect_uri: 'client.com/callback' } } + + it 'redirects to redirect_uri with fragment' do + expect(subject.error_response.redirect_uri).to match(/#{attrs[:redirect_uri]}#/) + end + end + + context 'with response_type = id_token token' do + let(:attrs) { { response_type: 'id_token token', redirect_uri: 'client.com/callback' } } + + it 'redirects to redirect_uri with fragment' do + expect(subject.error_response.redirect_uri).to match(/#{attrs[:redirect_uri]}#/) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/token_response_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/token_response_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..3fb85a2ea718fc571489e8a747bab884f998d6b6 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/oauth/token_response_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::OAuth::TokenResponse do + subject { Doorkeeper::OAuth::TokenResponse.new token } + + let(:token) { create :access_token } + let(:client) { Doorkeeper::OAuth::Client.new create(:application) } + let(:pre_auth) { Doorkeeper::OAuth::PreAuthorization.new(Doorkeeper.configuration, client_id: client.uid, nonce: '123456') } + let(:id_token) { Doorkeeper::OpenidConnect::IdToken.new token, pre_auth } + + before do + pre_auth.valid? # triggers loading of pre_auth.client + end + + describe '#body' do + before do + subject.id_token = id_token + end + + context 'with the openid scope present' do + before do + token.scopes = 'openid email' + end + + it 'adds the ID token to the response' do + expect(subject.body[:id_token]).to eq id_token.as_jws_token + end + end + + context 'with the openid scope present but no id_token' do + before do + token.scopes = 'openid email' + subject.id_token = nil + end + + it 'adds the ID token to the response' do + expect(subject.body[:id_token]).to be_truthy + end + end + + context 'with the openid scope not present' do + before do + token.scopes = 'email' + end + + it 'does not add the ID token to the response' do + expect(subject.body).not_to include :id_token + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/openid_connect_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/openid_connect_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..31a03afb663b0176379a1fb34101a93808e8f30b --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/openid_connect_spec.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect do + describe '.signing_algorithm' do + it 'returns the signing_algorithm as an uppercase symbol' do + expect(subject.signing_algorithm).to eq :RS256 + end + end + + describe '.signing_key' do + it 'returns the private key as JWK instance' do + expect(subject.signing_key).to be_a ::JWT::JWK::KeyBase + expect(subject.signing_key.kid).to eq 'IqYwZo2cE6hsyhs48cU8QHH4GanKIx0S4Dc99kgTIMA' + end + end + + describe '.signing_key_normalized' do + context 'when signing key is RSA' do + it 'returns the RSA public key parameters' do + expect(subject.signing_key_normalized).to eq( + :kty => 'RSA', + :kid => 'IqYwZo2cE6hsyhs48cU8QHH4GanKIx0S4Dc99kgTIMA', + :e => 'AQAB', + :n => 'sjdnSA6UWUQQHf6BLIkIEUhMRNBJC1NN_pFt1EJmEiI88GS0ceROO5B5Ooo9Y3QOWJ_n-u1uwTHBz0HCTN4wgArWd1TcqB5GQzQRP4eYnWyPfi4CfeqAHzQp-v4VwbcK0LW4FqtW5D0dtrFtI281FDxLhARzkhU2y7fuYhL8fVw5rUhE8uwvHRZ5CEZyxf7BSHxIvOZAAymhuzNLATt2DGkDInU1BmF75tEtBJAVLzWG_j4LPZh1EpSdfezqaXQlcy9PJi916UzTl0P7Yy-ulOdUsMlB6yo8qKTY1-AbZ5jzneHbGDU_O8QjYvii1WDmJ60t0jXicmOkGrOhruOptw' + ) + end + end + + context 'when signing key is EC' do + before { configure_ec } + + it 'returns the EC public key parameters' do + expect(subject.signing_key_normalized).to eq( + :kty => 'EC', + :kid => 'dOx_AhaepicN2r2M-sxZhgkYZMCX7dYhPsNOw1ZiFnI', + :crv => 'P-521', + :x => 'AeYVvbl3zZcFCdE-0msqOowYODjzeXAhjsZKhdNjGlDREvko3UFOw6S43g-s8bvVBmBz3fCodEzFRYQqJVI4UFvF', + :y => 'AYJ7GYeBm_Fb6liN53xGASdbRSzF34h4BDSVYzjtQc7I-1LK17fwwS3VfQCJwaT6zX33HTrhR4VoUEUJHKwR3dNs' + ) + end + end + + context 'when signing key is HMAC' do + before { configure_hmac } + + it 'returns the HMAC public key parameters' do + expect(subject.signing_key_normalized).to eq( + :kty => 'oct', + :kid => 'lyAW7LdxryFWQtLdgxZpOrI87APHrzJKgWLT0BkWVog' + ) + end + end + end + + describe 'registering grant flows' do + describe Doorkeeper::Request do + it 'uses the correct strategy for "id_token" response types' do + expect(described_class.authorization_strategy('id_token')).to eq(Doorkeeper::Request::IdToken) + end + + it 'uses the correct strategy for "id_token token" response types' do + expect(described_class.authorization_strategy('id_token token')).to eq(Doorkeeper::Request::IdTokenToken) + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/routes_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/routes_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..2f7c8b510a865e6d1d19f9e6da4d38512db36645 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/routes_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::Rails::Routes, type: :routing do + describe 'userinfo' do + it 'maps GET #show' do + expect(get: 'oauth/userinfo').to route_to( + controller: 'doorkeeper/openid_connect/userinfo', + action: 'show' + ) + end + + it 'maps POST #show' do + expect(post: 'oauth/userinfo').to route_to( + controller: 'doorkeeper/openid_connect/userinfo', + action: 'show' + ) + end + end + + describe 'discovery' do + it 'maps GET #provider' do + expect(get: '.well-known/openid-configuration').to route_to( + controller: 'doorkeeper/openid_connect/discovery', + action: 'provider' + ) + end + + it 'maps GET #webfinger' do + expect(get: '.well-known/webfinger').to route_to( + controller: 'doorkeeper/openid_connect/discovery', + action: 'webfinger' + ) + end + + it 'maps GET #keys' do + expect(get: 'oauth/discovery/keys').to route_to( + controller: 'doorkeeper/openid_connect/discovery', + action: 'keys' + ) + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/lib/user_info_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/lib/user_info_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..cf866b42d6188ea64d9398bd297eed4ff3e96ce8 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/lib/user_info_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::UserInfo do + subject { described_class.new token } + + let(:user) { create :user, name: 'Joe' } + let(:token) { create :access_token, resource_owner_id: user.id, scopes: scopes } + let(:scopes) { 'openid' } + + describe '#claims' do + it 'returns all accessible claims' do + expect(subject.claims).to eq({ + sub: user.id.to_s, + created_at: user.created_at.to_i, + variable_name: 'openid-name', + token_id: token.id, + both_responses: 'both', + user_info_response: 'user_info', + }) + end + + context 'with a grant for the profile scopes' do + let(:scopes) { 'openid profile' } + + it 'returns additional profile claims' do + expect(subject.claims).to eq({ + sub: user.id.to_s, + name: 'Joe', + created_at: user.created_at.to_i, + updated_at: user.updated_at.to_i, + variable_name: 'profile-name', + token_id: token.id, + both_responses: 'both', + user_info_response: 'user_info', + }) + end + end + end + + describe '#as_json' do + it 'returns claims with nil values and empty strings removed' do + allow(subject).to receive(:claims).and_return({ + nil: nil, + empty: '', + blank: ' ', + }) + + expect(subject.as_json).to eq({ + blank: ' ' + }) + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/models/access_grant_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/models/access_grant_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..43e9ef8db6bb723a0cc73e2c621f7d66262f239f --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/models/access_grant_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::AccessGrant do + subject { Doorkeeper::AccessGrant.new } + + it 'has one openid_request' do + association = subject.class.reflect_on_association :openid_request + + expect(association.options).to eq({ + class_name: 'Doorkeeper::OpenidConnect::Request', + inverse_of: :access_grant, + foreign_key: "access_grant_id", + dependent: :delete, + }) + end + + it 'extends the base doorkeeper AccessGrant' do + expect(subject).to respond_to(:"openid_request=") + end + + describe '#delete' do + it 'cascades to oauth_openid_requests' do + if Rails::VERSION::MAJOR >= 6 + access_grant = create(:access_grant, application: create(:application)) + create(:openid_request, access_grant: access_grant) + + expect { access_grant.delete } + .to(change { Doorkeeper::OpenidConnect::Request.count }.by(-1)) + else + skip <<-MSG.strip + Needs Rails 6 for foreign key support with sqlite3: + https://blog.bigbinary.com/2019/09/24/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3.html + MSG + end + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/models/request_spec.rb b/vendor/gems/doorkeeper-openid_connect/spec/models/request_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..4126fbd012335a6acac46dc8dc97d9a41e488eb4 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/models/request_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Doorkeeper::OpenidConnect::Request do + describe 'validations' do + it 'requires an access grant' do + subject.access_grant_id = nil + + expect(subject).not_to be_valid + expect(subject.errors).to include :access_grant_id + end + + it 'requires a nonce' do + subject.nonce = nil + + expect(subject).not_to be_valid + expect(subject.errors).to include :nonce + end + end + + describe 'associations' do + it 'belongs to an access_grant' do + association = subject.class.reflect_on_association :access_grant + + expect(association.options).to eq({ + class_name: 'Doorkeeper::AccessGrant', + inverse_of: :openid_request, + }) + end + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/rails_helper.rb b/vendor/gems/doorkeeper-openid_connect/spec/rails_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..79b9c48543b37c08c0e8d24eb5732c438df51b27 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/rails_helper.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV['RAILS_ENV'] ||= 'test' +require 'dummy/config/environment' +# Prevent database truncation if the environment is production +abort('The Rails environment is running in production mode!') if Rails.env.production? +require 'spec_helper' +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +# Checks for pending migration and applies them before tests are run. +# If you are not using ActiveRecord, you can remove this line. +Dir.chdir('spec/dummy') do + ActiveRecord::Migration.maintain_test_schema! +end + +require_relative 'support/doorkeeper_configuration.rb' + +require 'factory_bot' +FactoryBot.find_definitions + +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") + + config.include FactoryBot::Syntax::Methods + + # Reinitialize configuration after each example + config.after do + load Rails.root.join('config/initializers/doorkeeper.rb') + load Rails.root.join('config/initializers/doorkeeper_openid_connect.rb') + end +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/spec_helper.rb b/vendor/gems/doorkeeper-openid_connect/spec/spec_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..b0b2a54d4b00225b066fc44a6fa99c27eb726873 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/spec_helper.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require 'pry-byebug' + +puts "====> Doorkeeper version: #{Doorkeeper::VERSION::STRING}" + +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = 'spec/examples.txt' + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + # config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + # config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +end diff --git a/vendor/gems/doorkeeper-openid_connect/spec/support/doorkeeper_configuration.rb b/vendor/gems/doorkeeper-openid_connect/spec/support/doorkeeper_configuration.rb new file mode 100644 index 0000000000000000000000000000000000000000..5198a0b35144351b9a6b523701065938c24b4230 --- /dev/null +++ b/vendor/gems/doorkeeper-openid_connect/spec/support/doorkeeper_configuration.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module DoorkeeperConfiguration + def configure_doorkeeper(signing_key, signing_algorithm) + Doorkeeper::OpenidConnect.configure do + signing_key signing_key + + signing_algorithm signing_algorithm + + resource_owner_from_access_token do |access_token| + User.find_by(id: access_token.resource_owner_id) + end + + auth_time_from_resource_owner do |resource_owner| + resource_owner.current_sign_in_at + end + + subject do |resource_owner| + resource_owner.id + end + end + end + + def configure_ec + signing_key = <<~EOL + -----BEGIN EC PRIVATE KEY----- + MIHbAgEBBEF9VcxGjPKczrJlE1N3oEpZsauQfDXIjLeini7h4/3+DOKw2VWE4lCU + rNJJL65EHT+2TriRg2xSb0l0rK/MAFAFraAHBgUrgQQAI6GBiQOBhgAEAeYVvbl3 + zZcFCdE+0msqOowYODjzeXAhjsZKhdNjGlDREvko3UFOw6S43g+s8bvVBmBz3fCo + dEzFRYQqJVI4UFvFAYJ7GYeBm/Fb6liN53xGASdbRSzF34h4BDSVYzjtQc7I+1LK + 17fwwS3VfQCJwaT6zX33HTrhR4VoUEUJHKwR3dNs + -----END EC PRIVATE KEY----- + EOL + configure_doorkeeper(signing_key, :ES512) + end + + def configure_hmac + configure_doorkeeper('the_greatest_secret_key', :HS512) + end +end + +RSpec.configure { |config| config.include DoorkeeperConfiguration }