smart_app_launch_test_kit 0.4.5 → 0.5.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/config/presets/inferno_reference_server_preset.json +103 -0
- data/config/presets/inferno_reference_server_stu2_2_preset.json +89 -0
- data/config/presets/inferno_reference_server_stu2_preset.json +89 -0
- data/config/presets/smart_access_brands.json.erb +13 -0
- data/config/presets/smart_access_brands_example_1.json +37 -0
- data/config/presets/smart_access_brands_example_2.json +37 -0
- data/config/presets/smart_access_brands_example_3.json +37 -0
- data/config/presets/smart_access_brands_example_4.json +37 -0
- data/lib/smart_app_launch/cors_metadata_request_test.rb +40 -0
- data/lib/smart_app_launch/cors_openid_fhir_user_claim_test.rb +48 -0
- data/lib/smart_app_launch/cors_token_exchange_test.rb +35 -0
- data/lib/smart_app_launch/cors_well_known_endpoint_test.rb +40 -0
- data/lib/smart_app_launch/discovery_stu2_2_group.rb +12 -0
- data/lib/smart_app_launch/ehr_launch_group_stu2_2.rb +14 -0
- data/lib/smart_app_launch/metadata.rb +75 -0
- data/lib/smart_app_launch/openid_connect_group_stu2_2.rb +40 -0
- data/lib/smart_app_launch/smart_access_brands_examples/smart_access_brands_example.json.erb +198 -0
- data/lib/smart_app_launch/smart_access_brands_suite.rb +4 -1
- data/lib/smart_app_launch/smart_stu1_suite.rb +7 -6
- data/lib/smart_app_launch/smart_stu2_2_suite.rb +10 -10
- data/lib/smart_app_launch/smart_stu2_suite.rb +11 -10
- data/lib/smart_app_launch/standalone_launch_group_stu2_2.rb +14 -0
- data/lib/smart_app_launch/token_exchange_stu2_2_test.rb +30 -0
- data/lib/smart_app_launch/token_exchange_test.rb +10 -14
- data/lib/smart_app_launch/token_introspection_access_token_group_stu2_2.rb +2 -4
- data/lib/smart_app_launch/token_introspection_group.rb +1 -2
- data/lib/smart_app_launch/token_introspection_group_stu2_2.rb +0 -21
- data/lib/smart_app_launch/token_introspection_request_group.rb +47 -36
- data/lib/smart_app_launch/token_refresh_test.rb +13 -9
- data/lib/smart_app_launch/version.rb +2 -1
- data/lib/smart_app_launch_test_kit.rb +1 -0
- metadata +26 -8
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require_relative 'version'
|
|
2
|
+
|
|
3
|
+
module SMARTAppLaunch
|
|
4
|
+
class Metadata < Inferno::TestKit
|
|
5
|
+
id :smart_app_launch_test_kit
|
|
6
|
+
title 'SMART App Launch Test Kit'
|
|
7
|
+
description <<~DESCRIPTION
|
|
8
|
+
The SMART App Launch Test Kit primarily validates the conformance of an
|
|
9
|
+
authorization server implementation to a specified version of the [SMART
|
|
10
|
+
Application Launch Framework Implementation
|
|
11
|
+
Guide](http://hl7.org/fhir/smart-app-launch/index.html). This Test Kit also
|
|
12
|
+
provides Brand Bundle Publisher testing for the User-access Brands and Endpoints
|
|
13
|
+
specification. This Test Kit supports following versions of the SMART App
|
|
14
|
+
Launch IG: [STU1](https://hl7.org/fhir/smart-app-launch/1.0.0/),
|
|
15
|
+
[STU2](http://hl7.org/fhir/smart-app-launch/STU2/), and
|
|
16
|
+
[STU2.2](http://hl7.org/fhir/smart-app-launch/STU2.2/).
|
|
17
|
+
<!-- break -->
|
|
18
|
+
|
|
19
|
+
This Test Kit is [open
|
|
20
|
+
source](https://github.com/inferno-framework/smart-app-launch-test-kit#license)
|
|
21
|
+
and freely available for use or adoption by the health IT community including
|
|
22
|
+
EHR vendors, health app developers, and testing labs. It is built using the
|
|
23
|
+
[Inferno Framework](https://inferno-framework.github.io/inferno-core/). The
|
|
24
|
+
Inferno Framework is designed for reuse and aims to make it easier to build test
|
|
25
|
+
kits for any FHIR-based data exchange.
|
|
26
|
+
|
|
27
|
+
To run tests for a SMART App Launch authorization server, select one of the
|
|
28
|
+
"SMART App Launch" suites. To run tests for a Brand Bundle Publisher, select
|
|
29
|
+
the "SMART User-access Brands and Endpoints" suite.
|
|
30
|
+
|
|
31
|
+
## Status
|
|
32
|
+
|
|
33
|
+
The SMART App Launch Test Kit primarily verifies that systems correctly
|
|
34
|
+
implement the SMART App Launch IG for providing authorization and/or
|
|
35
|
+
authentication services to client applications accessing HL7 FHIR APIs.
|
|
36
|
+
|
|
37
|
+
The test kit currently tests the following requirements:
|
|
38
|
+
- Standalone Launch
|
|
39
|
+
- EHR Launch
|
|
40
|
+
|
|
41
|
+
It also tests the ability of a Brand Bundle Publisher to publish a valid brand
|
|
42
|
+
bundle as described in the User-access Brands and Endpoints specification.
|
|
43
|
+
|
|
44
|
+
See the test descriptions within the test kit for detail on the specific
|
|
45
|
+
validations performed as part of testing these requirements.
|
|
46
|
+
|
|
47
|
+
## Repository
|
|
48
|
+
|
|
49
|
+
The SMART App Launch Test Kit GitHub repository can be [found
|
|
50
|
+
here](https://github.com/inferno-framework/smart-app-launch-test-kit).
|
|
51
|
+
|
|
52
|
+
## Providing Feedback and Reporting Issues
|
|
53
|
+
|
|
54
|
+
We welcome feedback on the tests, including but not limited to the following
|
|
55
|
+
areas:
|
|
56
|
+
|
|
57
|
+
- Validation logic, such as potential bugs, lax checks, and unexpected failures.
|
|
58
|
+
- Requirements coverage, such as requirements that have been missed, tests that
|
|
59
|
+
necessitate features that the IG does not require, or other issues with the
|
|
60
|
+
interpretation of the IG's requirements.
|
|
61
|
+
- User experience, such as confusing or missing information in the test UI.
|
|
62
|
+
|
|
63
|
+
Please report any issues with this set of tests in the [issues
|
|
64
|
+
section](https://github.com/inferno-framework/smart-app-launch-test-kit/issues)
|
|
65
|
+
of the repository.
|
|
66
|
+
DESCRIPTION
|
|
67
|
+
suite_ids [:smart, :smart_stu2, :smart_stu2_2, :smart_access_brands]
|
|
68
|
+
tags ['SMART App Launch', 'Endpoint Publication']
|
|
69
|
+
last_updated LAST_UPDATED
|
|
70
|
+
version VERSION
|
|
71
|
+
maturity 'Medium'
|
|
72
|
+
authors ['Stephen MacVicar']
|
|
73
|
+
repo 'https://github.com/inferno-framework/smart-app-launch-test-kit'
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require_relative 'cors_openid_fhir_user_claim_test'
|
|
2
|
+
require_relative 'openid_connect_group'
|
|
3
|
+
|
|
4
|
+
module SMARTAppLaunch
|
|
5
|
+
class OpenIDConnectGroupSTU22 < OpenIDConnectGroup
|
|
6
|
+
id :smart_openid_connect_stu2_2
|
|
7
|
+
title 'OpenID Connect'
|
|
8
|
+
short_description 'Demonstrate the ability to authenticate users with OpenID Connect.'
|
|
9
|
+
|
|
10
|
+
description %(
|
|
11
|
+
# Background
|
|
12
|
+
|
|
13
|
+
OpenID Connect (OIDC) provides the ability to verify the identity of the
|
|
14
|
+
authorizing user. Within the [SMART App Launch
|
|
15
|
+
Framework](https://www.hl7.org/fhir/smart-app-launch/STU2.2/), Applications can
|
|
16
|
+
request an `id_token` be provided with by including the `openid fhirUser`
|
|
17
|
+
scopes when requesting authorization.
|
|
18
|
+
|
|
19
|
+
# Test Methodology
|
|
20
|
+
|
|
21
|
+
This sequence validates the id token returned as part of the OAuth 2.0
|
|
22
|
+
token response. Once the token is decoded, the server's OIDC configuration
|
|
23
|
+
is retrieved from its well-known configuration endpoint. This
|
|
24
|
+
configuration is checked to ensure that all required fields are present.
|
|
25
|
+
Next the keys used to cryptographically sign the id token are retrieved
|
|
26
|
+
from the url contained in the OIDC configuration. Then the header,
|
|
27
|
+
payload, and signature of the id token are validated. Finally, the FHIR
|
|
28
|
+
resource from the `fhirUser` claim in the id token is fetched from the
|
|
29
|
+
FHIR server.
|
|
30
|
+
|
|
31
|
+
For more information see:
|
|
32
|
+
|
|
33
|
+
* [SMART App Launch Framework](https://www.hl7.org/fhir/smart-app-launch/STU2.2/)
|
|
34
|
+
* [Scopes for requesting identity data](https://www.hl7.org/fhir/smart-app-launch/STU2.2/scopes-and-launch-context/index.html#scopes-for-requesting-identity-data)
|
|
35
|
+
* [Apps Requesting Authorization](https://www.hl7.org/fhir/smart-app-launch/STU2.2/index.html#step-1-app-asks-for-authorization)
|
|
36
|
+
* [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html)
|
|
37
|
+
)
|
|
38
|
+
test from: :smart_cors_openid_fhir_user_claim
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
{
|
|
2
|
+
"resourceType" : "Bundle",
|
|
3
|
+
"id" : "example3",
|
|
4
|
+
"type" : "collection",
|
|
5
|
+
"timestamp" : "2023-09-05T20:23:42.723178-07:00",
|
|
6
|
+
"entry" : [
|
|
7
|
+
{
|
|
8
|
+
"fullUrl" : "https://examplehospital.fhirserver.org/Organization/examplehospital",
|
|
9
|
+
"resource" : {
|
|
10
|
+
"resourceType" : "Organization",
|
|
11
|
+
"id" : "examplehospital",
|
|
12
|
+
"extension" : [
|
|
13
|
+
{
|
|
14
|
+
"extension" : [
|
|
15
|
+
{
|
|
16
|
+
"url" : "brandLogo",
|
|
17
|
+
"valueUrl" : "https://fhirserver.org/examplehospital-ehr1/themes/custom/logo.svg"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/organization-brand"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"extension" : [
|
|
24
|
+
{
|
|
25
|
+
"url" : "portalName",
|
|
26
|
+
"valueString" : "ExampleHospital Patient Gateway"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"url" : "portalUrl",
|
|
30
|
+
"valueUrl" : "https://patientgateway.examplehospital.ehr1.fhirserver.org"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"url" : "portalDescription",
|
|
34
|
+
"valueMarkdown" : "Patient Gateway is an online tool to help adult patients connect with health care providers, manage appointments, and refill prescriptions.\n"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"url" : "portalEndpoint",
|
|
38
|
+
"valueReference" : {
|
|
39
|
+
"reference" : "https://ehr1.fhirserver.com/Endpoint/examplehospital-ehr1",
|
|
40
|
+
"display" : "FHIR R4 Endpoint for EHR1"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/organization-portal"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"extension" : [
|
|
48
|
+
{
|
|
49
|
+
"url" : "portalName",
|
|
50
|
+
"valueString" : "ExampleHospital Pediatric Portal"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"url" : "portalUrl",
|
|
54
|
+
"valueUrl" : "https://pediatrics.examplehospital.ehr2.fhirserver.org"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"url" : "portalDescription",
|
|
58
|
+
"valueMarkdown" : "Pediatric Portal is the entrypoint for pediatric patients."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"url" : "portalEndpoint",
|
|
62
|
+
"valueReference" : {
|
|
63
|
+
"reference" : "https://ehr2.fhirserver.com/Endpoint/examplehospital-ehr2",
|
|
64
|
+
"display" : "FHIR R4 Endpoint for EHR2"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/organization-portal"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"identifier" : [
|
|
72
|
+
{
|
|
73
|
+
"system" : "urn:ietf:rfc:3986",
|
|
74
|
+
"value" : "https://examplehospital.fhirserver.org"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"active" : true,
|
|
78
|
+
"type" : [
|
|
79
|
+
{
|
|
80
|
+
"coding" : [
|
|
81
|
+
{
|
|
82
|
+
"system" : "http://terminology.hl7.org/CodeSystem/organization-type",
|
|
83
|
+
"code" : "prov",
|
|
84
|
+
"display" : "Healthcare Provider"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"name" : "ExampleHospital",
|
|
90
|
+
"alias" : [
|
|
91
|
+
"GoodHealth Healthcare"
|
|
92
|
+
],
|
|
93
|
+
"telecom" : [
|
|
94
|
+
{
|
|
95
|
+
"system" : "url",
|
|
96
|
+
"value" : "https://examplehospital.fhirserver.org/contact"
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"address" : [
|
|
100
|
+
{
|
|
101
|
+
"city" : "Boston",
|
|
102
|
+
"state" : "MA"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"city" : "Newton",
|
|
106
|
+
"state" : "MA"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"city" : "Waltham",
|
|
110
|
+
"state" : "MA"
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"endpoint" : [
|
|
114
|
+
{
|
|
115
|
+
"reference" : "https://ehr1.fhirserver.com/Endpoint/examplehospital-ehr1",
|
|
116
|
+
"display" : "FHIR R4 Endpoint for EHR1"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"reference" : "https://ehr2.fhirserver.com/Endpoint/examplehospital-ehr2",
|
|
120
|
+
"display" : "FHIR R4 Endpoint for EHR2"
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"fullUrl" : "https://ehr1.fhirserver.com/Endpoint/examplehospital-ehr1",
|
|
127
|
+
"resource" : {
|
|
128
|
+
"resourceType" : "Endpoint",
|
|
129
|
+
"id" : "examplehospital-ehr1",
|
|
130
|
+
"extension" : [
|
|
131
|
+
{
|
|
132
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/endpoint-fhir-version",
|
|
133
|
+
"valueCode" : "4.0.1"
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
"status" : "active",
|
|
137
|
+
"connectionType" : {
|
|
138
|
+
"system" : "http://terminology.hl7.org/CodeSystem/endpoint-connection-type",
|
|
139
|
+
"code" : "hl7-fhir-rest"
|
|
140
|
+
},
|
|
141
|
+
"name" : "FHIR R4 Endpoint for ExampleHospital's EHR1 Patient Gateway",
|
|
142
|
+
"contact" : [
|
|
143
|
+
{
|
|
144
|
+
"system" : "url",
|
|
145
|
+
"value" : "https://open.ehr1.fhirserver.com"
|
|
146
|
+
}
|
|
147
|
+
],
|
|
148
|
+
"payloadType" : [
|
|
149
|
+
{
|
|
150
|
+
"coding" : [
|
|
151
|
+
{
|
|
152
|
+
"system" : "http://terminology.hl7.org/CodeSystem/endpoint-payload-type",
|
|
153
|
+
"code" : "none"
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
"address" : "<%= Inferno::Application['base_url'] %>/custom/smart_access_brands/examples/r4_capability_statement"
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"fullUrl" : "https://ehr2.fhirserver.com/Endpoint/examplehospital-ehr2",
|
|
163
|
+
"resource" : {
|
|
164
|
+
"resourceType" : "Endpoint",
|
|
165
|
+
"id" : "examplehospital-ehr2",
|
|
166
|
+
"extension" : [
|
|
167
|
+
{
|
|
168
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/endpoint-fhir-version",
|
|
169
|
+
"valueCode" : "4.0.1"
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
"status" : "active",
|
|
173
|
+
"connectionType" : {
|
|
174
|
+
"system" : "http://terminology.hl7.org/CodeSystem/endpoint-connection-type",
|
|
175
|
+
"code" : "hl7-fhir-rest"
|
|
176
|
+
},
|
|
177
|
+
"name" : "FHIR R4 Endpoint for ExampleHospital's EHR2 Pediatric Portal",
|
|
178
|
+
"contact" : [
|
|
179
|
+
{
|
|
180
|
+
"system" : "url",
|
|
181
|
+
"value" : "https://open.ehr2.fhirserver.com"
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
"payloadType" : [
|
|
185
|
+
{
|
|
186
|
+
"coding" : [
|
|
187
|
+
{
|
|
188
|
+
"system" : "http://terminology.hl7.org/CodeSystem/endpoint-payload-type",
|
|
189
|
+
"code" : "none"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
"address" : "<%= Inferno::Application['base_url'] %>/custom/smart_access_brands/examples/r4_capability_statement"
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
}
|
|
@@ -5,7 +5,6 @@ module SMARTAppLaunch
|
|
|
5
5
|
id 'smart_access_brands'
|
|
6
6
|
title 'SMART User-access Brands and Endpoints STU2.2'
|
|
7
7
|
short_title 'SMART User-access Brands'
|
|
8
|
-
version VERSION
|
|
9
8
|
|
|
10
9
|
description <<~DESCRIPTION
|
|
11
10
|
The SMART User-access Brands Test Suite verifies that Brand Bundle Publishers publish valid User-access
|
|
@@ -34,6 +33,10 @@ module SMARTAppLaunch
|
|
|
34
33
|
Bundle as an input and leaving the User Access Brand Publication URL input blank.
|
|
35
34
|
INSTRUCTIONS
|
|
36
35
|
|
|
36
|
+
source_code_url('https://github.com/inferno-framework/smart-app-launch-test-kit')
|
|
37
|
+
download_url('https://github.com/inferno-framework/smart-app-launch-test-kit/releases')
|
|
38
|
+
report_issue_url('https://github.com/inferno-framework/smart-app-launch-test-kit/issues')
|
|
39
|
+
|
|
37
40
|
VALIDATION_MESSAGE_FILTERS = [
|
|
38
41
|
/\A\S+: \S+: URL value '.*' does not resolve/,
|
|
39
42
|
%r{\A\S+: \S+: Bundled or contained reference not found within the bundle/resource} # Validator issue with Brand profile: https://chat.fhir.org/#narrow/stream/291844-FHIR-Validator/topic/SMART.20v2.2E2.20User.20Access.20Brands.3A.20Brand.20validation.20error.3F/near/466321024
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'tls_test_kit'
|
|
2
2
|
|
|
3
3
|
require_relative 'jwks'
|
|
4
|
-
require_relative 'version'
|
|
5
4
|
require_relative 'discovery_stu1_group'
|
|
6
5
|
require_relative 'standalone_launch_group'
|
|
7
6
|
require_relative 'ehr_launch_group'
|
|
@@ -12,7 +11,6 @@ module SMARTAppLaunch
|
|
|
12
11
|
class SMARTSTU1Suite < Inferno::TestSuite
|
|
13
12
|
id 'smart'
|
|
14
13
|
title 'SMART App Launch STU1'
|
|
15
|
-
version VERSION
|
|
16
14
|
|
|
17
15
|
resume_test_route :get, '/launch' do |request|
|
|
18
16
|
request.query_parameters['iss']
|
|
@@ -34,15 +32,18 @@ module SMARTAppLaunch
|
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
description <<~DESCRIPTION
|
|
37
|
-
The SMART App Launch Test Suite verifies that systems correctly implement
|
|
38
|
-
the [SMART App Launch IG](http://hl7.org/fhir/smart-app-launch/1.0.0/)
|
|
39
|
-
for providing authorization and/or authentication services to client
|
|
40
|
-
applications accessing HL7® FHIR® APIs. To get started, please first register
|
|
35
|
+
The SMART App Launch Test Suite verifies that systems correctly implement
|
|
36
|
+
the [SMART App Launch IG](http://hl7.org/fhir/smart-app-launch/1.0.0/)
|
|
37
|
+
for providing authorization and/or authentication services to client
|
|
38
|
+
applications accessing HL7® FHIR® APIs. To get started, please first register
|
|
41
39
|
the Inferno client as a SMART App with the following information:
|
|
42
40
|
|
|
43
41
|
* SMART Launch URI: `#{config.options[:launch_uri]}`
|
|
44
42
|
* OAuth Redirect URI: `#{config.options[:redirect_uri]}`
|
|
45
43
|
DESCRIPTION
|
|
44
|
+
source_code_url('https://github.com/inferno-framework/smart-app-launch-test-kit')
|
|
45
|
+
download_url('https://github.com/inferno-framework/smart-app-launch-test-kit/releases')
|
|
46
|
+
report_issue_url('https://github.com/inferno-framework/smart-app-launch-test-kit/issues')
|
|
46
47
|
|
|
47
48
|
group do
|
|
48
49
|
title 'Standalone Launch'
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
require 'tls_test_kit'
|
|
2
2
|
|
|
3
3
|
require_relative 'jwks'
|
|
4
|
-
require_relative '
|
|
5
|
-
require_relative 'discovery_stu2_group'
|
|
4
|
+
require_relative 'discovery_stu2_2_group'
|
|
6
5
|
require_relative 'standalone_launch_group_stu2_2'
|
|
7
6
|
require_relative 'ehr_launch_group_stu2_2'
|
|
8
|
-
require_relative '
|
|
7
|
+
require_relative 'openid_connect_group_stu2_2'
|
|
9
8
|
require_relative 'token_introspection_group_stu2_2'
|
|
10
|
-
require_relative 'token_refresh_stu2_group'
|
|
11
9
|
require_relative 'backend_services_authorization_group'
|
|
12
10
|
|
|
13
11
|
module SMARTAppLaunch
|
|
14
12
|
class SMARTSTU22Suite < Inferno::TestSuite
|
|
15
13
|
id 'smart_stu2_2'
|
|
16
14
|
title 'SMART App Launch STU2.2'
|
|
17
|
-
version VERSION
|
|
18
15
|
|
|
19
16
|
resume_test_route :get, '/launch' do |request|
|
|
20
17
|
request.query_parameters['iss']
|
|
@@ -73,6 +70,9 @@ module SMARTAppLaunch
|
|
|
73
70
|
If the token introspection endpoint of the system under test is NOT available at .well-known/smart-configuration,
|
|
74
71
|
please run the test groups individually and group 3 Token Introspection will include the introspection endpoint as a manual input.
|
|
75
72
|
)
|
|
73
|
+
source_code_url('https://github.com/inferno-framework/smart-app-launch-test-kit')
|
|
74
|
+
download_url('https://github.com/inferno-framework/smart-app-launch-test-kit/releases')
|
|
75
|
+
report_issue_url('https://github.com/inferno-framework/smart-app-launch-test-kit/issues')
|
|
76
76
|
|
|
77
77
|
group do
|
|
78
78
|
title 'Standalone Launch'
|
|
@@ -92,10 +92,10 @@ module SMARTAppLaunch
|
|
|
92
92
|
|
|
93
93
|
run_as_group
|
|
94
94
|
|
|
95
|
-
group from: :
|
|
95
|
+
group from: :smart_discovery_stu2_2
|
|
96
96
|
group from: :smart_standalone_launch_stu2_2
|
|
97
97
|
|
|
98
|
-
group from: :
|
|
98
|
+
group from: :smart_openid_connect_stu2_2,
|
|
99
99
|
config: {
|
|
100
100
|
inputs: {
|
|
101
101
|
id_token: { name: :standalone_id_token },
|
|
@@ -167,11 +167,11 @@ module SMARTAppLaunch
|
|
|
167
167
|
|
|
168
168
|
run_as_group
|
|
169
169
|
|
|
170
|
-
group from: :
|
|
170
|
+
group from: :smart_discovery_stu2_2
|
|
171
171
|
|
|
172
172
|
group from: :smart_ehr_launch_stu2_2
|
|
173
173
|
|
|
174
|
-
group from: :
|
|
174
|
+
group from: :smart_openid_connect_stu2_2,
|
|
175
175
|
config: {
|
|
176
176
|
inputs: {
|
|
177
177
|
id_token: { name: :ehr_id_token },
|
|
@@ -237,7 +237,7 @@ module SMARTAppLaunch
|
|
|
237
237
|
|
|
238
238
|
run_as_group
|
|
239
239
|
|
|
240
|
-
group from: :
|
|
240
|
+
group from: :smart_discovery_stu2_2
|
|
241
241
|
group from: :backend_services_authorization
|
|
242
242
|
end
|
|
243
243
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'tls_test_kit'
|
|
2
2
|
|
|
3
3
|
require_relative 'jwks'
|
|
4
|
-
require_relative 'version'
|
|
5
4
|
require_relative 'discovery_stu2_group'
|
|
6
5
|
require_relative 'standalone_launch_group_stu2'
|
|
7
6
|
require_relative 'ehr_launch_group_stu2'
|
|
@@ -14,7 +13,6 @@ module SMARTAppLaunch
|
|
|
14
13
|
class SMARTSTU2Suite < Inferno::TestSuite
|
|
15
14
|
id 'smart_stu2'
|
|
16
15
|
title 'SMART App Launch STU2'
|
|
17
|
-
version VERSION
|
|
18
16
|
|
|
19
17
|
resume_test_route :get, '/launch' do |request|
|
|
20
18
|
request.query_parameters['iss']
|
|
@@ -42,10 +40,10 @@ module SMARTAppLaunch
|
|
|
42
40
|
}
|
|
43
41
|
|
|
44
42
|
description <<~DESCRIPTION
|
|
45
|
-
The SMART App Launch Test Suite verifies that systems correctly implement
|
|
46
|
-
the [SMART App Launch IG](http://hl7.org/fhir/smart-app-launch/STU2/)
|
|
47
|
-
for providing authorization and/or authentication services to client
|
|
48
|
-
applications accessing HL7® FHIR® APIs. To get started, please first register
|
|
43
|
+
The SMART App Launch Test Suite verifies that systems correctly implement
|
|
44
|
+
the [SMART App Launch IG](http://hl7.org/fhir/smart-app-launch/STU2/)
|
|
45
|
+
for providing authorization and/or authentication services to client
|
|
46
|
+
applications accessing HL7® FHIR® APIs. To get started, please first register
|
|
49
47
|
the Inferno client as a SMART App with the following information:
|
|
50
48
|
|
|
51
49
|
* SMART Launch URI: `#{config.options[:launch_uri]}`
|
|
@@ -59,17 +57,20 @@ module SMARTAppLaunch
|
|
|
59
57
|
|
|
60
58
|
input_instructions %(
|
|
61
59
|
When running tests at this level, the token introspection endpoint is not available as a manual input.
|
|
62
|
-
Instead, group 3 Token Introspection will assume the token introspection endpoint
|
|
60
|
+
Instead, group 3 Token Introspection will assume the token introspection endpoint
|
|
63
61
|
will be output from group 1 Standalone Launch tests, specifically the SMART On FHIR Discovery tests that query
|
|
64
62
|
the .well-known/smart-configuration endpoint. However, including the token introspection
|
|
65
63
|
endpoint as part of the well-known ouput is NOT required and is not formally checked in the SMART On FHIR Discovery
|
|
66
64
|
tests. RFC-7662 on Token Introspection says that "The means by which the protected resource discovers the location of the introspection
|
|
67
65
|
endpoint are outside the scope of this specification" and the Token Introspection IG does not add any further
|
|
68
|
-
requirements to this.
|
|
66
|
+
requirements to this.
|
|
69
67
|
|
|
70
|
-
If the token introspection endpoint of the system under test is NOT available at .well-known/smart-configuration,
|
|
71
|
-
please run the test groups individually and group 3 Token Introspection will include the introspection endpoint as a manual input.
|
|
68
|
+
If the token introspection endpoint of the system under test is NOT available at .well-known/smart-configuration,
|
|
69
|
+
please run the test groups individually and group 3 Token Introspection will include the introspection endpoint as a manual input.
|
|
72
70
|
)
|
|
71
|
+
source_code_url('https://github.com/inferno-framework/smart-app-launch-test-kit')
|
|
72
|
+
download_url('https://github.com/inferno-framework/smart-app-launch-test-kit/releases')
|
|
73
|
+
report_issue_url('https://github.com/inferno-framework/smart-app-launch-test-kit/issues')
|
|
73
74
|
|
|
74
75
|
group do
|
|
75
76
|
title 'Standalone Launch'
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
require_relative 'token_response_body_test_stu2_2'
|
|
2
2
|
require_relative 'standalone_launch_group_stu2'
|
|
3
|
+
require_relative 'cors_token_exchange_test'
|
|
4
|
+
require_relative 'token_exchange_stu2_2_test'
|
|
3
5
|
|
|
4
6
|
module SMARTAppLaunch
|
|
5
7
|
class StandaloneLaunchGroupSTU22 < StandaloneLaunchGroupSTU2
|
|
@@ -44,9 +46,21 @@ module SMARTAppLaunch
|
|
|
44
46
|
}
|
|
45
47
|
)
|
|
46
48
|
|
|
49
|
+
test from: :smart_token_exchange_stu2_2
|
|
50
|
+
|
|
51
|
+
token_exchange_index = children.find_index { |child| child.id.to_s.end_with? 'token_exchange' }
|
|
52
|
+
children[token_exchange_index] = children.pop
|
|
53
|
+
|
|
47
54
|
test from: :smart_token_response_body_stu2_2
|
|
48
55
|
|
|
49
56
|
token_response_body_index = children.find_index { |child| child.id.to_s.end_with? 'token_response_body' }
|
|
50
57
|
children[token_response_body_index] = children.pop
|
|
58
|
+
|
|
59
|
+
test from: :smart_cors_token_exchange,
|
|
60
|
+
config: {
|
|
61
|
+
requests: {
|
|
62
|
+
cors_token_request: { name: :standalone_token }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
51
65
|
end
|
|
52
66
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require_relative 'token_exchange_stu2_test'
|
|
2
|
+
|
|
3
|
+
module SMARTAppLaunch
|
|
4
|
+
class TokenExchangeSTU22Test < TokenExchangeSTU2Test
|
|
5
|
+
id :smart_token_exchange_stu2_2
|
|
6
|
+
|
|
7
|
+
def add_credentials_to_request(oauth2_params, oauth2_headers)
|
|
8
|
+
if client_auth_type == 'confidential_symmetric'
|
|
9
|
+
assert client_secret.present?,
|
|
10
|
+
'A client secret must be provided when using confidential symmetric client authentication.'
|
|
11
|
+
|
|
12
|
+
client_credentials = "#{client_id}:#{client_secret}"
|
|
13
|
+
oauth2_headers['Authorization'] = "Basic #{Base64.strict_encode64(client_credentials)}"
|
|
14
|
+
elsif client_auth_type == 'public'
|
|
15
|
+
oauth2_params[:client_id] = client_id
|
|
16
|
+
oauth2_headers['Origin'] = Inferno::Application['inferno_host']
|
|
17
|
+
else
|
|
18
|
+
oauth2_params.merge!(
|
|
19
|
+
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
|
20
|
+
client_assertion: ClientAssertionBuilder.build(
|
|
21
|
+
iss: client_id,
|
|
22
|
+
sub: client_id,
|
|
23
|
+
aud: smart_token_url,
|
|
24
|
+
client_auth_encryption_method:
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -51,7 +51,7 @@ module SMARTAppLaunch
|
|
|
51
51
|
skip_if request.query_parameters['error'].present?, 'Error during authorization request'
|
|
52
52
|
|
|
53
53
|
oauth2_params = {
|
|
54
|
-
code
|
|
54
|
+
code:,
|
|
55
55
|
redirect_uri: config.options[:redirect_uri],
|
|
56
56
|
grant_type: 'authorization_code'
|
|
57
57
|
}
|
|
@@ -59,9 +59,7 @@ module SMARTAppLaunch
|
|
|
59
59
|
|
|
60
60
|
add_credentials_to_request(oauth2_params, oauth2_headers)
|
|
61
61
|
|
|
62
|
-
if use_pkce == 'true'
|
|
63
|
-
oauth2_params[:code_verifier] = pkce_code_verifier
|
|
64
|
-
end
|
|
62
|
+
oauth2_params[:code_verifier] = pkce_code_verifier if use_pkce == 'true'
|
|
65
63
|
|
|
66
64
|
post(smart_token_url, body: oauth2_params, name: :token, headers: oauth2_headers)
|
|
67
65
|
|
|
@@ -72,17 +70,15 @@ module SMARTAppLaunch
|
|
|
72
70
|
|
|
73
71
|
token_response_body = JSON.parse(request.response_body)
|
|
74
72
|
|
|
75
|
-
|
|
76
73
|
output smart_credentials: {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
74
|
+
refresh_token: token_response_body['refresh_token'],
|
|
75
|
+
access_token: token_response_body['access_token'],
|
|
76
|
+
expires_in: token_response_body['expires_in'],
|
|
77
|
+
client_id:,
|
|
78
|
+
client_secret:,
|
|
79
|
+
token_retrieval_time:,
|
|
80
|
+
token_url: smart_token_url
|
|
81
|
+
}.to_json
|
|
86
82
|
end
|
|
87
83
|
end
|
|
88
84
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require_relative 'standalone_launch_group_stu2_2'
|
|
2
2
|
|
|
3
3
|
module SMARTAppLaunch
|
|
4
|
-
class SMARTTokenIntrospectionAccessTokenGroupSTU22 <
|
|
4
|
+
class SMARTTokenIntrospectionAccessTokenGroupSTU22 < Inferno::TestGroup
|
|
5
5
|
title 'Request New Access Token to Introspect'
|
|
6
6
|
run_as_group
|
|
7
7
|
|
|
@@ -20,9 +20,7 @@ module SMARTAppLaunch
|
|
|
20
20
|
Register Inferno as a Standalone SMART App and provide the registration details below.
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
+
group from: :smart_discovery_stu2_2
|
|
23
24
|
group from: :smart_standalone_launch_stu2_2
|
|
24
|
-
|
|
25
|
-
standalone_launch_index = children.find_index { |child| child.id.to_s.end_with? 'standalone_launch_stu2' }
|
|
26
|
-
children[standalone_launch_index] = children.pop
|
|
27
25
|
end
|
|
28
26
|
end
|
|
@@ -57,13 +57,12 @@ module SMARTAppLaunch
|
|
|
57
57
|
|
|
58
58
|
If the introspection endpoint is protected, testers must enter their own HTTP Authorization header for the introspection request. See
|
|
59
59
|
[RFC 7616 The 'Basic' HTTP Authentication Scheme](https://datatracker.ietf.org/doc/html/rfc7617) for the most common
|
|
60
|
-
approach that uses client credentials. Testers may also provide any additional parameters needed for their authorization
|
|
60
|
+
approach that uses client credentials. Testers may also provide any additional parameters needed for their authorization
|
|
61
61
|
server to complete the introspection request.
|
|
62
62
|
|
|
63
63
|
**Note:** For both the Authorization header and request parameters, user-input
|
|
64
64
|
values will be sent exactly as entered and therefore the tester must
|
|
65
65
|
URI-encode any appropriate values.
|
|
66
66
|
)
|
|
67
|
-
|
|
68
67
|
end
|
|
69
68
|
end
|
|
@@ -43,26 +43,5 @@ module SMARTAppLaunch
|
|
|
43
43
|
|
|
44
44
|
access_token_group_index = children.find_index { |child| child.id.to_s.end_with? 'access_token_group' }
|
|
45
45
|
children[access_token_group_index] = children.pop
|
|
46
|
-
|
|
47
|
-
input_order :url, :standalone_client_id, :standalone_client_secret,
|
|
48
|
-
:authorization_method, :use_pkce, :pkce_code_challenge_method,
|
|
49
|
-
:standalone_requested_scopes, :client_auth_encryption_method,
|
|
50
|
-
:client_auth_type, :custom_authorization_header,
|
|
51
|
-
:optional_introspection_request_params
|
|
52
|
-
input_instructions %(
|
|
53
|
-
Executing tests at this level will run all three Token Introspection groups back-to-back. If test groups need
|
|
54
|
-
to be run independently, exit this window and select a specific test group instead.
|
|
55
|
-
|
|
56
|
-
These tests are currently designed such that the token introspection URL must be present in the SMART well-known endpoint.
|
|
57
|
-
|
|
58
|
-
If the introspection endpoint is protected, testers must enter their own HTTP Authorization header for the introspection request. See
|
|
59
|
-
[RFC 7616 The 'Basic' HTTP Authentication Scheme](https://datatracker.ietf.org/doc/html/rfc7617) for the most common
|
|
60
|
-
approach that uses client credentials. Testers may also provide any additional parameters needed for their authorization
|
|
61
|
-
server to complete the introspection request.
|
|
62
|
-
|
|
63
|
-
**Note:** For both the Authorization header and request parameters, user-input
|
|
64
|
-
values will be sent exactly as entered and therefore the tester must
|
|
65
|
-
URI-encode any appropriate values.
|
|
66
|
-
)
|
|
67
46
|
end
|
|
68
47
|
end
|