omniauth_openid_connect 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/config/rubocop_linter_action.yml +59 -0
- data/.github/stale.yml +17 -0
- data/.github/workflows/main.yml +31 -0
- data/.github/workflows/rubocop.yml +22 -0
- data/.rubocop.yml +7 -1
- data/CHANGELOG.md +32 -0
- data/Guardfile +1 -1
- data/README.md +63 -9
- data/lib/omniauth/openid_connect/errors.rb +3 -0
- data/lib/omniauth/openid_connect/version.rb +1 -1
- data/lib/omniauth/strategies/openid_connect.rb +85 -22
- data/omniauth_openid_connect.gemspec +12 -4
- data/test/lib/omniauth/strategies/openid_connect_test.rb +155 -17
- data/test/strategy_test_case.rb +2 -0
- metadata +26 -12
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b5060fd9a0536e2740b340c56459f76b628912dea1ad54da415c2453921e6e3
|
4
|
+
data.tar.gz: ada9bd68c69837538cd485ce0595525b2109feb0f79611a3ceb06fa1bf7eed96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24c424fb608e45beba966b6914accdfad6e5af277c9428c94d3aec4ab3f4c010bfa66117a42d6ad1f57de9ea6d6d3ff99eaa5a33bdcbc753d1b7db568f3e870b
|
7
|
+
data.tar.gz: f2ebfcd68b35425cc656ecaa58151b962d0bc96a4023f1bfcf312e363e2e0878c298bc90d7fc70104220b71cdbc77346b3f64c4653222b8df1110a12bb249dd0
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Description: The name of the check that will be created.
|
2
|
+
# Valid Options: A reasonably sized string.
|
3
|
+
# Default: 'Rubocop Action'
|
4
|
+
check_name: 'Rubocop Results'
|
5
|
+
|
6
|
+
# Description: Versions required to run your RuboCop checks.
|
7
|
+
# Valid options: RuboCop and any RuboCop extension, by default the latest gem version will be used. You can explicitly state that
|
8
|
+
# (not required) or use a version number, like '1.5.1'.
|
9
|
+
# Default:
|
10
|
+
# versions:
|
11
|
+
# - rubocop: 'latest'
|
12
|
+
versions:
|
13
|
+
- rubocop
|
14
|
+
- rubocop-minitest
|
15
|
+
- rubocop-performance: '1.5.1'
|
16
|
+
|
17
|
+
# Description: Rubocop configuration file path relative to the workspace.
|
18
|
+
# Valid options: A valid file path inside of the workspace.
|
19
|
+
# Default: nil
|
20
|
+
# Note: This does not need to be filled out for Rubocop to still find your config.
|
21
|
+
# Resource: https://rubocop.readthedocs.io/en/stable/configuration/
|
22
|
+
rubocop_config_path: '.rubocop.yml'
|
23
|
+
|
24
|
+
# Run all cops enabled by configuration except this list.
|
25
|
+
# Valid options: list of valid cop(s) and/or departments.
|
26
|
+
# Default: nil
|
27
|
+
# Resource: https://rubocop.readthedocs.io/en/stable/cops/
|
28
|
+
# rubocop_excluded_cops:
|
29
|
+
# - 'Style/FrozenStringLiteralComment'
|
30
|
+
|
31
|
+
# Minimum severity for exit with error code
|
32
|
+
# Valid options: 'refactor', 'convention', 'warning', 'error', or 'fatal'.
|
33
|
+
# Default: 'warning'
|
34
|
+
# Resource: https://rubocop.readthedocs.io/en/stable/configuration/#severity
|
35
|
+
# rubocop_fail_level: 'warning'
|
36
|
+
|
37
|
+
# Whether or not to use --force-exclusion when building the rubocop command. Use this if you are only linting modified
|
38
|
+
# files and typically excluded files have been changed. For example, if you exclude db/schema.rb in your rubocop.yml
|
39
|
+
# but a change gets made, then with the check_scope config set to 'modified' rubocop will lint db/schema.rb. If you set
|
40
|
+
# this to true, rubocop will ignore it.
|
41
|
+
# Valid options: true || false
|
42
|
+
# Default: false
|
43
|
+
|
44
|
+
# Instead of installing gems from rubygems, we can run `bundle install` on your project,
|
45
|
+
# you would need to do this if you are using something like 'rubocop-github' or if you don't
|
46
|
+
# want to list out dependencies with the `versions` key.
|
47
|
+
# Valid options: true || false
|
48
|
+
# Default: false
|
49
|
+
# bundle: false
|
50
|
+
|
51
|
+
# The scope of code that Rubocop should lint. Use this if you only want to lint changed files. If this is not set
|
52
|
+
# or not equal to 'modified', Rubocop is run against the entire codebase. Note that this will not work on the master branch.
|
53
|
+
# Valid options: 'modified'
|
54
|
+
# Default: nil
|
55
|
+
|
56
|
+
# The base branch against which changes will be compared, if check_scope config is set to 'modified'.
|
57
|
+
# This setting is not used if check_scope != 'modified'.
|
58
|
+
# Valid options: 'origin/another_branch'
|
59
|
+
# Default: 'origin/master'
|
data/.github/stale.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Number of days of inactivity before an issue becomes stale
|
2
|
+
daysUntilStale: 60
|
3
|
+
# Number of days of inactivity before a stale issue is closed
|
4
|
+
daysUntilClose: 7
|
5
|
+
# Issues with these labels will never be considered stale
|
6
|
+
exemptLabels:
|
7
|
+
- pinned
|
8
|
+
- security
|
9
|
+
# Label to use when marking an issue as stale
|
10
|
+
staleLabel: wontfix
|
11
|
+
# Comment to post when marking an issue as stale. Set to `false` to disable
|
12
|
+
markComment: >
|
13
|
+
This issue has been automatically marked as stale because it has not had
|
14
|
+
recent activity. It will be closed if no further activity occurs. Thank you
|
15
|
+
for your contributions.
|
16
|
+
# Comment to post when closing a stale issue. Set to `false` to disable
|
17
|
+
closeComment: false
|
@@ -0,0 +1,31 @@
|
|
1
|
+
name: Main
|
2
|
+
on:
|
3
|
+
push:
|
4
|
+
branches:
|
5
|
+
- main
|
6
|
+
- master
|
7
|
+
|
8
|
+
pull_request:
|
9
|
+
types: [opened, synchronize, reopened]
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
base:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
strategy:
|
15
|
+
fail-fast: false
|
16
|
+
matrix:
|
17
|
+
ruby: ["2.5", "2.6", "2.7", "3.0"]
|
18
|
+
name: Ruby ${{ matrix.ruby }}
|
19
|
+
|
20
|
+
steps:
|
21
|
+
- name: Checkout code
|
22
|
+
uses: actions/checkout@v2
|
23
|
+
|
24
|
+
- name: Setup Ruby
|
25
|
+
uses: ruby/setup-ruby@v1
|
26
|
+
with:
|
27
|
+
ruby-version: ${{ matrix.ruby }}
|
28
|
+
bundler-cache: true
|
29
|
+
|
30
|
+
- name: Run tests
|
31
|
+
run: bundle exec rake
|
@@ -0,0 +1,22 @@
|
|
1
|
+
name: Rubocop check
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
branches:
|
6
|
+
- "*"
|
7
|
+
push:
|
8
|
+
branches:
|
9
|
+
- master
|
10
|
+
jobs:
|
11
|
+
build:
|
12
|
+
name: RuboCop Action
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
steps:
|
15
|
+
- name: Checkout Action
|
16
|
+
uses: actions/checkout@v1
|
17
|
+
- name: Rubocop Linter Action
|
18
|
+
uses: andrewmcodes/rubocop-linter-action@v3.2.0
|
19
|
+
with:
|
20
|
+
action_config_path: '.github/config/rubocop_linter_action.yml'
|
21
|
+
env:
|
22
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
data/.rubocop.yml
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
Gemspec/RequiredRubyVersion:
|
2
|
+
Enabled: false
|
3
|
+
|
1
4
|
LineLength:
|
2
5
|
Description: 'Limit lines to 130 characters.'
|
3
6
|
Max: 130
|
@@ -36,7 +39,10 @@ Documentation:
|
|
36
39
|
Enabled: false
|
37
40
|
|
38
41
|
Metrics/AbcSize:
|
39
|
-
Max:
|
42
|
+
Max: 60
|
43
|
+
|
44
|
+
Metrics/ClassLength:
|
45
|
+
Max: 300
|
40
46
|
|
41
47
|
Metrics/CyclomaticComplexity:
|
42
48
|
Max: 50
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,35 @@
|
|
1
|
+
# v0.4.0 (02.05.2021)
|
2
|
+
|
3
|
+
- Support dynamic parameters to the authorize URI [#90](https://github.com/omniauth/omniauth_openid_connect/pull/90)
|
4
|
+
- Upgrade Faker and replace Travis with Github Actions [#102](https://github.com/omniauth/omniauth_openid_connect/pull/102)
|
5
|
+
- Make `omniauth_openid_connect` gem compatible with `omniauth v2.0` [#95](https://github.com/omniauth/omniauth_openid_connect/pull/95)
|
6
|
+
- Fall back to the discovered jwks when no key specified [#97](https://github.com/omniauth/omniauth_openid_connect/pull/97)
|
7
|
+
- Allow updating to omniauth v2 [#88](https://github.com/omniauth/omniauth_openid_connect/pull/88)
|
8
|
+
|
9
|
+
# v0.3.5 (07.06.2020)
|
10
|
+
|
11
|
+
- bugfix: Info from decoded id_token is not exposed into `request.env['omniauth.auth']` [#61](https://github.com/m0n9oose/omniauth_openid_connect/pull/61)
|
12
|
+
- bugfix: NoMethodError (`undefined method 'count' for #<OpenIDConnect::ResponseObject::IdToken>`) [#60](https://github.com/m0n9oose/omniauth_openid_connect/pull/60)
|
13
|
+
|
14
|
+
# v0.3.4 (21.05.2020)
|
15
|
+
|
16
|
+
- Try to verify id_token when response_type is code [#44](https://github.com/m0n9oose/omniauth_openid_connect/pull/44)
|
17
|
+
- Provide more information on error [#49](https://github.com/m0n9oose/omniauth_openid_connect/pull/49)
|
18
|
+
- Update configuration documentation [#53](https://github.com/m0n9oose/omniauth_openid_connect/pull/53)
|
19
|
+
- Add documentation about the send_scope_to_token_endpoint config property [#52](https://github.com/m0n9oose/omniauth_openid_connect/pull/52)
|
20
|
+
- refactor: take uid_field from raw_attributes [#54](https://github.com/m0n9oose/omniauth_openid_connect/pull/54)
|
21
|
+
- chore(ci): add 2.7, ruby-head and jruby-head [#55](https://github.com/m0n9oose/omniauth_openid_connect/pull/55)
|
22
|
+
|
23
|
+
# v0.3.3 (09.11.2019)
|
24
|
+
|
25
|
+
- Pass `acr_values` to authorize url [#43](https://github.com/m0n9oose/omniauth_openid_connect/pull/43)
|
26
|
+
- Add raw info for id token [#42](https://github.com/m0n9oose/omniauth_openid_connect/pull/42)
|
27
|
+
- Fixed `id_token` verification when `id_token` is not used [#41](https://github.com/m0n9oose/omniauth_openid_connect/pull/41)
|
28
|
+
- Cast `response_type` to string when checking if it is set in params [#36](https://github.com/m0n9oose/omniauth_openid_connect/pull/36)
|
29
|
+
- Support both symbol and string version of `response_type` option [#35](https://github.com/m0n9oose/omniauth_openid_connect/pull/35)
|
30
|
+
- Fix gemspec homepage [#33](https://github.com/m0n9oose/omniauth_openid_connect/pull/33)
|
31
|
+
- Add support for `response_type` `id_token` [#32](https://github.com/m0n9oose/omniauth_openid_connect/pull/32)
|
32
|
+
|
1
33
|
# v0.3.2 (03.08.2019)
|
2
34
|
|
3
35
|
- Use response_mode in `authorize_uri` if the option is defined [#30](https://github.com/m0n9oose/omniauth_openid_connect/pull/30)
|
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,19 @@
|
|
1
|
+
# Maintainers Wanted
|
2
|
+
|
3
|
+
This project is looking for maintainers.
|
4
|
+
|
5
|
+
Due to lack of using this gem in my projects I have no time to keep it alive.
|
6
|
+
Feel free to open an issue if you interested.
|
7
|
+
|
8
|
+
_This project is built and maintained 100% voluntarily._
|
9
|
+
|
1
10
|
# OmniAuth::OpenIDConnect
|
2
11
|
|
3
12
|
Originally was [omniauth-openid-connect](https://github.com/jjbohn/omniauth-openid-connect)
|
4
13
|
|
5
14
|
I've forked this repository and launch as separate gem because maintaining of original was dropped.
|
6
15
|
|
7
|
-
[![Build Status](https://
|
16
|
+
[![Build Status](https://github.com/omniauth/omniauth_openid_connect/actions/workflows/main.yml/badge.svg)](https://github.com/omniauth/omniauth_openid_connect/actions/workflows/main.yml)
|
8
17
|
|
9
18
|
## Installation
|
10
19
|
|
@@ -20,6 +29,10 @@ Or install it yourself as:
|
|
20
29
|
|
21
30
|
$ gem install omniauth_openid_connect
|
22
31
|
|
32
|
+
## Supported Ruby Versions
|
33
|
+
|
34
|
+
OmniAuth::OpenIDConnect is tested under 2.4, 2.5, 2.6, 2.7
|
35
|
+
|
23
36
|
## Usage
|
24
37
|
|
25
38
|
Example configuration
|
@@ -40,7 +53,46 @@ config.omniauth :openid_connect, {
|
|
40
53
|
}
|
41
54
|
```
|
42
55
|
|
43
|
-
|
56
|
+
### Options Overview
|
57
|
+
|
58
|
+
| Field | Description | Required | Default | Example/Options |
|
59
|
+
|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|----------------------------|-----------------------------------------------------|
|
60
|
+
| name | Arbitrary string to identify connection and identify it from other openid_connect providers | no | String: openid_connect | :my_idp |
|
61
|
+
| issuer | Root url for the authorization server | yes | | https://myprovider.com |
|
62
|
+
| discovery | Should OpenID discovery be used. This is recommended if the IDP provides a discovery endpoint. See client config for how to manually enter discovered values. | no | false | one of: true, false |
|
63
|
+
| client_auth_method | Which authentication method to use to authenticate your app with the authorization server | no | Sym: basic | "basic", "jwks" |
|
64
|
+
| scope | Which OpenID scopes to include (:openid is always required) | no | Array<sym> [:openid] | [:openid, :profile, :email] |
|
65
|
+
| response_type | Which OAuth2 response type to use with the authorization request | no | String: code | one of: 'code', 'id_token' |
|
66
|
+
| state | A value to be used for the OAuth2 state parameter on the authorization request. Can be a proc that generates a string. | no | Random 16 character string | Proc.new { SecureRandom.hex(32) } |
|
67
|
+
| response_mode | The response mode per [spec](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html) | no | nil | one of: :query, :fragment, :form_post, :web_message |
|
68
|
+
| display | An optional parameter to the authorization request to determine how the authorization and consent page | no | nil | one of: :page, :popup, :touch, :wap |
|
69
|
+
| prompt | An optional parameter to the authrization request to determine what pages the user will be shown | no | nil | one of: :none, :login, :consent, :select_account |
|
70
|
+
| send_scope_to_token_endpoint | Should the scope parameter be sent to the authorization token endpoint? | no | true | one of: true, false |
|
71
|
+
| post_logout_redirect_uri | The logout redirect uri to use per the [session management draft](https://openid.net/specs/openid-connect-session-1_0.html) | no | empty | https://myapp.com/logout/callback |
|
72
|
+
| uid_field | The field of the user info response to be used as a unique id | no | 'sub' | "sub", "preferred_username" |
|
73
|
+
| extra_authorize_params | A hash of extra fixed parameters that will be merged to the authorization request | no | Hash | {"tenant" => "common"} |
|
74
|
+
| allow_authorize_params | A list of allowed dynamic parameters that will be merged to the authorization request | no | Array | [:screen_name] |
|
75
|
+
| client_options | A hash of client options detailed in its own section | yes | | |
|
76
|
+
|
77
|
+
### Client Config Options
|
78
|
+
|
79
|
+
These are the configuration options for the client_options hash of the configuration.
|
80
|
+
|
81
|
+
| Field | Description | Default | Replaced by discovery? |
|
82
|
+
|------------------------|-----------------------------------------------------------------|------------|------------------------|
|
83
|
+
| identifier | The OAuth2 client_id | | |
|
84
|
+
| secret | The OAuth2 client secret | | |
|
85
|
+
| redirect_uri | The OAuth2 authorization callback url in your app | | |
|
86
|
+
| scheme | The http scheme to use | https | |
|
87
|
+
| host | The host of the authorization server | nil | |
|
88
|
+
| port | The port for the authorization server | 443 | |
|
89
|
+
| authorization_endpoint | The authorize endpoint on the authorization server | /authorize | yes |
|
90
|
+
| token_endpoint | The token endpoint on the authorization server | /token | yes |
|
91
|
+
| userinfo_endpoint | The user info endpoint on the authorization server | /userinfo | yes |
|
92
|
+
| jwks_uri | The jwks_uri on the authorization server | /jwk | yes |
|
93
|
+
| end_session_endpoint | The url to call to log the user out at the authorization server | nil | yes |
|
94
|
+
|
95
|
+
### Additional Configuration Notes
|
44
96
|
* `name` is arbitrary, I recommend using the name of your provider. The name
|
45
97
|
configuration exists because you could be using multiple OpenID Connect
|
46
98
|
providers in a single app.
|
@@ -48,11 +100,9 @@ Configuration details:
|
|
48
100
|
**NOTE**: if you use this gem with Devise you should use `:openid_connect` name,
|
49
101
|
or Devise would route to 'users/auth/:provider' rather than 'users/auth/openid_connect'
|
50
102
|
|
51
|
-
*
|
52
|
-
|
53
|
-
|
54
|
-
server side web apps anyway and are designed more for native/mobile apps.
|
55
|
-
* If you want to pass `state` paramete by yourself. You can set Proc Object.
|
103
|
+
* `response_type` tells the authorization server which grant type the application wants to use,
|
104
|
+
currently, only `:code` (Authorization Code grant) and `:id_token` (Implicit grant) are valid.
|
105
|
+
* If you want to pass `state` paramete by yourself. You can set Proc Object.
|
56
106
|
e.g. `state: Proc.new { SecureRandom.hex(32) }`
|
57
107
|
* `nonce` is optional. If don't want to pass "nonce" parameter to provider, You should specify
|
58
108
|
`false` to `send_nonce` option. (default true)
|
@@ -60,8 +110,8 @@ Configuration details:
|
|
60
110
|
`:client_auth_method` option, automatically set `:basic`.
|
61
111
|
* Use "OpenID Connect Discovery", You should specify `true` to `discovery` option. (default false)
|
62
112
|
* In "OpenID Connect Discovery", generally provider should have Webfinger endpoint.
|
63
|
-
If provider does not have Webfinger endpoint, You can specify "Issuer" to option.
|
64
|
-
e.g. `issuer: "https://myprovider.com"`
|
113
|
+
If provider does not have Webfinger endpoint, You can specify "Issuer" to option.
|
114
|
+
e.g. `issuer: "https://myprovider.com"`
|
65
115
|
It means to get configuration from "https://myprovider.com/.well-known/openid-configuration".
|
66
116
|
* The uid is by default using the `sub` value from the `user_info` response,
|
67
117
|
which in some applications is not the expected value. To avoid such limitations, the uid label can be
|
@@ -69,6 +119,10 @@ Configuration details:
|
|
69
119
|
that appears in the `user_info` details.
|
70
120
|
* The `issuer` property should exactly match the provider's issuer link.
|
71
121
|
* The `response_mode` option is optional and specifies how the result of the authorization request is formatted.
|
122
|
+
* Some OpenID Connect providers require the `scope` attribute in requests to the token endpoint, even if
|
123
|
+
this is not in the protocol specifications. In those cases, the `send_scope_to_token_endpoint`
|
124
|
+
property can be used to add the attribute to the token request. Initial value is `true`, which means that the
|
125
|
+
scope attribute is included by default.
|
72
126
|
|
73
127
|
For the full low down on OpenID Connect, please check out
|
74
128
|
[the spec](http://openid.net/specs/openid-connect-core-1_0.html).
|
@@ -14,6 +14,11 @@ module OmniAuth
|
|
14
14
|
include OmniAuth::Strategy
|
15
15
|
extend Forwardable
|
16
16
|
|
17
|
+
RESPONSE_TYPE_EXCEPTIONS = {
|
18
|
+
'id_token' => { exception_class: OmniAuth::OpenIDConnect::MissingIdTokenError, key: :missing_id_token }.freeze,
|
19
|
+
'code' => { exception_class: OmniAuth::OpenIDConnect::MissingCodeError, key: :missing_code }.freeze,
|
20
|
+
}.freeze
|
21
|
+
|
17
22
|
def_delegator :request, :params
|
18
23
|
|
19
24
|
option :name, 'openid_connect'
|
@@ -35,7 +40,7 @@ module OmniAuth
|
|
35
40
|
option :client_jwk_signing_key
|
36
41
|
option :client_x509_signing_key
|
37
42
|
option :scope, [:openid]
|
38
|
-
option :response_type, 'code'
|
43
|
+
option :response_type, 'code' # ['code', 'id_token']
|
39
44
|
option :state
|
40
45
|
option :response_mode # [:query, :fragment, :form_post, :web_message]
|
41
46
|
option :display, nil # [:page, :popup, :touch, :wap]
|
@@ -49,13 +54,12 @@ module OmniAuth
|
|
49
54
|
option :send_scope_to_token_endpoint, true
|
50
55
|
option :client_auth_method
|
51
56
|
option :post_logout_redirect_uri
|
57
|
+
option :extra_authorize_params, {}
|
58
|
+
option :allow_authorize_params, []
|
52
59
|
option :uid_field, 'sub'
|
53
60
|
|
54
61
|
def uid
|
55
|
-
user_info.
|
56
|
-
rescue NoMethodError
|
57
|
-
log :warn, "User sub:#{user_info.sub} missing info field: #{options.uid_field}"
|
58
|
-
user_info.sub
|
62
|
+
user_info.raw_attributes[options.uid_field.to_sym] || user_info.sub
|
59
63
|
end
|
60
64
|
|
61
65
|
info do
|
@@ -105,26 +109,26 @@ module OmniAuth
|
|
105
109
|
error_description = params['error_description'] || params['error_reason']
|
106
110
|
invalid_state = params['state'].to_s.empty? || params['state'] != stored_state
|
107
111
|
|
108
|
-
raise CallbackError
|
109
|
-
|
110
|
-
raise CallbackError, 'Invalid state parameter' if invalid_state
|
112
|
+
raise CallbackError, error: params['error'], reason: error_description, uri: params['error_uri'] if error
|
113
|
+
raise CallbackError, error: :csrf_detected, reason: "Invalid 'state' parameter" if invalid_state
|
111
114
|
|
112
|
-
return
|
115
|
+
return unless valid_response_type?
|
113
116
|
|
114
117
|
options.issuer = issuer if options.issuer.nil? || options.issuer.empty?
|
115
118
|
|
116
|
-
|
117
|
-
.verify! issuer: options.issuer,
|
118
|
-
client_id: client_options.identifier,
|
119
|
-
nonce: stored_nonce
|
120
|
-
|
119
|
+
verify_id_token!(params['id_token']) if configured_response_type == 'id_token'
|
121
120
|
discover!
|
122
121
|
client.redirect_uri = redirect_uri
|
122
|
+
|
123
|
+
return id_token_callback_phase if configured_response_type == 'id_token'
|
124
|
+
|
123
125
|
client.authorization_code = authorization_code
|
124
126
|
access_token
|
125
127
|
super
|
126
|
-
rescue CallbackError
|
127
|
-
fail!(
|
128
|
+
rescue CallbackError => e
|
129
|
+
fail!(e.error, e)
|
130
|
+
rescue ::Rack::OAuth2::Client::Error => e
|
131
|
+
fail!(e.response[:error], e)
|
128
132
|
rescue ::Timeout::Error, ::Errno::ETIMEDOUT => e
|
129
133
|
fail!(:timeout, e)
|
130
134
|
rescue ::SocketError => e
|
@@ -165,14 +169,22 @@ module OmniAuth
|
|
165
169
|
prompt: options.prompt,
|
166
170
|
nonce: (new_nonce if options.send_nonce),
|
167
171
|
hd: options.hd,
|
172
|
+
acr_values: options.acr_values,
|
168
173
|
}
|
174
|
+
|
175
|
+
opts.merge!(options.extra_authorize_params) unless options.extra_authorize_params.empty?
|
176
|
+
|
177
|
+
options.allow_authorize_params.each do |key|
|
178
|
+
opts[key] = request.params[key.to_s] unless opts.key?(key)
|
179
|
+
end
|
180
|
+
|
169
181
|
client.authorization_uri(opts.reject { |_k, v| v.nil? })
|
170
182
|
end
|
171
183
|
|
172
184
|
def public_key
|
173
185
|
return config.jwks if options.discovery
|
174
186
|
|
175
|
-
key_or_secret
|
187
|
+
key_or_secret || config.jwks
|
176
188
|
end
|
177
189
|
|
178
190
|
private
|
@@ -194,7 +206,15 @@ module OmniAuth
|
|
194
206
|
end
|
195
207
|
|
196
208
|
def user_info
|
197
|
-
@user_info
|
209
|
+
return @user_info if @user_info
|
210
|
+
|
211
|
+
if access_token.id_token
|
212
|
+
decoded = decode_id_token(access_token.id_token).raw_attributes
|
213
|
+
|
214
|
+
@user_info = ::OpenIDConnect::ResponseObject::UserInfo.new access_token.userinfo!.raw_attributes.merge(decoded)
|
215
|
+
else
|
216
|
+
@user_info = access_token.userinfo!
|
217
|
+
end
|
198
218
|
end
|
199
219
|
|
200
220
|
def access_token
|
@@ -204,6 +224,10 @@ module OmniAuth
|
|
204
224
|
scope: (options.scope if options.send_scope_to_token_endpoint),
|
205
225
|
client_auth_method: options.client_auth_method
|
206
226
|
)
|
227
|
+
|
228
|
+
verify_id_token!(@access_token.id_token) if configured_response_type == 'code'
|
229
|
+
|
230
|
+
@access_token
|
207
231
|
end
|
208
232
|
|
209
233
|
def decode_id_token(id_token)
|
@@ -237,6 +261,12 @@ module OmniAuth
|
|
237
261
|
session.delete('omniauth.nonce')
|
238
262
|
end
|
239
263
|
|
264
|
+
def script_name
|
265
|
+
return '' if @env.nil?
|
266
|
+
|
267
|
+
super
|
268
|
+
end
|
269
|
+
|
240
270
|
def session
|
241
271
|
return {} if @env.nil?
|
242
272
|
|
@@ -294,13 +324,46 @@ module OmniAuth
|
|
294
324
|
@logout_path_pattern ||= %r{\A#{Regexp.quote(request_path)}(/logout)}
|
295
325
|
end
|
296
326
|
|
327
|
+
def id_token_callback_phase
|
328
|
+
user_data = decode_id_token(params['id_token']).raw_attributes
|
329
|
+
env['omniauth.auth'] = AuthHash.new(
|
330
|
+
provider: name,
|
331
|
+
uid: user_data['sub'],
|
332
|
+
info: { name: user_data['name'], email: user_data['email'] },
|
333
|
+
extra: { raw_info: user_data }
|
334
|
+
)
|
335
|
+
call_app!
|
336
|
+
end
|
337
|
+
|
338
|
+
def valid_response_type?
|
339
|
+
return true if params.key?(configured_response_type)
|
340
|
+
|
341
|
+
error_attrs = RESPONSE_TYPE_EXCEPTIONS[configured_response_type]
|
342
|
+
fail!(error_attrs[:key], error_attrs[:exception_class].new(params['error']))
|
343
|
+
|
344
|
+
false
|
345
|
+
end
|
346
|
+
|
347
|
+
def configured_response_type
|
348
|
+
@configured_response_type ||= options.response_type.to_s
|
349
|
+
end
|
350
|
+
|
351
|
+
def verify_id_token!(id_token)
|
352
|
+
return unless id_token
|
353
|
+
|
354
|
+
decode_id_token(id_token).verify!(issuer: options.issuer,
|
355
|
+
client_id: client_options.identifier,
|
356
|
+
nonce: stored_nonce)
|
357
|
+
end
|
358
|
+
|
297
359
|
class CallbackError < StandardError
|
298
360
|
attr_accessor :error, :error_reason, :error_uri
|
299
361
|
|
300
|
-
def initialize(
|
301
|
-
|
302
|
-
self.
|
303
|
-
self.
|
362
|
+
def initialize(data)
|
363
|
+
super
|
364
|
+
self.error = data[:error]
|
365
|
+
self.error_reason = data[:reason]
|
366
|
+
self.error_uri = data[:uri]
|
304
367
|
end
|
305
368
|
|
306
369
|
def message
|
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.email = ['jjbohn@gmail.com', 'm0n9oose@gmail.com']
|
12
12
|
spec.summary = 'OpenID Connect Strategy for OmniAuth'
|
13
13
|
spec.description = 'OpenID Connect Strategy for OmniAuth.'
|
14
|
-
spec.homepage = 'https://github.com/
|
14
|
+
spec.homepage = 'https://github.com/m0n9oose/omniauth_openid_connect'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0")
|
@@ -19,17 +19,25 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
|
+
spec.metadata = {
|
23
|
+
'bug_tracker_uri' => 'https://github.com/m0n9oose/omniauth_openid_connect/issues',
|
24
|
+
'changelog_uri' => 'https://github.com/m0n9oose/omniauth_openid_connect/releases',
|
25
|
+
'documentation_uri' => "https://github.com/m0n9oose/omniauth_openid_connect/tree/v#{spec.version}#readme",
|
26
|
+
'source_code_uri' => "https://github.com/m0n9oose/omniauth_openid_connect/tree/v#{spec.version}",
|
27
|
+
'rubygems_mfa_required' => 'true',
|
28
|
+
}
|
29
|
+
|
22
30
|
spec.add_dependency 'addressable', '~> 2.5'
|
23
|
-
spec.add_dependency 'omniauth', '
|
31
|
+
spec.add_dependency 'omniauth', '>= 1.9', '< 3'
|
24
32
|
spec.add_dependency 'openid_connect', '~> 1.1'
|
25
33
|
spec.add_development_dependency 'coveralls', '~> 0.8'
|
26
|
-
spec.add_development_dependency 'faker', '~>
|
34
|
+
spec.add_development_dependency 'faker', '~> 2.0'
|
27
35
|
spec.add_development_dependency 'guard', '~> 2.14'
|
28
36
|
spec.add_development_dependency 'guard-bundler', '~> 2.2'
|
29
37
|
spec.add_development_dependency 'guard-minitest', '~> 2.4'
|
30
38
|
spec.add_development_dependency 'minitest', '~> 5.1'
|
31
39
|
spec.add_development_dependency 'mocha', '~> 1.7'
|
32
40
|
spec.add_development_dependency 'rake', '~> 12.0'
|
33
|
-
spec.add_development_dependency 'rubocop', '~>
|
41
|
+
spec.add_development_dependency 'rubocop', '~> 1.12'
|
34
42
|
spec.add_development_dependency 'simplecov', '~> 0.12'
|
35
43
|
end
|
@@ -36,6 +36,7 @@ module OmniAuth
|
|
36
36
|
::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
|
37
37
|
|
38
38
|
request.stubs(:path_info).returns('/auth/openid_connect/logout')
|
39
|
+
request.stubs(:path).returns('/auth/openid_connect/logout')
|
39
40
|
|
40
41
|
strategy.expects(:redirect).with(regexp_matches(expected_redirect))
|
41
42
|
strategy.other_phase
|
@@ -60,6 +61,7 @@ module OmniAuth
|
|
60
61
|
::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
|
61
62
|
|
62
63
|
request.stubs(:path_info).returns('/auth/openid_connect/logout')
|
64
|
+
request.stubs(:path).returns('/auth/openid_connect/logout')
|
63
65
|
|
64
66
|
strategy.expects(:redirect).with(expected_redirect)
|
65
67
|
strategy.other_phase
|
@@ -69,7 +71,7 @@ module OmniAuth
|
|
69
71
|
strategy.options.issuer = 'example.com'
|
70
72
|
strategy.options.client_options.host = 'example.com'
|
71
73
|
|
72
|
-
request.stubs(:
|
74
|
+
request.stubs(:path).returns('/auth/openid_connect/logout')
|
73
75
|
|
74
76
|
strategy.expects(:call_app!)
|
75
77
|
strategy.other_phase
|
@@ -123,6 +125,46 @@ module OmniAuth
|
|
123
125
|
strategy.request_phase
|
124
126
|
end
|
125
127
|
|
128
|
+
def test_request_phase_with_response_mode_symbol
|
129
|
+
expected_redirect = /^https:\/\/example\.com\/authorize\?client_id=1234&nonce=\w{32}&response_mode=form_post&response_type=id_token&scope=openid&state=\w{32}$/
|
130
|
+
strategy.options.issuer = 'example.com'
|
131
|
+
strategy.options.response_mode = 'form_post'
|
132
|
+
strategy.options.response_type = :id_token
|
133
|
+
strategy.options.client_options.host = 'example.com'
|
134
|
+
|
135
|
+
strategy.expects(:redirect).with(regexp_matches(expected_redirect))
|
136
|
+
strategy.request_phase
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_option_acr_values
|
140
|
+
strategy.options.client_options[:host] = 'foobar.com'
|
141
|
+
|
142
|
+
assert(!(strategy.authorize_uri =~ /acr_values=/), 'URI must not contain acr_values')
|
143
|
+
|
144
|
+
strategy.options.acr_values = 'urn:some:acr:values:value'
|
145
|
+
assert(strategy.authorize_uri =~ /acr_values=/, 'URI must contain acr_values')
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_option_custom_attributes
|
149
|
+
strategy.options.client_options[:host] = 'foobar.com'
|
150
|
+
strategy.options.extra_authorize_params = {resource: 'xyz'}
|
151
|
+
|
152
|
+
assert(strategy.authorize_uri =~ /resource=xyz/, 'URI must contain custom params')
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_request_phase_with_allowed_params
|
156
|
+
strategy.options.issuer = 'example.com'
|
157
|
+
strategy.options.allow_authorize_params = [:name, :logo, :resource]
|
158
|
+
strategy.options.extra_authorize_params = {resource: 'xyz'}
|
159
|
+
strategy.options.client_options.host = 'example.com'
|
160
|
+
request.stubs(:params).returns('name' => 'example', 'logo' => 'example_logo', 'resource' => 'abc', 'not_allowed' => 'filter_me')
|
161
|
+
|
162
|
+
assert(strategy.authorize_uri =~ /resource=xyz/, 'URI must contain fixed param resource')
|
163
|
+
assert(strategy.authorize_uri =~ /name=example/, 'URI must contain dynamic param name')
|
164
|
+
assert(strategy.authorize_uri =~ /logo=example_logo/, 'URI must contain dynamic param logo')
|
165
|
+
refute(strategy.authorize_uri =~ /not_allowed=filter_me/, 'URI must filter not allowed param')
|
166
|
+
end
|
167
|
+
|
126
168
|
def test_uid
|
127
169
|
assert_equal user_info.sub, strategy.uid
|
128
170
|
|
@@ -138,17 +180,45 @@ module OmniAuth
|
|
138
180
|
state = SecureRandom.hex(16)
|
139
181
|
nonce = SecureRandom.hex(16)
|
140
182
|
request.stubs(:params).returns('code' => code, 'state' => state)
|
141
|
-
request.stubs(:
|
183
|
+
request.stubs(:path).returns('')
|
142
184
|
|
143
185
|
strategy.options.issuer = 'example.com'
|
144
186
|
strategy.options.client_signing_alg = :RS256
|
145
187
|
strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
|
188
|
+
strategy.options.response_type = 'code'
|
189
|
+
|
190
|
+
strategy.unstub(:user_info)
|
191
|
+
access_token = stub('OpenIDConnect::AccessToken')
|
192
|
+
access_token.stubs(:access_token)
|
193
|
+
access_token.stubs(:refresh_token)
|
194
|
+
access_token.stubs(:expires_in)
|
195
|
+
access_token.stubs(:scope)
|
196
|
+
access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
|
197
|
+
client.expects(:access_token!).at_least_once.returns(access_token)
|
198
|
+
access_token.expects(:userinfo!).returns(user_info)
|
146
199
|
|
147
200
|
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
|
201
|
+
id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
|
148
202
|
id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
|
149
|
-
::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
|
150
203
|
id_token.expects(:verify!)
|
151
204
|
|
205
|
+
strategy.expects(:decode_id_token).twice.with(access_token.id_token).returns(id_token)
|
206
|
+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
207
|
+
strategy.callback_phase
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_callback_phase_with_id_token
|
211
|
+
code = SecureRandom.hex(16)
|
212
|
+
state = SecureRandom.hex(16)
|
213
|
+
nonce = SecureRandom.hex(16)
|
214
|
+
request.stubs(:params).returns('id_token' => code, 'state' => state)
|
215
|
+
request.stubs(:path).returns('')
|
216
|
+
|
217
|
+
strategy.options.issuer = 'example.com'
|
218
|
+
strategy.options.client_signing_alg = :RS256
|
219
|
+
strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
|
220
|
+
strategy.options.response_type = 'id_token'
|
221
|
+
|
152
222
|
strategy.unstub(:user_info)
|
153
223
|
access_token = stub('OpenIDConnect::AccessToken')
|
154
224
|
access_token.stubs(:access_token)
|
@@ -156,8 +226,12 @@ module OmniAuth
|
|
156
226
|
access_token.stubs(:expires_in)
|
157
227
|
access_token.stubs(:scope)
|
158
228
|
access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
|
159
|
-
|
160
|
-
|
229
|
+
|
230
|
+
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
|
231
|
+
id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
|
232
|
+
id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
|
233
|
+
::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
|
234
|
+
id_token.expects(:verify!)
|
161
235
|
|
162
236
|
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
163
237
|
strategy.callback_phase
|
@@ -170,7 +244,7 @@ module OmniAuth
|
|
170
244
|
jwks = JSON::JWK::Set.new(JSON.parse(File.read('test/fixtures/jwks.json'))['keys'])
|
171
245
|
|
172
246
|
request.stubs(:params).returns('code' => code, 'state' => state)
|
173
|
-
request.stubs(:
|
247
|
+
request.stubs(:path).returns('')
|
174
248
|
|
175
249
|
strategy.options.client_options.host = 'example.com'
|
176
250
|
strategy.options.discovery = true
|
@@ -189,6 +263,7 @@ module OmniAuth
|
|
189
263
|
::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
|
190
264
|
|
191
265
|
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
|
266
|
+
id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
|
192
267
|
id_token.stubs(:verify!).with(issuer: 'https://example.com/', client_id: @identifier, nonce: nonce).returns(true)
|
193
268
|
::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
|
194
269
|
|
@@ -210,7 +285,7 @@ module OmniAuth
|
|
210
285
|
state = SecureRandom.hex(16)
|
211
286
|
nonce = SecureRandom.hex(16)
|
212
287
|
request.stubs(:params).returns('error' => 'invalid_request')
|
213
|
-
request.stubs(:
|
288
|
+
request.stubs(:path).returns('')
|
214
289
|
|
215
290
|
strategy.call!({'rack.session' => {'omniauth.state' => state, 'omniauth.nonce' => nonce}})
|
216
291
|
strategy.expects(:fail!)
|
@@ -222,7 +297,7 @@ module OmniAuth
|
|
222
297
|
state = SecureRandom.hex(16)
|
223
298
|
nonce = SecureRandom.hex(16)
|
224
299
|
request.stubs(:params).returns('code' => code, 'state' => 'foobar')
|
225
|
-
request.stubs(:
|
300
|
+
request.stubs(:path).returns('')
|
226
301
|
|
227
302
|
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
228
303
|
strategy.expects(:fail!)
|
@@ -233,11 +308,37 @@ module OmniAuth
|
|
233
308
|
state = SecureRandom.hex(16)
|
234
309
|
nonce = SecureRandom.hex(16)
|
235
310
|
request.stubs(:params).returns('state' => state)
|
236
|
-
request.stubs(:
|
311
|
+
request.stubs(:path).returns('')
|
237
312
|
|
238
313
|
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
239
314
|
|
240
|
-
strategy.expects(:fail!)
|
315
|
+
strategy.expects(:fail!).with(:missing_code, is_a(OmniAuth::OpenIDConnect::MissingCodeError))
|
316
|
+
strategy.callback_phase
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_callback_phase_without_id_token
|
320
|
+
state = SecureRandom.hex(16)
|
321
|
+
nonce = SecureRandom.hex(16)
|
322
|
+
request.stubs(:params).returns('state' => state)
|
323
|
+
request.stubs(:path).returns('')
|
324
|
+
strategy.options.response_type = 'id_token'
|
325
|
+
|
326
|
+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
327
|
+
|
328
|
+
strategy.expects(:fail!).with(:missing_id_token, is_a(OmniAuth::OpenIDConnect::MissingIdTokenError))
|
329
|
+
strategy.callback_phase
|
330
|
+
end
|
331
|
+
|
332
|
+
def test_callback_phase_without_id_token_symbol
|
333
|
+
state = SecureRandom.hex(16)
|
334
|
+
nonce = SecureRandom.hex(16)
|
335
|
+
request.stubs(:params).returns('state' => state)
|
336
|
+
request.stubs(:path).returns('')
|
337
|
+
strategy.options.response_type = :id_token
|
338
|
+
|
339
|
+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
340
|
+
|
341
|
+
strategy.expects(:fail!).with(:missing_id_token, is_a(OmniAuth::OpenIDConnect::MissingIdTokenError))
|
241
342
|
strategy.callback_phase
|
242
343
|
end
|
243
344
|
|
@@ -246,7 +347,7 @@ module OmniAuth
|
|
246
347
|
state = SecureRandom.hex(16)
|
247
348
|
nonce = SecureRandom.hex(16)
|
248
349
|
request.stubs(:params).returns('code' => code, 'state' => state)
|
249
|
-
request.stubs(:
|
350
|
+
request.stubs(:path).returns('')
|
250
351
|
|
251
352
|
strategy.options.issuer = 'example.com'
|
252
353
|
|
@@ -266,7 +367,7 @@ module OmniAuth
|
|
266
367
|
state = SecureRandom.hex(16)
|
267
368
|
nonce = SecureRandom.hex(16)
|
268
369
|
request.stubs(:params).returns('code' => code, 'state' => state)
|
269
|
-
request.stubs(:
|
370
|
+
request.stubs(:path).returns('')
|
270
371
|
|
271
372
|
strategy.options.issuer = 'example.com'
|
272
373
|
|
@@ -286,7 +387,7 @@ module OmniAuth
|
|
286
387
|
state = SecureRandom.hex(16)
|
287
388
|
nonce = SecureRandom.hex(16)
|
288
389
|
request.stubs(:params).returns('code' => code, 'state' => state)
|
289
|
-
request.stubs(:
|
390
|
+
request.stubs(:path).returns('')
|
290
391
|
|
291
392
|
strategy.options.issuer = 'example.com'
|
292
393
|
|
@@ -306,7 +407,7 @@ module OmniAuth
|
|
306
407
|
state = SecureRandom.hex(16)
|
307
408
|
nonce = SecureRandom.hex(16)
|
308
409
|
request.stubs(:params).returns('code' => code, 'state' => state)
|
309
|
-
request.stubs(:
|
410
|
+
request.stubs(:path).returns('')
|
310
411
|
|
311
412
|
strategy.options.issuer = 'example.com'
|
312
413
|
|
@@ -407,7 +508,7 @@ module OmniAuth
|
|
407
508
|
# the following should fail because the wrong state is passed to the callback
|
408
509
|
code = SecureRandom.hex(16)
|
409
510
|
request.stubs(:params).returns('code' => code, 'state' => 43)
|
410
|
-
request.stubs(:
|
511
|
+
request.stubs(:path).returns('')
|
411
512
|
|
412
513
|
strategy.call!('rack.session' => session)
|
413
514
|
strategy.expects(:fail!)
|
@@ -416,7 +517,8 @@ module OmniAuth
|
|
416
517
|
|
417
518
|
def test_dynamic_state
|
418
519
|
# Stub request parameters
|
419
|
-
|
520
|
+
request.stubs(:path).returns('')
|
521
|
+
strategy.call!('rack.session' => { }, QUERY_STRING: { state: 'abc', client_id: '123' } )
|
420
522
|
|
421
523
|
strategy.options.state = lambda { |env|
|
422
524
|
# Get params from request, e.g. CGI.parse(env['QUERY_STRING'])
|
@@ -448,7 +550,7 @@ module OmniAuth
|
|
448
550
|
}.to_json
|
449
551
|
success = Struct.new(:status, :body).new(200, json_response)
|
450
552
|
|
451
|
-
request.stubs(:
|
553
|
+
request.stubs(:path).returns('')
|
452
554
|
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
453
555
|
|
454
556
|
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
|
@@ -492,6 +594,42 @@ module OmniAuth
|
|
492
594
|
strategy.options.client_signing_alg = :HS256
|
493
595
|
assert_equal strategy.options.client_options.secret, strategy.public_key
|
494
596
|
end
|
597
|
+
|
598
|
+
def test_id_token_auth_hash
|
599
|
+
state = SecureRandom.hex(16)
|
600
|
+
nonce = SecureRandom.hex(16)
|
601
|
+
strategy.options.response_type = 'id_token'
|
602
|
+
strategy.options.issuer = 'example.com'
|
603
|
+
|
604
|
+
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
|
605
|
+
id_token.stubs(:verify!).returns(true)
|
606
|
+
id_token.stubs(:raw_attributes, :to_h).returns(
|
607
|
+
{
|
608
|
+
"iss": "http://server.example.com",
|
609
|
+
"sub": "248289761001",
|
610
|
+
"aud": "s6BhdRkqt3",
|
611
|
+
"nonce": "n-0S6_WzA2Mj",
|
612
|
+
"exp": 1311281970,
|
613
|
+
"iat": 1311280970,
|
614
|
+
}
|
615
|
+
)
|
616
|
+
|
617
|
+
request.stubs(:params).returns('state' => state, 'nounce' => nonce, 'id_token' => id_token)
|
618
|
+
request.stubs(:path).returns('')
|
619
|
+
|
620
|
+
strategy.stubs(:decode_id_token).returns(id_token)
|
621
|
+
strategy.stubs(:stored_state).returns(state)
|
622
|
+
|
623
|
+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
624
|
+
strategy.callback_phase
|
625
|
+
|
626
|
+
auth_hash = strategy.send(:env)['omniauth.auth']
|
627
|
+
assert auth_hash.key?('provider')
|
628
|
+
assert auth_hash.key?('uid')
|
629
|
+
assert auth_hash.key?('info')
|
630
|
+
assert auth_hash.key?('extra')
|
631
|
+
assert auth_hash['extra'].key?('raw_info')
|
632
|
+
end
|
495
633
|
end
|
496
634
|
end
|
497
635
|
end
|
data/test/strategy_test_case.rb
CHANGED
@@ -37,6 +37,7 @@ class StrategyTestCase < MiniTest::Test
|
|
37
37
|
request.stubs(:env).returns({})
|
38
38
|
request.stubs(:scheme).returns({})
|
39
39
|
request.stubs(:ssl?).returns(false)
|
40
|
+
request.stubs(:path).returns('')
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
@@ -46,6 +47,7 @@ class StrategyTestCase < MiniTest::Test
|
|
46
47
|
strategy.options.client_options.secret = @secret
|
47
48
|
strategy.stubs(:request).returns(request)
|
48
49
|
strategy.stubs(:user_info).returns(user_info)
|
50
|
+
strategy.stubs(:script_name).returns('')
|
49
51
|
end
|
50
52
|
end
|
51
53
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniauth_openid_connect
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Bohn
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-02-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: addressable
|
@@ -29,16 +29,22 @@ dependencies:
|
|
29
29
|
name: omniauth
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '1.9'
|
35
|
+
- - "<"
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3'
|
35
38
|
type: :runtime
|
36
39
|
prerelease: false
|
37
40
|
version_requirements: !ruby/object:Gem::Requirement
|
38
41
|
requirements:
|
39
|
-
- - "
|
42
|
+
- - ">="
|
40
43
|
- !ruby/object:Gem::Version
|
41
44
|
version: '1.9'
|
45
|
+
- - "<"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3'
|
42
48
|
- !ruby/object:Gem::Dependency
|
43
49
|
name: openid_connect
|
44
50
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,14 +79,14 @@ dependencies:
|
|
73
79
|
requirements:
|
74
80
|
- - "~>"
|
75
81
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
82
|
+
version: '2.0'
|
77
83
|
type: :development
|
78
84
|
prerelease: false
|
79
85
|
version_requirements: !ruby/object:Gem::Requirement
|
80
86
|
requirements:
|
81
87
|
- - "~>"
|
82
88
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
89
|
+
version: '2.0'
|
84
90
|
- !ruby/object:Gem::Dependency
|
85
91
|
name: guard
|
86
92
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,14 +177,14 @@ dependencies:
|
|
171
177
|
requirements:
|
172
178
|
- - "~>"
|
173
179
|
- !ruby/object:Gem::Version
|
174
|
-
version: '
|
180
|
+
version: '1.12'
|
175
181
|
type: :development
|
176
182
|
prerelease: false
|
177
183
|
version_requirements: !ruby/object:Gem::Requirement
|
178
184
|
requirements:
|
179
185
|
- - "~>"
|
180
186
|
- !ruby/object:Gem::Version
|
181
|
-
version: '
|
187
|
+
version: '1.12'
|
182
188
|
- !ruby/object:Gem::Dependency
|
183
189
|
name: simplecov
|
184
190
|
requirement: !ruby/object:Gem::Requirement
|
@@ -201,9 +207,12 @@ executables: []
|
|
201
207
|
extensions: []
|
202
208
|
extra_rdoc_files: []
|
203
209
|
files:
|
210
|
+
- ".github/config/rubocop_linter_action.yml"
|
211
|
+
- ".github/stale.yml"
|
212
|
+
- ".github/workflows/main.yml"
|
213
|
+
- ".github/workflows/rubocop.yml"
|
204
214
|
- ".gitignore"
|
205
215
|
- ".rubocop.yml"
|
206
|
-
- ".travis.yml"
|
207
216
|
- CHANGELOG.md
|
208
217
|
- Gemfile
|
209
218
|
- Guardfile
|
@@ -222,10 +231,15 @@ files:
|
|
222
231
|
- test/lib/omniauth/strategies/openid_connect_test.rb
|
223
232
|
- test/strategy_test_case.rb
|
224
233
|
- test/test_helper.rb
|
225
|
-
homepage: https://github.com/
|
234
|
+
homepage: https://github.com/m0n9oose/omniauth_openid_connect
|
226
235
|
licenses:
|
227
236
|
- MIT
|
228
|
-
metadata:
|
237
|
+
metadata:
|
238
|
+
bug_tracker_uri: https://github.com/m0n9oose/omniauth_openid_connect/issues
|
239
|
+
changelog_uri: https://github.com/m0n9oose/omniauth_openid_connect/releases
|
240
|
+
documentation_uri: https://github.com/m0n9oose/omniauth_openid_connect/tree/v0.4.0#readme
|
241
|
+
source_code_uri: https://github.com/m0n9oose/omniauth_openid_connect/tree/v0.4.0
|
242
|
+
rubygems_mfa_required: 'true'
|
229
243
|
post_install_message:
|
230
244
|
rdoc_options: []
|
231
245
|
require_paths:
|
@@ -241,7 +255,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
241
255
|
- !ruby/object:Gem::Version
|
242
256
|
version: '0'
|
243
257
|
requirements: []
|
244
|
-
rubygems_version: 3.
|
258
|
+
rubygems_version: 3.3.5
|
245
259
|
signing_key:
|
246
260
|
specification_version: 4
|
247
261
|
summary: OpenID Connect Strategy for OmniAuth
|