smart_app_launch_test_kit 0.4.3 → 0.4.4
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/smart_app_launch/ehr_launch_group_stu2_2.rb +54 -0
- data/lib/smart_app_launch/smart_access_brands_examples/r4_capability_statement.json +198 -0
- data/lib/smart_app_launch/smart_access_brands_group.rb +59 -0
- data/lib/smart_app_launch/smart_access_brands_retrieval_group.rb +21 -0
- data/lib/smart_app_launch/smart_access_brands_retrieve_bundle_test.rb +31 -0
- data/lib/smart_app_launch/smart_access_brands_suite.rb +77 -0
- data/lib/smart_app_launch/smart_access_brands_validate_brands_test.rb +104 -0
- data/lib/smart_app_launch/smart_access_brands_validate_bundle_test.rb +45 -0
- data/lib/smart_app_launch/smart_access_brands_validate_endpoint_urls_test.rb +120 -0
- data/lib/smart_app_launch/smart_access_brands_validate_endpoints_test.rb +70 -0
- data/lib/smart_app_launch/smart_access_brands_validation_group.rb +24 -0
- data/lib/smart_app_launch/smart_stu2_2_suite.rb +243 -0
- data/lib/smart_app_launch/standalone_launch_group_stu2_2.rb +52 -0
- data/lib/smart_app_launch/token_introspection_access_token_group_stu2_2.rb +28 -0
- data/lib/smart_app_launch/token_introspection_group_stu2_2.rb +68 -0
- data/lib/smart_app_launch/token_payload_validation.rb +129 -60
- data/lib/smart_app_launch/token_response_body_test_stu2_2.rb +32 -0
- data/lib/smart_app_launch/version.rb +1 -1
- data/lib/smart_app_launch/well_known_endpoint_test.rb +5 -1
- data/lib/smart_app_launch_test_kit.rb +2 -0
- metadata +18 -2
@@ -5,66 +5,66 @@ module SMARTAppLaunch
|
|
5
5
|
|
6
6
|
# All resource types from DSTU3, STU3, R4, R4B, and R5
|
7
7
|
FHIR_RESOURCE_TYPES = [
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
8
|
+
'Account', 'ActivityDefinition', 'ActorDefinition',
|
9
|
+
'AdministrableProductDefinition', 'AdverseEvent', 'AllergyIntolerance',
|
10
|
+
'Appointment', 'AppointmentResponse', 'ArtifactAssessment', 'AuditEvent',
|
11
|
+
'Basic', 'Binary', 'BiologicallyDerivedProduct',
|
12
|
+
'BiologicallyDerivedProductDispense', 'BodySite', 'BodyStructure',
|
13
|
+
'Bundle', 'CapabilityStatement', 'CarePlan', 'CareTeam', 'CatalogEntry',
|
14
|
+
'ChargeItem', 'ChargeItemDefinition', 'Citation', 'Claim',
|
15
|
+
'ClaimResponse', 'ClinicalImpression', 'ClinicalUseDefinition',
|
16
|
+
'CodeSystem', 'Communication', 'CommunicationRequest',
|
17
|
+
'CompartmentDefinition', 'Composition', 'ConceptMap', 'Condition',
|
18
|
+
'ConditionDefinition', 'Conformance', 'Consent', 'Contract', 'Coverage',
|
19
|
+
'CoverageEligibilityRequest', 'CoverageEligibilityResponse',
|
20
|
+
'DataElement', 'DetectedIssue', 'Device', 'DeviceAssociation',
|
21
|
+
'DeviceComponent', 'DeviceDefinition', 'DeviceDispense', 'DeviceMetric',
|
22
|
+
'DeviceRequest', 'DeviceUsage', 'DeviceUseRequest', 'DeviceUseStatement',
|
23
|
+
'DiagnosticOrder', 'DiagnosticReport', 'DocumentManifest',
|
24
|
+
'DocumentReference', 'EffectEvidenceSynthesis', 'EligibilityRequest',
|
25
|
+
'EligibilityResponse', 'Encounter', 'EncounterHistory', 'Endpoint',
|
26
|
+
'EnrollmentRequest', 'EnrollmentResponse', 'EpisodeOfCare',
|
27
|
+
'EventDefinition', 'Evidence', 'EvidenceReport', 'EvidenceVariable',
|
28
|
+
'ExampleScenario', 'ExpansionProfile', 'ExplanationOfBenefit',
|
29
|
+
'FamilyMemberHistory', 'Flag', 'FormularyItem', 'GenomicStudy', 'Goal',
|
30
|
+
'GraphDefinition', 'Group', 'GuidanceResponse', 'HealthcareService',
|
31
|
+
'ImagingManifest', 'ImagingObjectSelection', 'ImagingSelection',
|
32
|
+
'ImagingStudy', 'Immunization', 'ImmunizationEvaluation',
|
33
|
+
'ImmunizationRecommendation', 'ImplementationGuide', 'Ingredient',
|
34
|
+
'InsurancePlan', 'InventoryItem', 'InventoryReport', 'Invoice', 'Library',
|
35
|
+
'Linkage', 'List', 'Location', 'ManufacturedItemDefinition', 'Measure',
|
36
|
+
'MeasureReport', 'Media', 'Medication', 'MedicationAdministration',
|
37
|
+
'MedicationDispense', 'MedicationKnowledge', 'MedicationOrder',
|
38
|
+
'MedicationRequest', 'MedicationStatement', 'MedicinalProduct',
|
39
|
+
'MedicinalProductAuthorization', 'MedicinalProductContraindication',
|
40
|
+
'MedicinalProductDefinition', 'MedicinalProductIndication',
|
41
|
+
'MedicinalProductIngredient', 'MedicinalProductInteraction',
|
42
|
+
'MedicinalProductManufactured', 'MedicinalProductPackaged',
|
43
|
+
'MedicinalProductPharmaceutical', 'MedicinalProductUndesirableEffect',
|
44
|
+
'MessageDefinition', 'MessageHeader', 'MolecularSequence', 'NamingSystem',
|
45
|
+
'NutritionIntake', 'NutritionOrder', 'NutritionProduct', 'Observation',
|
46
|
+
'ObservationDefinition', 'OperationDefinition', 'OperationOutcome',
|
47
|
+
'Order', 'OrderResponse', 'Organization', 'OrganizationAffiliation',
|
48
|
+
'PackagedProductDefinition', 'Patient', 'PaymentNotice',
|
49
|
+
'PaymentReconciliation', 'Permission', 'Person', 'PlanDefinition',
|
50
|
+
'Practitioner', 'PractitionerRole', 'Procedure', 'ProcedureRequest',
|
51
|
+
'ProcessRequest', 'ProcessResponse', 'Provenance', 'Questionnaire',
|
52
|
+
'QuestionnaireResponse', 'ReferralRequest', 'RegulatedAuthorization',
|
53
|
+
'RelatedPerson', 'RequestGroup', 'RequestOrchestration', 'Requirements',
|
54
|
+
'ResearchDefinition', 'ResearchElementDefinition', 'ResearchStudy',
|
55
|
+
'ResearchSubject', 'RiskAssessment', 'RiskEvidenceSynthesis', 'Schedule',
|
56
|
+
'SearchParameter', 'Sequence', 'ServiceDefinition', 'ServiceRequest',
|
57
|
+
'Slot', 'Specimen', 'SpecimenDefinition', 'StructureDefinition',
|
58
|
+
'StructureMap', 'Subscription', 'SubscriptionStatus', 'SubscriptionTopic',
|
59
|
+
'Substance', 'SubstanceDefinition', 'SubstanceNucleicAcid',
|
60
|
+
'SubstancePolymer', 'SubstanceProtein', 'SubstanceReferenceInformation',
|
61
|
+
'SubstanceSourceMaterial', 'SubstanceSpecification', 'SupplyDelivery',
|
62
|
+
'SupplyRequest', 'Task', 'TerminologyCapabilities', 'TestPlan',
|
63
|
+
'TestReport', 'TestScript', 'Transport', 'ValueSet', 'VerificationResult',
|
64
|
+
'VisionPrescription'
|
65
65
|
].to_set.freeze
|
66
66
|
|
67
|
-
FHIR_ID_REGEX =
|
67
|
+
FHIR_ID_REGEX = %r{[A-Za-z0-9\-\.]{1,64}(/_history/[A-Za-z0-9\-\.]{1,64})?(#[A-Za-z0-9\-\.]{1,64})?}
|
68
68
|
|
69
69
|
def validate_required_fields_present(body, required_fields)
|
70
70
|
missing_fields = required_fields.select { |field| body[field].blank? }
|
@@ -93,7 +93,7 @@ module SMARTAppLaunch
|
|
93
93
|
|
94
94
|
def validate_scope_subset(received_scopes, original_scopes)
|
95
95
|
extra_scopes = received_scopes.split - original_scopes.split
|
96
|
-
assert extra_scopes.empty?,
|
96
|
+
assert extra_scopes.empty?, 'Token response contained scopes which are not a subset of the scope granted to the ' \
|
97
97
|
"original access token: #{extra_scopes.join(', ')}"
|
98
98
|
end
|
99
99
|
|
@@ -124,7 +124,6 @@ module SMARTAppLaunch
|
|
124
124
|
|
125
125
|
fhir_context.each do |reference|
|
126
126
|
assert !reference.start_with?('http'), "`#{reference}` is not a relative reference"
|
127
|
-
|
128
127
|
resource_type, id = reference.split('/')
|
129
128
|
assert FHIR_RESOURCE_TYPES.include?(resource_type),
|
130
129
|
"`#{resource_type}` is not a valid FHIR resource type"
|
@@ -132,5 +131,75 @@ module SMARTAppLaunch
|
|
132
131
|
assert id.match?(FHIR_ID_REGEX), "`#{id}` is not a valid FHIR id"
|
133
132
|
end
|
134
133
|
end
|
134
|
+
|
135
|
+
def check_fhir_context_reference(reference)
|
136
|
+
assert reference.is_a?(String), "`#{reference.inspect}` is not a String"
|
137
|
+
assert !reference.start_with?('http'), "`#{reference}` is not a relative reference"
|
138
|
+
|
139
|
+
resource_type, id = reference.split('/')
|
140
|
+
|
141
|
+
assert FHIR_RESOURCE_TYPES.include?(resource_type),
|
142
|
+
"`#{resource_type}` in `reference` is not a valid FHIR resource type"
|
143
|
+
|
144
|
+
assert id.match?(FHIR_ID_REGEX), "`#{id}` in `reference` is not a valid FHIR id"
|
145
|
+
end
|
146
|
+
|
147
|
+
def check_fhir_context_canonical(canonical)
|
148
|
+
assert canonical.is_a?(String), "`#{canonical.inspect}` is not a String"
|
149
|
+
assert canonical.start_with?('http'), "`#{canonical}` is not a canonical reference"
|
150
|
+
|
151
|
+
split_canonical = canonical.split('/')
|
152
|
+
|
153
|
+
if split_canonical.last.start_with?(/&|\|/)
|
154
|
+
resource_type = split_canonical[-3]
|
155
|
+
id = split_canonical[-2]
|
156
|
+
else
|
157
|
+
resource_type = split_canonical[-2]
|
158
|
+
id = split_canonical.last.split(/&|\|/).first
|
159
|
+
end
|
160
|
+
|
161
|
+
assert FHIR_RESOURCE_TYPES.include?(resource_type),
|
162
|
+
"`#{resource_type}` in `canonical` is not a valid FHIR resource type"
|
163
|
+
|
164
|
+
assert id.match?(FHIR_ID_REGEX), "`#{id}` in `canonical` is not a valid FHIR id"
|
165
|
+
end
|
166
|
+
|
167
|
+
def check_fhir_context_identifier(identifier)
|
168
|
+
assert identifier.is_a?(Hash), "`#{identifier.inspect}` is not an Object"
|
169
|
+
end
|
170
|
+
|
171
|
+
def validate_fhir_context_stu2_2(fhir_context)
|
172
|
+
return if fhir_context.nil?
|
173
|
+
|
174
|
+
assert fhir_context.is_a?(Array), "`fhirContext` field is a #{fhir_context.class.name}, but should be an Array"
|
175
|
+
|
176
|
+
fhir_context.each do |reference|
|
177
|
+
assert reference.is_a?(Hash), "`#{reference.inspect}` is not an Object"
|
178
|
+
end
|
179
|
+
|
180
|
+
fhir_context.each do |context|
|
181
|
+
reference = context['reference']
|
182
|
+
canonical = context['canonical']
|
183
|
+
identifier = context['identifier']
|
184
|
+
|
185
|
+
type = context['type']
|
186
|
+
|
187
|
+
assert reference.present? || canonical.present? || identifier.present?,
|
188
|
+
'`fhirContext` array SHALL include at least one of "reference", "canonical", or "identifier"'
|
189
|
+
|
190
|
+
check_fhir_context_reference(reference) if reference.present?
|
191
|
+
check_fhir_context_canonical(canonical) if canonical.present?
|
192
|
+
check_fhir_context_identifier(identifier) if identifier.present?
|
193
|
+
|
194
|
+
if (canonical.present? || identifier.present?) && type.blank?
|
195
|
+
info 'The `type` field is recommended when "canonical" or "identifier" is present in `fhirContext` object'
|
196
|
+
end
|
197
|
+
|
198
|
+
next unless type.present?
|
199
|
+
|
200
|
+
assert FHIR_RESOURCE_TYPES.include?(type),
|
201
|
+
"`#{type}` in `type` is not a valid FHIR resource type"
|
202
|
+
end
|
203
|
+
end
|
135
204
|
end
|
136
205
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'token_payload_validation'
|
2
|
+
|
3
|
+
module SMARTAppLaunch
|
4
|
+
class TokenResponseBodyTestSTU22 < TokenResponseBodyTest
|
5
|
+
title 'Token exchange response body contains required information encoded in JSON'
|
6
|
+
description %(
|
7
|
+
The EHR authorization server shall return a JSON structure that includes
|
8
|
+
an access token or a message indicating that the authorization request
|
9
|
+
has been denied. `access_token`, `token_type`, and `scope` are required.
|
10
|
+
`token_type` must be Bearer. `expires_in` is required for token
|
11
|
+
refreshes.
|
12
|
+
|
13
|
+
The format of the optional `fhirContext` field is validated if present.
|
14
|
+
)
|
15
|
+
id :smart_token_response_body_stu2_2
|
16
|
+
|
17
|
+
input :requested_scopes
|
18
|
+
output :id_token,
|
19
|
+
:refresh_token,
|
20
|
+
:access_token,
|
21
|
+
:expires_in,
|
22
|
+
:patient_id,
|
23
|
+
:encounter_id,
|
24
|
+
:received_scopes,
|
25
|
+
:intent
|
26
|
+
uses_request :token
|
27
|
+
|
28
|
+
def validate_fhir_context(fhir_context)
|
29
|
+
validate_fhir_context_stu2_2(fhir_context)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -13,6 +13,7 @@ module SMARTAppLaunch
|
|
13
13
|
input :url,
|
14
14
|
title: 'FHIR Endpoint',
|
15
15
|
description: 'URL of the FHIR endpoint used by SMART applications'
|
16
|
+
|
16
17
|
output :well_known_configuration,
|
17
18
|
:well_known_authorization_url,
|
18
19
|
:well_known_introspection_url,
|
@@ -34,9 +35,12 @@ module SMARTAppLaunch
|
|
34
35
|
base_url = "#{url.chomp('/')}/"
|
35
36
|
config = JSON.parse(request.response_body)
|
36
37
|
|
38
|
+
if config['introspection_endpoint'].present?
|
39
|
+
output well_known_introspection_url: make_url_absolute(base_url, config['introspection_endpoint'])
|
40
|
+
end
|
41
|
+
|
37
42
|
output well_known_configuration: request.response_body,
|
38
43
|
well_known_authorization_url: make_url_absolute(base_url, config['authorization_endpoint']),
|
39
|
-
well_known_introspection_url: make_url_absolute(base_url, config['introspection_endpoint']),
|
40
44
|
well_known_management_url: make_url_absolute(base_url, config['management_endpoint']),
|
41
45
|
well_known_registration_url: make_url_absolute(base_url, config['registration_endpoint']),
|
42
46
|
well_known_revocation_url: make_url_absolute(base_url, config['revocation_endpoint']),
|
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: 0.4.
|
4
|
+
version: 0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen MacVicar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inferno_core
|
@@ -161,6 +161,7 @@ files:
|
|
161
161
|
- lib/smart_app_launch/discovery_stu2_group.rb
|
162
162
|
- lib/smart_app_launch/ehr_launch_group.rb
|
163
163
|
- lib/smart_app_launch/ehr_launch_group_stu2.rb
|
164
|
+
- lib/smart_app_launch/ehr_launch_group_stu2_2.rb
|
164
165
|
- lib/smart_app_launch/jwks.rb
|
165
166
|
- lib/smart_app_launch/launch_received_test.rb
|
166
167
|
- lib/smart_app_launch/openid_connect_group.rb
|
@@ -172,15 +173,29 @@ files:
|
|
172
173
|
- lib/smart_app_launch/openid_token_header_test.rb
|
173
174
|
- lib/smart_app_launch/openid_token_payload_test.rb
|
174
175
|
- lib/smart_app_launch/post_auth.html
|
176
|
+
- lib/smart_app_launch/smart_access_brands_examples/r4_capability_statement.json
|
177
|
+
- lib/smart_app_launch/smart_access_brands_group.rb
|
178
|
+
- lib/smart_app_launch/smart_access_brands_retrieval_group.rb
|
179
|
+
- lib/smart_app_launch/smart_access_brands_retrieve_bundle_test.rb
|
180
|
+
- lib/smart_app_launch/smart_access_brands_suite.rb
|
181
|
+
- lib/smart_app_launch/smart_access_brands_validate_brands_test.rb
|
182
|
+
- lib/smart_app_launch/smart_access_brands_validate_bundle_test.rb
|
183
|
+
- lib/smart_app_launch/smart_access_brands_validate_endpoint_urls_test.rb
|
184
|
+
- lib/smart_app_launch/smart_access_brands_validate_endpoints_test.rb
|
185
|
+
- lib/smart_app_launch/smart_access_brands_validation_group.rb
|
175
186
|
- lib/smart_app_launch/smart_jwks.json
|
176
187
|
- lib/smart_app_launch/smart_stu1_suite.rb
|
188
|
+
- lib/smart_app_launch/smart_stu2_2_suite.rb
|
177
189
|
- lib/smart_app_launch/smart_stu2_suite.rb
|
178
190
|
- lib/smart_app_launch/standalone_launch_group.rb
|
179
191
|
- lib/smart_app_launch/standalone_launch_group_stu2.rb
|
192
|
+
- lib/smart_app_launch/standalone_launch_group_stu2_2.rb
|
180
193
|
- lib/smart_app_launch/token_exchange_stu2_test.rb
|
181
194
|
- lib/smart_app_launch/token_exchange_test.rb
|
182
195
|
- lib/smart_app_launch/token_introspection_access_token_group.rb
|
196
|
+
- lib/smart_app_launch/token_introspection_access_token_group_stu2_2.rb
|
183
197
|
- lib/smart_app_launch/token_introspection_group.rb
|
198
|
+
- lib/smart_app_launch/token_introspection_group_stu2_2.rb
|
184
199
|
- lib/smart_app_launch/token_introspection_request_group.rb
|
185
200
|
- lib/smart_app_launch/token_introspection_response_group.rb
|
186
201
|
- lib/smart_app_launch/token_payload_validation.rb
|
@@ -190,6 +205,7 @@ files:
|
|
190
205
|
- lib/smart_app_launch/token_refresh_stu2_test.rb
|
191
206
|
- lib/smart_app_launch/token_refresh_test.rb
|
192
207
|
- lib/smart_app_launch/token_response_body_test.rb
|
208
|
+
- lib/smart_app_launch/token_response_body_test_stu2_2.rb
|
193
209
|
- lib/smart_app_launch/token_response_headers_test.rb
|
194
210
|
- lib/smart_app_launch/url_helpers.rb
|
195
211
|
- lib/smart_app_launch/version.rb
|