onc_certification_g10_test_kit 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/inferno/terminology/expected_manifest.yml +242 -29
- data/lib/inferno/terminology/fhir_package_manager.rb +27 -0
- data/lib/inferno/terminology/loader.rb +22 -1
- data/lib/inferno/terminology/tasks/create_value_set_validators.rb +1 -1
- data/lib/inferno/terminology/tasks/download_fhir_terminology.rb +5 -0
- data/lib/inferno/terminology/value_set.rb +51 -5
- data/lib/onc_certification_g10_test_kit/base_token_refresh_group.rb +5 -4
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export_stu1.rb +5 -0
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export_stu2.rb +2 -0
- data/lib/onc_certification_g10_test_kit/bulk_data_group_export_validation.rb +206 -28
- data/lib/onc_certification_g10_test_kit/bulk_export_validation_tester.rb +25 -40
- data/lib/onc_certification_g10_test_kit/encounter_context_test.rb +30 -0
- data/lib/onc_certification_g10_test_kit/feature.rb +5 -8
- data/lib/onc_certification_g10_test_kit/limited_scope_grant_test.rb +18 -5
- data/lib/onc_certification_g10_test_kit/profile_selector.rb +175 -0
- data/lib/onc_certification_g10_test_kit/restricted_resource_type_access_group.rb +54 -4
- data/lib/onc_certification_g10_test_kit/single_patient_us_core_5_api_group.rb +93 -0
- data/lib/onc_certification_g10_test_kit/smart_app_launch_invalid_aud_group.rb +50 -5
- data/lib/onc_certification_g10_test_kit/smart_ehr_patient_launch_group.rb +94 -0
- data/lib/onc_certification_g10_test_kit/smart_ehr_patient_launch_group_stu2.rb +94 -0
- data/lib/onc_certification_g10_test_kit/smart_ehr_practitioner_app_group.rb +197 -13
- data/lib/onc_certification_g10_test_kit/smart_invalid_pkce_group.rb +310 -0
- data/lib/onc_certification_g10_test_kit/smart_invalid_token_group_stu2.rb +211 -0
- data/lib/onc_certification_g10_test_kit/smart_limited_app_group.rb +135 -9
- data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group.rb +16 -4
- data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group_stu2.rb +130 -0
- data/lib/onc_certification_g10_test_kit/smart_scopes_test.rb +134 -67
- data/lib/onc_certification_g10_test_kit/smart_standalone_patient_app_group.rb +166 -11
- data/lib/onc_certification_g10_test_kit/unrestricted_resource_type_access_group.rb +119 -135
- data/lib/onc_certification_g10_test_kit/version.rb +1 -1
- data/lib/onc_certification_g10_test_kit/visual_inspection_and_attestations_group.rb +19 -0
- data/lib/onc_certification_g10_test_kit/well_known_capabilities_test.rb +7 -1
- data/lib/onc_certification_g10_test_kit.rb +115 -74
- metadata +19 -11
- data/lib/onc_certification_g10_test_kit/profile_guesser.rb +0 -72
@@ -2,6 +2,7 @@ require_relative 'base_token_refresh_group'
|
|
2
2
|
require_relative 'smart_scopes_test'
|
3
3
|
require_relative 'unauthorized_access_test'
|
4
4
|
require_relative 'well_known_capabilities_test'
|
5
|
+
require_relative 'encounter_context_test'
|
5
6
|
|
6
7
|
module ONCCertificationG10TestKit
|
7
8
|
class SmartEHRPractitionerAppGroup < Inferno::TestGroup
|
@@ -14,29 +15,35 @@ module ONCCertificationG10TestKit
|
|
14
15
|
* Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
|
15
16
|
|
16
17
|
Enter in the appropriate scope to enable user-level access to all relevant
|
17
|
-
resources.
|
18
|
-
|
19
|
-
|
18
|
+
resources. If using SMART v2, v2-style scopes must be used. In addition,
|
19
|
+
support for the OpenID Connect (openid fhirUser), refresh tokens
|
20
|
+
(offline_access), and EHR context (launch) are required. This test expects
|
21
|
+
that the EHR will launch the application with a patient context.
|
20
22
|
|
21
23
|
After submit is pressed, Inferno will wait for the system under test to launch
|
22
24
|
the application.
|
23
25
|
)
|
24
26
|
|
25
27
|
description %(
|
26
|
-
Demonstrate the ability to perform an EHR launch to a
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
Connect is decoded and validated.
|
28
|
+
Demonstrate the ability to perform an EHR launch to a SMART on FHIR
|
29
|
+
confidential client with patient context, refresh token, OpenID Connect
|
30
|
+
(OIDC) identity token, and (SMART v2 only) use the POST HTTP method for
|
31
|
+
code exchange. After launch, a simple Patient resource read is performed
|
32
|
+
on the patient in context. The access token is then refreshed, and the
|
33
|
+
Patient resource is read using the new access token to ensure that the
|
34
|
+
refresh was successful. Finally, the authentication information provided
|
35
|
+
by OpenID Connect is decoded and validated.
|
35
36
|
|
36
37
|
For EHRs that use Internet Explorer 11 to display embedded apps,
|
37
38
|
please review [instructions on how to complete the EHR Practitioner App
|
38
39
|
test](https://github.com/onc-healthit/onc-certification-g10-test-kit/wiki/Completing-EHR-Practitioner-App-test-in-Internet-Explorer/).
|
39
40
|
|
41
|
+
* [SMART on FHIR
|
42
|
+
(STU1)](http://www.hl7.org/fhir/smart-app-launch/1.0.0/)
|
43
|
+
* [SMART on FHIR
|
44
|
+
(STU2)](http://hl7.org/fhir/smart-app-launch/STU2)
|
45
|
+
* [OpenID Connect
|
46
|
+
(OIDC)](https://openid.net/specs/openid-connect-core-1_0.html)
|
40
47
|
)
|
41
48
|
id :g10_smart_ehr_practitioner_app
|
42
49
|
run_as_group
|
@@ -52,6 +59,8 @@ module ONCCertificationG10TestKit
|
|
52
59
|
input_order :url, :ehr_client_id, :ehr_client_secret
|
53
60
|
|
54
61
|
group from: :smart_discovery do
|
62
|
+
required_suite_options(smart_app_launch_version: 'smart_app_launch_1')
|
63
|
+
|
55
64
|
test from: 'g10_smart_well_known_capabilities',
|
56
65
|
config: {
|
57
66
|
options: {
|
@@ -69,7 +78,32 @@ module ONCCertificationG10TestKit
|
|
69
78
|
}
|
70
79
|
end
|
71
80
|
|
81
|
+
group from: :smart_discovery_stu2 do
|
82
|
+
required_suite_options(smart_app_launch_version: 'smart_app_launch_2')
|
83
|
+
|
84
|
+
test from: 'g10_smart_well_known_capabilities',
|
85
|
+
config: {
|
86
|
+
options: {
|
87
|
+
required_capabilities: [
|
88
|
+
'launch-ehr',
|
89
|
+
'client-confidential-symmetric',
|
90
|
+
'sso-openid-connect',
|
91
|
+
'context-banner',
|
92
|
+
'context-style',
|
93
|
+
'context-ehr-patient',
|
94
|
+
'permission-offline',
|
95
|
+
'permission-user',
|
96
|
+
'authorize-post',
|
97
|
+
'permission-v1',
|
98
|
+
'permission-v2'
|
99
|
+
]
|
100
|
+
}
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
72
104
|
group from: :smart_ehr_launch do
|
105
|
+
required_suite_options(smart_app_launch_version: 'smart_app_launch_1')
|
106
|
+
|
73
107
|
title 'EHR Launch With Practitioner Scope'
|
74
108
|
input :client_secret,
|
75
109
|
name: :ehr_client_secret,
|
@@ -101,6 +135,9 @@ module ONCCertificationG10TestKit
|
|
101
135
|
inputs: {
|
102
136
|
requested_scopes: { name: :ehr_requested_scopes },
|
103
137
|
received_scopes: { name: :ehr_received_scopes }
|
138
|
+
},
|
139
|
+
options: {
|
140
|
+
scope_version: :v1
|
104
141
|
}
|
105
142
|
)
|
106
143
|
|
@@ -108,7 +145,7 @@ module ONCCertificationG10TestKit
|
|
108
145
|
['openid', 'fhirUser', 'launch', 'offline_access']
|
109
146
|
end
|
110
147
|
|
111
|
-
def
|
148
|
+
def required_scope_type
|
112
149
|
'user'
|
113
150
|
end
|
114
151
|
end
|
@@ -128,6 +165,151 @@ module ONCCertificationG10TestKit
|
|
128
165
|
}
|
129
166
|
}
|
130
167
|
|
168
|
+
test from: :g10_encounter_context,
|
169
|
+
config: {
|
170
|
+
inputs: {
|
171
|
+
encounter_id: { name: :ehr_encounter_id },
|
172
|
+
access_token: { name: :ehr_access_token }
|
173
|
+
}
|
174
|
+
},
|
175
|
+
required_suite_options: { us_core_version: 'us_core_5' }
|
176
|
+
|
177
|
+
test do
|
178
|
+
title 'Launch context contains smart_style_url which links to valid JSON'
|
179
|
+
description %(
|
180
|
+
In order to mimic the style of the SMART host more closely, SMART apps
|
181
|
+
can check for the existence of this launch context parameter and
|
182
|
+
download the JSON file referenced by the URL value.
|
183
|
+
)
|
184
|
+
id :Test13
|
185
|
+
uses_request :token
|
186
|
+
|
187
|
+
run do
|
188
|
+
skip_if request.status != 200, 'No token response received'
|
189
|
+
assert_valid_json response[:body]
|
190
|
+
|
191
|
+
body = JSON.parse(response[:body])
|
192
|
+
|
193
|
+
assert body['smart_style_url'].present?,
|
194
|
+
'Token response did not contain `smart_style_url`'
|
195
|
+
|
196
|
+
get(body['smart_style_url'])
|
197
|
+
|
198
|
+
assert_response_status(200)
|
199
|
+
assert_valid_json(response[:body])
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
test do
|
204
|
+
title 'Launch context contains need_patient_banner'
|
205
|
+
description %(
|
206
|
+
`need_patient_banner` is a boolean value indicating whether the app
|
207
|
+
was launched in a UX context where a patient banner is required (when
|
208
|
+
true) or not required (when false).
|
209
|
+
)
|
210
|
+
id :Test14
|
211
|
+
uses_request :token
|
212
|
+
|
213
|
+
run do
|
214
|
+
skip_if request.status != 200, 'No token response received'
|
215
|
+
assert_valid_json response[:body]
|
216
|
+
|
217
|
+
body = JSON.parse(response[:body])
|
218
|
+
|
219
|
+
assert body.key?('need_patient_banner'),
|
220
|
+
'Token response did not contain `need_patient_banner`'
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
group from: :smart_ehr_launch_stu2,
|
226
|
+
config: {
|
227
|
+
inputs: {
|
228
|
+
use_pkce: {
|
229
|
+
default: 'true',
|
230
|
+
locked: true
|
231
|
+
},
|
232
|
+
pkce_code_challenge_method: {
|
233
|
+
locked: true
|
234
|
+
},
|
235
|
+
authorization_method: {
|
236
|
+
name: :ehr_authorization_method,
|
237
|
+
default: 'post',
|
238
|
+
locked: true
|
239
|
+
}
|
240
|
+
}
|
241
|
+
} do
|
242
|
+
required_suite_options(smart_app_launch_version: 'smart_app_launch_2')
|
243
|
+
|
244
|
+
title 'EHR Launch With Practitioner Scope'
|
245
|
+
input :client_secret,
|
246
|
+
name: :ehr_client_secret,
|
247
|
+
title: 'EHR Launch Client Secret',
|
248
|
+
description: 'Client Secret provided during registration of Inferno as an EHR launch application',
|
249
|
+
optional: false
|
250
|
+
|
251
|
+
config(
|
252
|
+
inputs: {
|
253
|
+
requested_scopes: {
|
254
|
+
default: %(
|
255
|
+
launch openid fhirUser offline_access user/Medication.rs
|
256
|
+
user/AllergyIntolerance.rs user/CarePlan.rs user/CareTeam.rs
|
257
|
+
user/Condition.rs user/Device.rs user/DiagnosticReport.rs
|
258
|
+
user/DocumentReference.rs user/Encounter.rs user/Goal.rs
|
259
|
+
user/Immunization.rs user/Location.rs user/MedicationRequest.rs
|
260
|
+
user/Observation.rs user/Organization.rs user/Patient.rs
|
261
|
+
user/Practitioner.rs user/Procedure.rs user/Provenance.rs
|
262
|
+
user/PractitionerRole.rs
|
263
|
+
).gsub(/\s{2,}/, ' ').strip
|
264
|
+
}
|
265
|
+
}
|
266
|
+
)
|
267
|
+
|
268
|
+
test from: :g10_smart_scopes do
|
269
|
+
title 'User-level access with OpenID Connect and Refresh Token scopes used.'
|
270
|
+
config(
|
271
|
+
inputs: {
|
272
|
+
requested_scopes: { name: :ehr_requested_scopes },
|
273
|
+
received_scopes: { name: :ehr_received_scopes }
|
274
|
+
},
|
275
|
+
options: {
|
276
|
+
scope_version: :v2
|
277
|
+
}
|
278
|
+
)
|
279
|
+
|
280
|
+
def required_scopes
|
281
|
+
['openid', 'fhirUser', 'launch', 'offline_access']
|
282
|
+
end
|
283
|
+
|
284
|
+
def required_scope_type
|
285
|
+
'user'
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
test from: :g10_unauthorized_access,
|
290
|
+
config: {
|
291
|
+
inputs: {
|
292
|
+
patient_id: { name: :ehr_patient_id }
|
293
|
+
}
|
294
|
+
}
|
295
|
+
|
296
|
+
test from: :g10_patient_context,
|
297
|
+
config: {
|
298
|
+
inputs: {
|
299
|
+
patient_id: { name: :ehr_patient_id },
|
300
|
+
access_token: { name: :ehr_access_token }
|
301
|
+
}
|
302
|
+
}
|
303
|
+
|
304
|
+
test from: :g10_encounter_context,
|
305
|
+
config: {
|
306
|
+
inputs: {
|
307
|
+
encounter_id: { name: :ehr_encounter_id },
|
308
|
+
access_token: { name: :ehr_access_token }
|
309
|
+
}
|
310
|
+
},
|
311
|
+
required_suite_options: { us_core_version: 'us_core_5' }
|
312
|
+
|
131
313
|
test do
|
132
314
|
title 'Launch context contains smart_style_url which links to valid JSON'
|
133
315
|
description %(
|
@@ -136,6 +318,7 @@ module ONCCertificationG10TestKit
|
|
136
318
|
download the JSON file referenced by the URL value.
|
137
319
|
)
|
138
320
|
uses_request :token
|
321
|
+
id :g10_smart_style_url
|
139
322
|
|
140
323
|
run do
|
141
324
|
skip_if request.status != 200, 'No token response received'
|
@@ -161,6 +344,7 @@ module ONCCertificationG10TestKit
|
|
161
344
|
true) or not required (when false).
|
162
345
|
)
|
163
346
|
uses_request :token
|
347
|
+
id :g10_smart_need_patient_banner
|
164
348
|
|
165
349
|
run do
|
166
350
|
skip_if request.status != 200, 'No token response received'
|
@@ -0,0 +1,310 @@
|
|
1
|
+
module ONCCertificationG10TestKit
|
2
|
+
class InvalidSMARTTokenRequestTest < Inferno::Test
|
3
|
+
title 'OAuth token exchange fails when supplied invalid code_verifier'
|
4
|
+
description %(
|
5
|
+
If the request failed verification or is invalid, the authorization
|
6
|
+
server returns an error response.
|
7
|
+
)
|
8
|
+
uses_request :redirect
|
9
|
+
id :invalid_pkce_request
|
10
|
+
|
11
|
+
input :code, :use_pkce, :pkce_code_verifier, :client_id, :client_secret, :smart_token_url
|
12
|
+
|
13
|
+
def modify_oauth_params(oauth_params)
|
14
|
+
oauth_params
|
15
|
+
end
|
16
|
+
|
17
|
+
run do
|
18
|
+
skip_if request.query_parameters['error'].present?, 'Error during authorization request'
|
19
|
+
|
20
|
+
oauth2_params = {
|
21
|
+
grant_type: 'authorization_code',
|
22
|
+
code: code,
|
23
|
+
redirect_uri: config.options[:redirect_uri]
|
24
|
+
}
|
25
|
+
|
26
|
+
oauth2_headers = { 'Content-Type' => 'application/x-www-form-urlencoded' }
|
27
|
+
|
28
|
+
if client_secret.present?
|
29
|
+
client_credentials = "#{client_id}:#{client_secret}"
|
30
|
+
oauth2_headers['Authorization'] = "Basic #{Base64.strict_encode64(client_credentials)}"
|
31
|
+
else
|
32
|
+
oauth2_params[:client_id] = client_id
|
33
|
+
end
|
34
|
+
|
35
|
+
modify_oauth_params(oauth2_params)
|
36
|
+
|
37
|
+
post(smart_token_url, body: oauth2_params, name: :token, headers: oauth2_headers)
|
38
|
+
|
39
|
+
assert_response_status([400, 401])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class SMARTInvalidPKCEGroup < Inferno::TestGroup
|
44
|
+
title 'SMART App Launch Error: Invalid PKCE Code Verifier'
|
45
|
+
short_title 'SMART Invalid PKCE Code Verifier'
|
46
|
+
input_instructions %(
|
47
|
+
Register Inferno as a standalone application using the following information:
|
48
|
+
|
49
|
+
* Redirect URI: `#{SMARTAppLaunch::AppRedirectTest.config.options[:redirect_uri]}`
|
50
|
+
)
|
51
|
+
description %(
|
52
|
+
# Background
|
53
|
+
|
54
|
+
The #{title} Group verifies that a SMART Launch Sequence, specifically the
|
55
|
+
[Standalone
|
56
|
+
Launch](http://hl7.org/fhir/smart-app-launch/STU2/app-launch.html#launch-app-standalone-launch)
|
57
|
+
Sequence, verifies that servers properly support PKCE. It does this by ensuring the launch fails
|
58
|
+
in the case where the client sends an invalid PKCE `code_verifier`.
|
59
|
+
|
60
|
+
This group performs four launches with various forms of an invalid `code_verifier`
|
61
|
+
(e.g. incorrect `code_verifier`, blank `code_identifier`) and verifies that these do
|
62
|
+
not result in a successful launch. Testers can expect to be prompted four times
|
63
|
+
that a redirect will occur in this test.
|
64
|
+
|
65
|
+
This test is not included as part of the Single Patient App group
|
66
|
+
because there is no way for a client to infer that PKCE is supported on the server
|
67
|
+
properly without performing extra launches. Attempting to verify this within the
|
68
|
+
same launch cannot be done because some servers may not accept an authorization code
|
69
|
+
after it has been used unsuccessfully in this manner.
|
70
|
+
)
|
71
|
+
id :g10_smart_invalid_pkce_code_verifier_group
|
72
|
+
run_as_group
|
73
|
+
|
74
|
+
input :use_pkce,
|
75
|
+
title: 'Proof Key for Code Exchange (PKCE)',
|
76
|
+
type: 'radio',
|
77
|
+
default: 'true',
|
78
|
+
locked: true,
|
79
|
+
options: {
|
80
|
+
list_options: [
|
81
|
+
{
|
82
|
+
label: 'Enabled',
|
83
|
+
value: 'true'
|
84
|
+
},
|
85
|
+
{
|
86
|
+
label: 'Disabled',
|
87
|
+
value: 'false'
|
88
|
+
}
|
89
|
+
]
|
90
|
+
}
|
91
|
+
input :pkce_code_challenge_method,
|
92
|
+
optional: true,
|
93
|
+
title: 'PKCE Code Challenge Method',
|
94
|
+
type: 'radio',
|
95
|
+
default: 'S256',
|
96
|
+
locked: true,
|
97
|
+
options: {
|
98
|
+
list_options: [
|
99
|
+
{
|
100
|
+
label: 'S256',
|
101
|
+
value: 'S256'
|
102
|
+
},
|
103
|
+
{
|
104
|
+
label: 'Plain',
|
105
|
+
value: 'plain'
|
106
|
+
}
|
107
|
+
]
|
108
|
+
}
|
109
|
+
|
110
|
+
input_order :url,
|
111
|
+
:standalone_client_id,
|
112
|
+
:standalone_client_secret,
|
113
|
+
:standalone_requested_scopes,
|
114
|
+
:use_pkce,
|
115
|
+
:pkce_code_challenge_method,
|
116
|
+
:smart_authorization_url,
|
117
|
+
:smart_token_url
|
118
|
+
|
119
|
+
config(
|
120
|
+
inputs: {
|
121
|
+
client_id: {
|
122
|
+
name: :standalone_client_id,
|
123
|
+
title: 'Standalone Client ID',
|
124
|
+
description: 'Client ID provided during registration of Inferno as a standalone application'
|
125
|
+
},
|
126
|
+
client_secret: {
|
127
|
+
name: :standalone_client_secret,
|
128
|
+
title: 'Standalone Client Secret',
|
129
|
+
description: 'Client Secret provided during registration of Inferno as a standalone application'
|
130
|
+
},
|
131
|
+
requested_scopes: {
|
132
|
+
name: :standalone_requested_scopes,
|
133
|
+
title: 'Standalone Scope',
|
134
|
+
description: 'OAuth 2.0 scope provided by system to enable all required functionality',
|
135
|
+
type: 'textarea',
|
136
|
+
default: %(
|
137
|
+
launch/patient openid fhirUser offline_access
|
138
|
+
patient/Medication.read patient/AllergyIntolerance.read
|
139
|
+
patient/CarePlan.read patient/CareTeam.read patient/Condition.read
|
140
|
+
patient/Device.read patient/DiagnosticReport.read
|
141
|
+
patient/DocumentReference.read patient/Encounter.read
|
142
|
+
patient/Goal.read patient/Immunization.read patient/Location.read
|
143
|
+
patient/MedicationRequest.read patient/Observation.read
|
144
|
+
patient/Organization.read patient/Patient.read
|
145
|
+
patient/Practitioner.read patient/Procedure.read
|
146
|
+
patient/Provenance.read patient/PractitionerRole.read
|
147
|
+
).gsub(/\s{2,}/, ' ').strip
|
148
|
+
},
|
149
|
+
url: {
|
150
|
+
title: 'Standalone FHIR Endpoint',
|
151
|
+
description: 'URL of the FHIR endpoint used by standalone applications'
|
152
|
+
},
|
153
|
+
code: {
|
154
|
+
name: :invalid_token_code
|
155
|
+
},
|
156
|
+
state: {
|
157
|
+
name: :invalid_token_state
|
158
|
+
},
|
159
|
+
smart_authorization_url: {
|
160
|
+
title: 'OAuth 2.0 Authorize Endpoint',
|
161
|
+
description: 'OAuth 2.0 Authorize Endpoint provided during the patient standalone launch'
|
162
|
+
},
|
163
|
+
smart_token_url: {
|
164
|
+
title: 'OAuth 2.0 Token Endpoint',
|
165
|
+
description: 'OAuth 2.0 Token Endpoint provided during the patient standalone launch'
|
166
|
+
},
|
167
|
+
pkce_code_challenge: {
|
168
|
+
name: :invalid_token_pkce_code_challenge
|
169
|
+
},
|
170
|
+
pkce_code_verifier: {
|
171
|
+
name: :invalid_token_pkce_code_verifier
|
172
|
+
}
|
173
|
+
},
|
174
|
+
outputs: {
|
175
|
+
code: { name: :invalid_token_code },
|
176
|
+
state: { name: :invalid_token_state },
|
177
|
+
expires_in: { name: :invalid_token_expires_in },
|
178
|
+
pkce_code_challenge: { name: :invalid_token_pkce_code_challenge },
|
179
|
+
pkce_code_verifier: { name: :invalid_token_pkce_code_verifier }
|
180
|
+
},
|
181
|
+
requests: {
|
182
|
+
redirect: { name: :invalid_token_redirect },
|
183
|
+
token: { name: :invalid_token_token }
|
184
|
+
}
|
185
|
+
)
|
186
|
+
|
187
|
+
test from: :smart_app_redirect_stu2,
|
188
|
+
id: :smart_no_code_verifier_redirect,
|
189
|
+
config: {
|
190
|
+
options: {
|
191
|
+
redirect_message_proc: lambda do |auth_url|
|
192
|
+
%(
|
193
|
+
### Invalid PKCE code_verifier 1/4
|
194
|
+
|
195
|
+
This launch does not provide a `code_verifier` and verifies the
|
196
|
+
server does not issue an access token.
|
197
|
+
|
198
|
+
[Follow this link to authorize with the SMART
|
199
|
+
server](#{auth_url}).
|
200
|
+
|
201
|
+
Tests will resume once Inferno receives a request at
|
202
|
+
`#{config.options[:redirect_uri]}` with a state of `#{state}`.
|
203
|
+
)
|
204
|
+
end
|
205
|
+
}
|
206
|
+
}
|
207
|
+
test from: :smart_code_received,
|
208
|
+
id: :smart_no_code_verifier_code_received
|
209
|
+
test from: :invalid_pkce_request do
|
210
|
+
title 'OAuth token exchange fails when no code_verifier is given'
|
211
|
+
id :smart_no_verifier_token_request
|
212
|
+
end
|
213
|
+
|
214
|
+
test from: :smart_app_redirect_stu2,
|
215
|
+
id: :smart_blank_code_verifier_redirect,
|
216
|
+
config: {
|
217
|
+
options: {
|
218
|
+
redirect_message_proc: lambda do |auth_url|
|
219
|
+
%(
|
220
|
+
### Invalid PKCE code_verifier 2/4
|
221
|
+
|
222
|
+
This launch provides a blank `code_verifier` and verifies the
|
223
|
+
server does not issue an access token.
|
224
|
+
|
225
|
+
[Follow this link to authorize with the SMART
|
226
|
+
server](#{auth_url}).
|
227
|
+
|
228
|
+
Tests will resume once Inferno receives a request at
|
229
|
+
`#{config.options[:redirect_uri]}` with a state of `#{state}`.
|
230
|
+
)
|
231
|
+
end
|
232
|
+
}
|
233
|
+
}
|
234
|
+
test from: :smart_code_received,
|
235
|
+
id: :smart_blank_code_verifier_code_received
|
236
|
+
test from: :invalid_pkce_request do
|
237
|
+
title 'OAuth token exchange fails when code_verifier is blank'
|
238
|
+
id :smart_blank_verifier_token_request
|
239
|
+
|
240
|
+
def modify_oauth_params(oauth_params)
|
241
|
+
oauth_params.merge!(code_verifier: '')
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
test from: :smart_app_redirect_stu2,
|
246
|
+
id: :smart_bad_code_verifier_redirect,
|
247
|
+
config: {
|
248
|
+
options: {
|
249
|
+
redirect_message_proc: lambda do |auth_url|
|
250
|
+
%(
|
251
|
+
### Invalid PKCE code_verifier 3/4
|
252
|
+
|
253
|
+
This launch provides an invalid `code_verifier` and verifies the
|
254
|
+
server does not issue an access token.
|
255
|
+
|
256
|
+
[Follow this link to authorize with the SMART
|
257
|
+
server](#{auth_url}).
|
258
|
+
|
259
|
+
Tests will resume once Inferno receives a request at
|
260
|
+
`#{config.options[:redirect_uri]}` with a state of `#{state}`.
|
261
|
+
)
|
262
|
+
end
|
263
|
+
}
|
264
|
+
}
|
265
|
+
test from: :smart_code_received,
|
266
|
+
id: :smart_bad_code_verifier_code_received
|
267
|
+
test from: :invalid_pkce_request do
|
268
|
+
title 'OAuth token exchange fails when code_verifier is incorrect'
|
269
|
+
id :smart_bad_code_verifier_token_request
|
270
|
+
|
271
|
+
def modify_oauth_params(oauth_params)
|
272
|
+
oauth_params.merge!(code_verifier: "#{SecureRandom.uuid}-#{SecureRandom.uuid}")
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
test from: :smart_app_redirect_stu2,
|
277
|
+
id: :smart_plain_code_verifier_redirect,
|
278
|
+
config: {
|
279
|
+
options: {
|
280
|
+
redirect_message_proc: lambda do |auth_url|
|
281
|
+
%(
|
282
|
+
### Invalid PKCE code_verifier 4/4
|
283
|
+
|
284
|
+
This launch provides a `plain` `code_verifier` instead of one
|
285
|
+
encoded with `S256` and verifies the server does not issue an
|
286
|
+
access token.
|
287
|
+
|
288
|
+
[Follow this link to authorize with the SMART
|
289
|
+
server](#{auth_url}).
|
290
|
+
|
291
|
+
Tests will resume once Inferno receives a request at
|
292
|
+
`#{config.options[:redirect_uri]}` with a state of `#{state}`.
|
293
|
+
)
|
294
|
+
end
|
295
|
+
}
|
296
|
+
}
|
297
|
+
test from: :smart_code_received,
|
298
|
+
id: :smart_plain_code_verifier_code_received
|
299
|
+
test from: :invalid_pkce_request do
|
300
|
+
title 'OAuth token exchange fails when code_verifier matches code_challenge'
|
301
|
+
id :smart_plain_code_verifier_token_request
|
302
|
+
|
303
|
+
input :pkce_code_challenge
|
304
|
+
|
305
|
+
def modify_oauth_params(oauth_params)
|
306
|
+
oauth_params.merge!(code_verifier: pkce_code_challenge)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|