smart_app_launch_test_kit 1.0.1 → 1.0.2
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/execution_scripts/README.md +16 -0
- data/execution_scripts/client_vs_server/access_data_and_continue_client.rb +37 -0
- data/execution_scripts/client_vs_server/smart_v22_backend_services_with_commands.yaml +69 -0
- data/execution_scripts/client_vs_server/smart_v22_backend_services_with_commands_client_expected.json +1 -0
- data/execution_scripts/client_vs_server/smart_v22_backend_services_with_commands_server_expected.json +478 -0
- data/execution_scripts/client_vs_server/smart_v22_backend_services_with_commands_server_no_tls_expected.json +479 -0
- data/execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands.yaml +122 -0
- data/execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands_client_expected.json +1 -0
- data/execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands_client_no_tls_expected.json +1 -0
- data/execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands_server_expected.json +1 -0
- data/execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands_server_no_tls_expected.json +1 -0
- data/execution_scripts/client_vs_server/smart_v22_public_with_commands.yaml +123 -0
- data/execution_scripts/client_vs_server/smart_v22_public_with_commands_client_expected.json +1 -0
- data/execution_scripts/client_vs_server/smart_v22_public_with_commands_client_no_tls_expected.json +1 -0
- data/execution_scripts/client_vs_server/smart_v22_public_with_commands_server_expected.json +1 -0
- data/execution_scripts/client_vs_server/smart_v22_public_with_commands_server_no_tls_expected.json +1 -0
- data/execution_scripts/client_vs_server/visit_and_wait_to_return_to_inferno.rb +17 -0
- data/execution_scripts/reference_server/base_ref_server_authorize.rb +24 -0
- data/execution_scripts/reference_server/base_ref_server_ehr_launch.rb +24 -0
- data/execution_scripts/reference_server/ref_server_authorize_85_all_scopes.rb +3 -0
- data/execution_scripts/reference_server/ref_server_authorize_launched_all_scopes.rb +3 -0
- data/execution_scripts/reference_server/ref_server_ehr_launch_85.rb +3 -0
- data/execution_scripts/reference_server/smart_v1_vs_reference_server_with_commands.yaml +60 -0
- data/execution_scripts/reference_server/smart_v1_vs_reference_server_with_commands_expected.json +1 -0
- data/execution_scripts/reference_server/smart_v22_vs_reference_server_with_commands.yaml +93 -0
- data/execution_scripts/reference_server/smart_v22_vs_reference_server_with_commands_expected.json +1 -0
- data/execution_scripts/reference_server/smart_v22_vs_reference_server_with_commands_same_host_expected.json +4166 -0
- data/execution_scripts/reference_server/smart_v2_vs_reference_server_with_commands.yaml +81 -0
- data/execution_scripts/reference_server/smart_v2_vs_reference_server_with_commands_expected.json +1 -0
- data/lib/smart_app_launch/app_launch_test.rb +4 -0
- data/lib/smart_app_launch/app_redirect_test.rb +2 -1
- data/lib/smart_app_launch/client_suite/access_alca_interaction_test.rb +5 -1
- data/lib/smart_app_launch/client_suite/access_alcs_interaction_test.rb +5 -1
- data/lib/smart_app_launch/client_suite/access_alp_interaction_test.rb +6 -2
- data/lib/smart_app_launch/client_suite/access_bsca_interaction_test.rb +4 -1
- data/lib/smart_app_launch/client_suite/authentication_verification.rb +1 -1
- data/lib/smart_app_launch/client_suite/client_descriptions.rb +4 -3
- data/lib/smart_app_launch/cors_metadata_request_test.rb +11 -4
- data/lib/smart_app_launch/cors_openid_fhir_user_claim_test.rb +8 -4
- data/lib/smart_app_launch/cors_token_exchange_test.rb +8 -4
- data/lib/smart_app_launch/cors_well_known_endpoint_test.rb +8 -4
- data/lib/smart_app_launch/version.rb +2 -2
- metadata +34 -6
|
@@ -14,7 +14,7 @@ module SMARTAppLaunch
|
|
|
14
14
|
|
|
15
15
|
input :url
|
|
16
16
|
input :smart_auth_info, type: :auth_info, options: { mode: 'auth' }
|
|
17
|
-
output :state, :pkce_code_challenge, :pkce_code_verifier
|
|
17
|
+
output :state, :pkce_code_challenge, :pkce_code_verifier, :authorization_url
|
|
18
18
|
receives_request :redirect
|
|
19
19
|
|
|
20
20
|
def default_redirect_uri
|
|
@@ -104,6 +104,7 @@ module SMARTAppLaunch
|
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
info("Inferno redirecting browser to #{authorization_url}.")
|
|
107
|
+
output(authorization_url:)
|
|
107
108
|
|
|
108
109
|
wait(
|
|
109
110
|
identifier: state,
|
|
@@ -52,6 +52,8 @@ module SMARTAppLaunch
|
|
|
52
52
|
description: INPUT_ECHOED_FHIR_RESPONSE_DESCRIPTION
|
|
53
53
|
|
|
54
54
|
output :launch_key
|
|
55
|
+
output :launch_urls
|
|
56
|
+
output :continuation_url
|
|
55
57
|
|
|
56
58
|
def client_suite_id
|
|
57
59
|
return config.options[:endpoint_suite_id] if config.options[:endpoint_suite_id].present?
|
|
@@ -69,11 +71,13 @@ module SMARTAppLaunch
|
|
|
69
71
|
)
|
|
70
72
|
end
|
|
71
73
|
|
|
74
|
+
continuation_url = "#{client_resume_pass_url}?token=#{client_id}"
|
|
75
|
+
output(continuation_url:)
|
|
72
76
|
wait(
|
|
73
77
|
identifier: client_id,
|
|
74
78
|
message: access_wait_dialog_app_launch_access_prefix(client_id, 'confidential asymmetric', client_fhir_base_url) +
|
|
75
79
|
access_wait_dialog_ehr_launch_instructions(smart_launch_urls, client_fhir_base_url) +
|
|
76
|
-
access_wait_dialog_access_response_and_continue_suffix(
|
|
80
|
+
access_wait_dialog_access_response_and_continue_suffix(continuation_url)
|
|
77
81
|
)
|
|
78
82
|
end
|
|
79
83
|
end
|
|
@@ -52,6 +52,8 @@ module SMARTAppLaunch
|
|
|
52
52
|
description: INPUT_ECHOED_FHIR_RESPONSE_DESCRIPTION
|
|
53
53
|
|
|
54
54
|
output :launch_key
|
|
55
|
+
output :launch_urls
|
|
56
|
+
output :continuation_url
|
|
55
57
|
|
|
56
58
|
def client_suite_id
|
|
57
59
|
return config.options[:endpoint_suite_id] if config.options[:endpoint_suite_id].present?
|
|
@@ -69,11 +71,13 @@ module SMARTAppLaunch
|
|
|
69
71
|
)
|
|
70
72
|
end
|
|
71
73
|
|
|
74
|
+
continuation_url = "#{client_resume_pass_url}?token=#{client_id}"
|
|
75
|
+
output(continuation_url:)
|
|
72
76
|
wait(
|
|
73
77
|
identifier: client_id,
|
|
74
78
|
message: access_wait_dialog_app_launch_access_prefix(client_id, 'confidential symmetric', client_fhir_base_url) +
|
|
75
79
|
access_wait_dialog_ehr_launch_instructions(smart_launch_urls, client_fhir_base_url) +
|
|
76
|
-
access_wait_dialog_access_response_and_continue_suffix(
|
|
80
|
+
access_wait_dialog_access_response_and_continue_suffix(continuation_url)
|
|
77
81
|
)
|
|
78
82
|
end
|
|
79
83
|
end
|
|
@@ -51,6 +51,8 @@ module SMARTAppLaunch
|
|
|
51
51
|
description: INPUT_ECHOED_FHIR_RESPONSE_DESCRIPTION
|
|
52
52
|
|
|
53
53
|
output :launch_key
|
|
54
|
+
output :launch_urls
|
|
55
|
+
output :continuation_url
|
|
54
56
|
|
|
55
57
|
def client_suite_id
|
|
56
58
|
return config.options[:endpoint_suite_id] if config.options[:endpoint_suite_id].present?
|
|
@@ -67,12 +69,14 @@ module SMARTAppLaunch
|
|
|
67
69
|
'Input **Launch Context** is not valid JSON and will be disregarded when responding to token requests'
|
|
68
70
|
)
|
|
69
71
|
end
|
|
70
|
-
|
|
72
|
+
|
|
73
|
+
continuation_url = "#{client_resume_pass_url}?token=#{client_id}"
|
|
74
|
+
output(continuation_url:)
|
|
71
75
|
wait(
|
|
72
76
|
identifier: client_id,
|
|
73
77
|
message: access_wait_dialog_app_launch_access_prefix(client_id, 'public', client_fhir_base_url) +
|
|
74
78
|
access_wait_dialog_ehr_launch_instructions(smart_launch_urls, client_fhir_base_url) +
|
|
75
|
-
access_wait_dialog_access_response_and_continue_suffix(
|
|
79
|
+
access_wait_dialog_access_response_and_continue_suffix(continuation_url)
|
|
76
80
|
)
|
|
77
81
|
end
|
|
78
82
|
end
|
|
@@ -31,6 +31,7 @@ module SMARTAppLaunch
|
|
|
31
31
|
type: 'textarea',
|
|
32
32
|
optional: true,
|
|
33
33
|
description: INPUT_ECHOED_FHIR_RESPONSE_DESCRIPTION
|
|
34
|
+
output :continuation_url
|
|
34
35
|
|
|
35
36
|
def client_suite_id
|
|
36
37
|
return config.options[:endpoint_suite_id] if config.options[:endpoint_suite_id].present?
|
|
@@ -39,10 +40,12 @@ module SMARTAppLaunch
|
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
run do
|
|
43
|
+
continuation_url = "#{client_resume_pass_url}?token=#{client_id}"
|
|
44
|
+
output(continuation_url:)
|
|
42
45
|
wait(
|
|
43
46
|
identifier: client_id,
|
|
44
47
|
message: access_wait_dialog_backend_services_access_prefix(client_id, client_fhir_base_url) +
|
|
45
|
-
access_wait_dialog_access_response_and_continue_suffix(
|
|
48
|
+
access_wait_dialog_access_response_and_continue_suffix(continuation_url)
|
|
46
49
|
)
|
|
47
50
|
end
|
|
48
51
|
end
|
|
@@ -34,7 +34,7 @@ module SMARTAppLaunch
|
|
|
34
34
|
return unless decoded_token.present?
|
|
35
35
|
|
|
36
36
|
check_jwt_header(decoded_token.header, request_num)
|
|
37
|
-
check_jwt_payload(decoded_token.
|
|
37
|
+
check_jwt_payload(decoded_token.unverified_payload, jti_list, request_num)
|
|
38
38
|
check_jwt_signature(decoded_token, request_num)
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -91,15 +91,16 @@ module SMARTAppLaunch
|
|
|
91
91
|
|
|
92
92
|
launch_query_string = Rack::Utils.build_query({ iss: fhir_base_url, launch: launch_key })
|
|
93
93
|
ehr_launch_locations = smart_launch_urls.split(',').map { |launch_url| "#{launch_url}?#{launch_query_string}" }
|
|
94
|
+
output(launch_urls: ehr_launch_locations.join(','))
|
|
95
|
+
|
|
94
96
|
ehr_launch_links_string = ehr_launch_locations.map { |url| "- [launch](#{url})" }.join("\n")
|
|
95
|
-
|
|
96
97
|
"\n\nOr open one of the following links in a new tab to perform an EHR launch:\n#{ehr_launch_links_string}\n\n"
|
|
97
98
|
else
|
|
98
99
|
''
|
|
99
100
|
end
|
|
100
101
|
end
|
|
101
102
|
|
|
102
|
-
def access_wait_dialog_access_response_and_continue_suffix(
|
|
103
|
+
def access_wait_dialog_access_response_and_continue_suffix(continuation_url)
|
|
103
104
|
<<~SUFFIX
|
|
104
105
|
Inferno will respond to requests with either:
|
|
105
106
|
- A resource from the Bundle in the **Available Resources** input if the request is a read matching
|
|
@@ -107,7 +108,7 @@ module SMARTAppLaunch
|
|
|
107
108
|
- Otherwise, the contents of the **Default FHIR Response** if provided.
|
|
108
109
|
- Otherwise, an OperationOutcome indicating nothing to echo.
|
|
109
110
|
|
|
110
|
-
[Click here](#{
|
|
111
|
+
[Click here](#{continuation_url}) once the client has made a data access request.
|
|
111
112
|
SUFFIX
|
|
112
113
|
end
|
|
113
114
|
end
|
|
@@ -33,10 +33,17 @@ module SMARTAppLaunch
|
|
|
33
33
|
|
|
34
34
|
assert_response_status(200)
|
|
35
35
|
inferno_origin = Inferno::Application['inferno_host']
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
|
|
37
|
+
if url.starts_with?(inferno_origin)
|
|
38
|
+
info 'No CORS headers required: Inferno and the target server are on the same host.'
|
|
39
|
+
else
|
|
40
|
+
cors_allow_origin = request.response_header('Access-Control-Allow-Origin')&.value
|
|
41
|
+
assert cors_allow_origin.present?, 'No `Access-Control-Allow-Origin` header received.'
|
|
42
|
+
assert cors_allow_origin == inferno_origin || cors_allow_origin == '*',
|
|
43
|
+
"`Access-Control-Allow-Origin` must be `#{inferno_origin}`, but received: `#{cors_allow_origin}`"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
40
47
|
end
|
|
41
48
|
end
|
|
42
49
|
end
|
|
@@ -41,10 +41,14 @@ module SMARTAppLaunch
|
|
|
41
41
|
assert_response_status(200)
|
|
42
42
|
|
|
43
43
|
inferno_origin = Inferno::Application['inferno_host']
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
if url.starts_with?(inferno_origin)
|
|
45
|
+
info 'No CORS headers required: Inferno and the target server are on the same host.'
|
|
46
|
+
else
|
|
47
|
+
cors_allow_origin = request.response_header('Access-Control-Allow-Origin')&.value
|
|
48
|
+
assert cors_allow_origin.present?, 'No `Access-Control-Allow-Origin` header received.'
|
|
49
|
+
assert cors_allow_origin == inferno_origin || cors_allow_origin == '*',
|
|
50
|
+
"`Access-Control-Allow-Origin` must be `#{inferno_origin}`, but received: `#{cors_allow_origin}`"
|
|
51
|
+
end
|
|
48
52
|
end
|
|
49
53
|
end
|
|
50
54
|
end
|
|
@@ -28,10 +28,14 @@ module SMARTAppLaunch
|
|
|
28
28
|
skip_if request.status != 200, 'Previous request was unsuccessful, cannot check for CORS support'
|
|
29
29
|
|
|
30
30
|
inferno_origin = Inferno::Application['inferno_host']
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
if request.url.starts_with?(inferno_origin)
|
|
32
|
+
info 'No CORS headers required: Inferno and the target server are on the same host.'
|
|
33
|
+
else
|
|
34
|
+
cors_header = request.response_header('Access-Control-Allow-Origin')&.value
|
|
35
|
+
|
|
36
|
+
assert cors_header == inferno_origin || cors_header == '*',
|
|
37
|
+
"Request must have `Access-Control-Allow-Origin` header containing `#{inferno_origin}`"
|
|
38
|
+
end
|
|
35
39
|
end
|
|
36
40
|
end
|
|
37
41
|
end
|
|
@@ -33,10 +33,14 @@ module SMARTAppLaunch
|
|
|
33
33
|
'Origin' => inferno_origin })
|
|
34
34
|
assert_response_status(200)
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
if request.url.starts_with?(inferno_origin)
|
|
37
|
+
info 'No CORS headers required: Inferno and the target server are on the same host.'
|
|
38
|
+
else
|
|
39
|
+
cors_allow_origin = request.response_header('Access-Control-Allow-Origin')&.value
|
|
40
|
+
assert cors_allow_origin.present?, 'No `Access-Control-Allow-Origin` header received.'
|
|
41
|
+
assert cors_allow_origin == inferno_origin || cors_allow_origin == '*',
|
|
42
|
+
"`Access-Control-Allow-Origin` must be `#{inferno_origin}`, but received: `#{cors_allow_origin}`"
|
|
43
|
+
end
|
|
40
44
|
end
|
|
41
45
|
end
|
|
42
46
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smart_app_launch_test_kit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Inferno Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: inferno_core
|
|
@@ -50,14 +50,14 @@ dependencies:
|
|
|
50
50
|
requirements:
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '2
|
|
53
|
+
version: '3.2'
|
|
54
54
|
type: :runtime
|
|
55
55
|
prerelease: false
|
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
|
58
58
|
- - "~>"
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '2
|
|
60
|
+
version: '3.2'
|
|
61
61
|
- !ruby/object:Gem::Dependency
|
|
62
62
|
name: tls_test_kit
|
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -165,7 +165,6 @@ dependencies:
|
|
|
165
165
|
description: Inferno Tests for the SMART Application Launch Framework Implementation
|
|
166
166
|
Guide
|
|
167
167
|
email:
|
|
168
|
-
- inferno@groups.mitre.org
|
|
169
168
|
executables: []
|
|
170
169
|
extensions: []
|
|
171
170
|
extra_rdoc_files: []
|
|
@@ -183,6 +182,35 @@ files:
|
|
|
183
182
|
- config/presets/smart_access_brands_example_2.json
|
|
184
183
|
- config/presets/smart_access_brands_example_3.json
|
|
185
184
|
- config/presets/smart_access_brands_example_4.json
|
|
185
|
+
- execution_scripts/README.md
|
|
186
|
+
- execution_scripts/client_vs_server/access_data_and_continue_client.rb
|
|
187
|
+
- execution_scripts/client_vs_server/smart_v22_backend_services_with_commands.yaml
|
|
188
|
+
- execution_scripts/client_vs_server/smart_v22_backend_services_with_commands_client_expected.json
|
|
189
|
+
- execution_scripts/client_vs_server/smart_v22_backend_services_with_commands_server_expected.json
|
|
190
|
+
- execution_scripts/client_vs_server/smart_v22_backend_services_with_commands_server_no_tls_expected.json
|
|
191
|
+
- execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands.yaml
|
|
192
|
+
- execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands_client_expected.json
|
|
193
|
+
- execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands_client_no_tls_expected.json
|
|
194
|
+
- execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands_server_expected.json
|
|
195
|
+
- execution_scripts/client_vs_server/smart_v22_confidential_symmetric_with_commands_server_no_tls_expected.json
|
|
196
|
+
- execution_scripts/client_vs_server/smart_v22_public_with_commands.yaml
|
|
197
|
+
- execution_scripts/client_vs_server/smart_v22_public_with_commands_client_expected.json
|
|
198
|
+
- execution_scripts/client_vs_server/smart_v22_public_with_commands_client_no_tls_expected.json
|
|
199
|
+
- execution_scripts/client_vs_server/smart_v22_public_with_commands_server_expected.json
|
|
200
|
+
- execution_scripts/client_vs_server/smart_v22_public_with_commands_server_no_tls_expected.json
|
|
201
|
+
- execution_scripts/client_vs_server/visit_and_wait_to_return_to_inferno.rb
|
|
202
|
+
- execution_scripts/reference_server/base_ref_server_authorize.rb
|
|
203
|
+
- execution_scripts/reference_server/base_ref_server_ehr_launch.rb
|
|
204
|
+
- execution_scripts/reference_server/ref_server_authorize_85_all_scopes.rb
|
|
205
|
+
- execution_scripts/reference_server/ref_server_authorize_launched_all_scopes.rb
|
|
206
|
+
- execution_scripts/reference_server/ref_server_ehr_launch_85.rb
|
|
207
|
+
- execution_scripts/reference_server/smart_v1_vs_reference_server_with_commands.yaml
|
|
208
|
+
- execution_scripts/reference_server/smart_v1_vs_reference_server_with_commands_expected.json
|
|
209
|
+
- execution_scripts/reference_server/smart_v22_vs_reference_server_with_commands.yaml
|
|
210
|
+
- execution_scripts/reference_server/smart_v22_vs_reference_server_with_commands_expected.json
|
|
211
|
+
- execution_scripts/reference_server/smart_v22_vs_reference_server_with_commands_same_host_expected.json
|
|
212
|
+
- execution_scripts/reference_server/smart_v2_vs_reference_server_with_commands.yaml
|
|
213
|
+
- execution_scripts/reference_server/smart_v2_vs_reference_server_with_commands_expected.json
|
|
186
214
|
- lib/smart_app_launch/app_launch_test.rb
|
|
187
215
|
- lib/smart_app_launch/app_redirect_test.rb
|
|
188
216
|
- lib/smart_app_launch/app_redirect_test_stu2.rb
|