onc_certification_g10_test_kit 2.3.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|