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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/config/presets/inferno_reference_server_preset.json +103 -0
  3. data/config/presets/inferno_reference_server_stu2_2_preset.json +89 -0
  4. data/config/presets/inferno_reference_server_stu2_preset.json +89 -0
  5. data/config/presets/smart_access_brands.json.erb +13 -0
  6. data/config/presets/smart_access_brands_example_1.json +37 -0
  7. data/config/presets/smart_access_brands_example_2.json +37 -0
  8. data/config/presets/smart_access_brands_example_3.json +37 -0
  9. data/config/presets/smart_access_brands_example_4.json +37 -0
  10. data/lib/smart_app_launch/cors_metadata_request_test.rb +40 -0
  11. data/lib/smart_app_launch/cors_openid_fhir_user_claim_test.rb +48 -0
  12. data/lib/smart_app_launch/cors_token_exchange_test.rb +35 -0
  13. data/lib/smart_app_launch/cors_well_known_endpoint_test.rb +40 -0
  14. data/lib/smart_app_launch/discovery_stu2_2_group.rb +12 -0
  15. data/lib/smart_app_launch/ehr_launch_group_stu2_2.rb +14 -0
  16. data/lib/smart_app_launch/metadata.rb +75 -0
  17. data/lib/smart_app_launch/openid_connect_group_stu2_2.rb +40 -0
  18. data/lib/smart_app_launch/smart_access_brands_examples/smart_access_brands_example.json.erb +198 -0
  19. data/lib/smart_app_launch/smart_access_brands_suite.rb +4 -1
  20. data/lib/smart_app_launch/smart_stu1_suite.rb +7 -6
  21. data/lib/smart_app_launch/smart_stu2_2_suite.rb +10 -10
  22. data/lib/smart_app_launch/smart_stu2_suite.rb +11 -10
  23. data/lib/smart_app_launch/standalone_launch_group_stu2_2.rb +14 -0
  24. data/lib/smart_app_launch/token_exchange_stu2_2_test.rb +30 -0
  25. data/lib/smart_app_launch/token_exchange_test.rb +10 -14
  26. data/lib/smart_app_launch/token_introspection_access_token_group_stu2_2.rb +2 -4
  27. data/lib/smart_app_launch/token_introspection_group.rb +1 -2
  28. data/lib/smart_app_launch/token_introspection_group_stu2_2.rb +0 -21
  29. data/lib/smart_app_launch/token_introspection_request_group.rb +47 -36
  30. data/lib/smart_app_launch/token_refresh_test.rb +13 -9
  31. data/lib/smart_app_launch/version.rb +2 -1
  32. data/lib/smart_app_launch_test_kit.rb +1 -0
  33. metadata +26 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 956da1bf90eccfbfda23b793f3870ad7ce7f50fdeaeee25cda93d392fcab8d3b
4
- data.tar.gz: c927a7c94eb03a22b891c244a3349f593dacb4432f2f959da410a0c9dbc293cc
3
+ metadata.gz: 047dcb8643e2524e9bdcd7653db652640f08e672085d18fd589d4a50e717cd08
4
+ data.tar.gz: cf7fe4c64a2e9c9bb9e50bcc2176e7ee5a8c5cac6a970376fb29b8d31e50ca96
5
5
  SHA512:
6
- metadata.gz: 26afb54c26303bd57f5fe9b9005b887b9c37c579a3b7efd95e91e4bb52bbce91db9d39aa16aee8581dbb4f195b69eca82842f616e089575e2eb6b9c8c0915ad0
7
- data.tar.gz: f7b3cc01e93eab4057917bf2a7805f73922b3994a56767e9a012e4cd0ac8a2e03fb1994da35154c5830a4b8c6e458bb5d44987ea6812d09bbb7b3737722a50de
6
+ metadata.gz: 4b0bd4cfc4a2d2db72017cf433482edb59aeb22ea4d538a03a44f14664631d86e9426a4b1b521175673275c7464a0b3f33f673fc488a1b2b9581c5df6a97e7bf
7
+ data.tar.gz: a99702f36d6b8501102cadfca039b0f7b6e46e65e19068da1a52971afee24758228fa59f0c3273c6bad730b47f107d80074e5b222bb9dfd5921c35473e423f1e
@@ -0,0 +1,103 @@
1
+ {
2
+ "title": "Inferno Reference Server",
3
+ "id": "smart_stu1_reference_server",
4
+ "test_suite_id": "smart",
5
+ "inputs": [
6
+ {
7
+ "name": "url",
8
+ "type": "text",
9
+ "value": "https://inferno.healthit.gov/reference-server/r4"
10
+ },
11
+ {
12
+ "name": "standalone_client_id",
13
+ "type": "text",
14
+ "value": "SAMPLE_PUBLIC_CLIENT_ID"
15
+ },
16
+ {
17
+ "name": "standalone_requested_scopes",
18
+ "type": "text",
19
+ "value": "launch/patient openid fhirUser offline_access patient/*.read"
20
+ },
21
+ {
22
+ "name": "use_pkce",
23
+ "type": "radio",
24
+ "title": "Proof Key for Code Exchange (PKCE)",
25
+ "options": {
26
+ "list_options": [
27
+ {
28
+ "label": "Enabled",
29
+ "value": "true"
30
+ },
31
+ {
32
+ "label": "Disabled",
33
+ "value": "false"
34
+ }
35
+ ]
36
+ },
37
+ "value": "false"
38
+ },
39
+ {
40
+ "name": "pkce_code_challenge_method",
41
+ "type": "radio",
42
+ "optional": true,
43
+ "title": "PKCE Code Challenge Method",
44
+ "options": {
45
+ "list_options": [
46
+ {
47
+ "label": "S256",
48
+ "value": "S256"
49
+ },
50
+ {
51
+ "label": "plain",
52
+ "value": "plain"
53
+ }
54
+ ]
55
+ },
56
+ "value": "S256"
57
+ },
58
+ {
59
+ "name": "client_auth_type",
60
+ "value": "public",
61
+ "_title": "Client Authentication Method",
62
+ "_type": "radio",
63
+ "_options": {
64
+ "list_options": [
65
+ {
66
+ "label": "Public",
67
+ "value": "public"
68
+ },
69
+ {
70
+ "label": "Confidential Symmetric",
71
+ "value": "confidential_symmetric"
72
+ },
73
+ {
74
+ "label": "Confidential Asymmetric",
75
+ "value": "confidential_asymmetric"
76
+ }
77
+ ]
78
+ }
79
+ },
80
+ {
81
+ "name": "standalone_client_secret",
82
+ "type": "text",
83
+ "optional": true,
84
+ "value": null
85
+ },
86
+ {
87
+ "name": "ehr_client_id",
88
+ "type": "text",
89
+ "value": "SAMPLE_PUBLIC_CLIENT_ID"
90
+ },
91
+ {
92
+ "name": "ehr_requested_scopes",
93
+ "type": "text",
94
+ "value": "launch openid fhirUser offline_access user/*.read"
95
+ },
96
+ {
97
+ "name": "ehr_client_secret",
98
+ "type": "text",
99
+ "optional": true,
100
+ "value": null
101
+ }
102
+ ]
103
+ }
@@ -0,0 +1,89 @@
1
+ {
2
+ "title": "Inferno Reference Server",
3
+ "id": "smart_stu2_2_reference_server",
4
+ "test_suite_id": "smart_stu2_2",
5
+ "inputs": [
6
+ {
7
+ "name": "url",
8
+ "type": "text",
9
+ "value": "https://inferno.healthit.gov/reference-server/r4"
10
+ },
11
+ {
12
+ "name": "standalone_client_id",
13
+ "type": "text",
14
+ "value": "SAMPLE_PUBLIC_CLIENT_ID"
15
+ },
16
+ {
17
+ "name": "standalone_requested_scopes",
18
+ "type": "text",
19
+ "value": "launch/patient openid fhirUser offline_access patient/*.read"
20
+ },
21
+ {
22
+ "name": "standalone_client_secret",
23
+ "type": "text",
24
+ "optional": true,
25
+ "value": null
26
+ },
27
+ {
28
+ "name": "ehr_client_id",
29
+ "type": "text",
30
+ "value": "SAMPLE_PUBLIC_CLIENT_ID"
31
+ },
32
+ {
33
+ "name": "ehr_requested_scopes",
34
+ "type": "text",
35
+ "value": "launch openid fhirUser offline_access user/*.read"
36
+ },
37
+ {
38
+ "name": "ehr_client_secret",
39
+ "type": "text",
40
+ "optional": true,
41
+ "value": null
42
+ },
43
+ {
44
+ "name": "client_auth_encryption_method",
45
+ "value": "ES384",
46
+ "_title": "Encryption Method (Confidential Asymmetric Client Auth Only)",
47
+ "_type": "radio",
48
+ "_options": {
49
+ "list_options": [
50
+ {
51
+ "label": "ES384",
52
+ "value": "ES384"
53
+ },
54
+ {
55
+ "label": "RS384",
56
+ "value": "RS384"
57
+ }
58
+ ]
59
+ }
60
+ },
61
+ {
62
+ "name": "client_auth_type",
63
+ "value": "public",
64
+ "_title": "Client Authentication Method",
65
+ "_type": "radio",
66
+ "_options": {
67
+ "list_options": [
68
+ {
69
+ "label": "Public",
70
+ "value": "public"
71
+ },
72
+ {
73
+ "label": "Confidential Symmetric",
74
+ "value": "confidential_symmetric"
75
+ },
76
+ {
77
+ "label": "Confidential Asymmetric",
78
+ "value": "confidential_asymmetric"
79
+ }
80
+ ]
81
+ }
82
+ },
83
+ {
84
+ "name": "backend_services_client_id",
85
+ "type": "text",
86
+ "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJlZ2lzdHJhdGlvbi10b2tlbiJ9.eyJqd2tzX3VybCI6Imh0dHA6Ly8xMC4xNS4yNTIuNzMvaW5mZXJuby8ud2VsbC1rbm93bi9qd2tzLmpzb24iLCJhY2Nlc3NUb2tlbnNFeHBpcmVJbiI6MTUsImlhdCI6MTU5NzQxMzE5NX0.q4v4Msc74kN506KTZ0q_minyapJw0gwlT6M_uiL73S4"
87
+ }
88
+ ]
89
+ }
@@ -0,0 +1,89 @@
1
+ {
2
+ "title": "Inferno Reference Server",
3
+ "id": "smart_stu2_reference_server",
4
+ "test_suite_id": "smart_stu2",
5
+ "inputs": [
6
+ {
7
+ "name": "url",
8
+ "type": "text",
9
+ "value": "https://inferno.healthit.gov/reference-server/r4"
10
+ },
11
+ {
12
+ "name": "standalone_client_id",
13
+ "type": "text",
14
+ "value": "SAMPLE_PUBLIC_CLIENT_ID"
15
+ },
16
+ {
17
+ "name": "standalone_requested_scopes",
18
+ "type": "text",
19
+ "value": "launch/patient openid fhirUser offline_access patient/*.read"
20
+ },
21
+ {
22
+ "name": "standalone_client_secret",
23
+ "type": "text",
24
+ "optional": true,
25
+ "value": null
26
+ },
27
+ {
28
+ "name": "ehr_client_id",
29
+ "type": "text",
30
+ "value": "SAMPLE_PUBLIC_CLIENT_ID"
31
+ },
32
+ {
33
+ "name": "ehr_requested_scopes",
34
+ "type": "text",
35
+ "value": "launch openid fhirUser offline_access user/*.read"
36
+ },
37
+ {
38
+ "name": "ehr_client_secret",
39
+ "type": "text",
40
+ "optional": true,
41
+ "value": null
42
+ },
43
+ {
44
+ "name": "client_auth_encryption_method",
45
+ "value": "ES384",
46
+ "_title": "Encryption Method (Confidential Asymmetric Client Auth Only)",
47
+ "_type": "radio",
48
+ "_options": {
49
+ "list_options": [
50
+ {
51
+ "label": "ES384",
52
+ "value": "ES384"
53
+ },
54
+ {
55
+ "label": "RS384",
56
+ "value": "RS384"
57
+ }
58
+ ]
59
+ }
60
+ },
61
+ {
62
+ "name": "client_auth_type",
63
+ "value": "public",
64
+ "_title": "Client Authentication Method",
65
+ "_type": "radio",
66
+ "_options": {
67
+ "list_options": [
68
+ {
69
+ "label": "Public",
70
+ "value": "public"
71
+ },
72
+ {
73
+ "label": "Confidential Symmetric",
74
+ "value": "confidential_symmetric"
75
+ },
76
+ {
77
+ "label": "Confidential Asymmetric",
78
+ "value": "confidential_asymmetric"
79
+ }
80
+ ]
81
+ }
82
+ },
83
+ {
84
+ "name": "backend_services_client_id",
85
+ "type": "text",
86
+ "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJlZ2lzdHJhdGlvbi10b2tlbiJ9.eyJqd2tzX3VybCI6Imh0dHA6Ly8xMC4xNS4yNTIuNzMvaW5mZXJuby8ud2VsbC1rbm93bi9qd2tzLmpzb24iLCJhY2Nlc3NUb2tlbnNFeHBpcmVJbiI6MTUsImlhdCI6MTU5NzQxMzE5NX0.q4v4Msc74kN506KTZ0q_minyapJw0gwlT6M_uiL73S4"
87
+ }
88
+ ]
89
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "title": "Inferno Example SMART Access Brands Bundle",
3
+ "id": "smart_access_brands_bundle_example_inferno",
4
+ "test_suite_id": "smart_access_brands",
5
+ "inputs": [
6
+ {
7
+ "name": "smart_access_brands_publication_url",
8
+ "value": "<%= Inferno::Application['base_url'] %>/custom/smart_access_brands/examples/smart_access_brands_example.json",
9
+ "title": "SMART Access Brands Bundle URL",
10
+ "type": "text"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "title": "Labs with Locations Nationwide IG Example SMART Access Brands Bundle",
3
+ "id": "smart_access_brands_bundle_example_1",
4
+ "test_suite_id": "smart_access_brands",
5
+ "inputs": [
6
+ {
7
+ "name": "user_access_brands_publication_url",
8
+ "value": "https://hl7.org/fhir/smart-app-launch/STU2.2/Bundle-example1.json",
9
+ "title": "User Access Brands Publication URL",
10
+ "type": "text"
11
+ },
12
+ {
13
+ "name": "endpoint_availability_success_rate",
14
+ "default": "all",
15
+ "description": "Select an option to choose how many Endpoints have to be available and send back a valid capability statement for the Endpoint validation test to pass.",
16
+ "options": {
17
+ "list_options": [
18
+ {
19
+ "label": "All",
20
+ "value": "all"
21
+ },
22
+ {
23
+ "label": "At Least 1",
24
+ "value": "at_least_1"
25
+ },
26
+ {
27
+ "label": "None",
28
+ "value": "none"
29
+ }
30
+ ]
31
+ },
32
+ "title": "Endpoint Availability Success Rate",
33
+ "type": "radio",
34
+ "value": "none"
35
+ }
36
+ ]
37
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "title": "Regional Health System IG Example SMART Access Brands Bundle",
3
+ "id": "smart_access_brands_bundle_example_2",
4
+ "test_suite_id": "smart_access_brands",
5
+ "inputs": [
6
+ {
7
+ "name": "user_access_brands_publication_url",
8
+ "value": "https://hl7.org/fhir/smart-app-launch/STU2.2/Bundle-example2.json",
9
+ "title": "User Access Brands Publication URL",
10
+ "type": "text"
11
+ },
12
+ {
13
+ "name": "endpoint_availability_success_rate",
14
+ "default": "all",
15
+ "description": "Select an option to choose how many Endpoints have to be available and send back a valid capability statement for the Endpoint validation test to pass.",
16
+ "options": {
17
+ "list_options": [
18
+ {
19
+ "label": "All",
20
+ "value": "all"
21
+ },
22
+ {
23
+ "label": "At Least 1",
24
+ "value": "at_least_1"
25
+ },
26
+ {
27
+ "label": "None",
28
+ "value": "none"
29
+ }
30
+ ]
31
+ },
32
+ "title": "Endpoint Availability Success Rate",
33
+ "type": "radio",
34
+ "value": "none"
35
+ }
36
+ ]
37
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "title": "Different EHRs IG Example SMART Access Brands Bundle",
3
+ "id": "smart_access_brands_bundle_example_3",
4
+ "test_suite_id": "smart_access_brands",
5
+ "inputs": [
6
+ {
7
+ "name": "user_access_brands_publication_url",
8
+ "value": "https://hl7.org/fhir/smart-app-launch/STU2.2/Bundle-example3.json",
9
+ "title": "User Access Brands Publication URL",
10
+ "type": "text"
11
+ },
12
+ {
13
+ "name": "endpoint_availability_success_rate",
14
+ "default": "all",
15
+ "description": "Select an option to choose how many Endpoints have to be available and send back a valid capability statement for the Endpoint validation test to pass.",
16
+ "options": {
17
+ "list_options": [
18
+ {
19
+ "label": "All",
20
+ "value": "all"
21
+ },
22
+ {
23
+ "label": "At Least 1",
24
+ "value": "at_least_1"
25
+ },
26
+ {
27
+ "label": "None",
28
+ "value": "none"
29
+ }
30
+ ]
31
+ },
32
+ "title": "Endpoint Availability Success Rate",
33
+ "type": "radio",
34
+ "value": "none"
35
+ }
36
+ ]
37
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "title": "Co-equal Brands IG Example SMART Access Brands Bundle",
3
+ "id": "smart_access_brands_bundle_example_4",
4
+ "test_suite_id": "smart_access_brands",
5
+ "inputs": [
6
+ {
7
+ "name": "user_access_brands_publication_url",
8
+ "value": "https://hl7.org/fhir/smart-app-launch/STU2.2/Bundle-example4.json",
9
+ "title": "User Access Brands Publication URL",
10
+ "type": "text"
11
+ },
12
+ {
13
+ "name": "endpoint_availability_success_rate",
14
+ "default": "all",
15
+ "description": "Select an option to choose how many Endpoints have to be available and send back a valid capability statement for the Endpoint validation test to pass.",
16
+ "options": {
17
+ "list_options": [
18
+ {
19
+ "label": "All",
20
+ "value": "all"
21
+ },
22
+ {
23
+ "label": "At Least 1",
24
+ "value": "at_least_1"
25
+ },
26
+ {
27
+ "label": "None",
28
+ "value": "none"
29
+ }
30
+ ]
31
+ },
32
+ "title": "Endpoint Availability Success Rate",
33
+ "type": "radio",
34
+ "value": "none"
35
+ }
36
+ ]
37
+ }
@@ -0,0 +1,40 @@
1
+ require_relative 'url_helpers'
2
+
3
+ module SMARTAppLaunch
4
+ class CORSMetadataRequest < Inferno::Test
5
+ id :smart_cors_metadata_request
6
+
7
+ include URLHelpers
8
+
9
+ title 'SMART metadata Endpoint Enables Cross-Origin Resource Sharing (CORS)'
10
+ description %(
11
+ The SMART [Considerations for Cross-Origin Resource Sharing (CORS) support](http://hl7.org/fhir/smart-app-launch/STU2.2/app-launch.html#considerations-for-cross-origin-resource-sharing-cors-support)
12
+ specifies that servers that support purely browser-based apps SHALL enable Cross-Origin Resource Sharing (CORS)
13
+ as follows:
14
+
15
+ - For requests from any origin, CORS configuration permits access to the public discovery endpoints
16
+ (.well-known/smart-configuration and metadata).
17
+
18
+ This test verifies that the metadata request is returned with the appropriate CORS header.
19
+ )
20
+ optional
21
+
22
+ input :url
23
+
24
+ fhir_client do
25
+ url :url
26
+ headers 'Origin' => Inferno::Application['inferno_host']
27
+ end
28
+
29
+ run do
30
+ fhir_get_capability_statement
31
+
32
+ assert_response_status(200)
33
+ inferno_origin = Inferno::Application['inferno_host']
34
+ cors_allow_origin = request.response_header('Access-Control-Allow-Origin')&.value
35
+ assert cors_allow_origin.present?, 'No `Access-Control-Allow-Origin` header received.'
36
+ assert cors_allow_origin == inferno_origin || cors_allow_origin == '*',
37
+ "`Access-Control-Allow-Origin` must be `#{inferno_origin}`, but received: `#{cors_allow_origin}`"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,48 @@
1
+ module SMARTAppLaunch
2
+ class CORSOpenIDFHIRUserClaimTest < Inferno::Test
3
+ id :smart_cors_openid_fhir_user_claim
4
+ title 'SMART FHIR User REST API Endpoint Enables Cross-Origin Resource Sharing (CORS)'
5
+ description %(
6
+ The SMART [Considerations for Cross-Origin Resource Sharing (CORS) support](http://hl7.org/fhir/smart-app-launch/STU2.2/app-launch.html#considerations-for-cross-origin-resource-sharing-cors-support)
7
+ specifies that servers that support purely browser-based apps SHALL enable Cross-Origin Resource Sharing (CORS)
8
+ as follows:
9
+
10
+ - For requests from a client's registered origin(s), CORS configuration permits access to the token
11
+ endpoint and to FHIR REST API endpoints.
12
+
13
+ This test verifies that a request to the FHIR REST API endpoint for the FHIR user is returned with the appropriate
14
+ CORS header.
15
+ )
16
+ optional
17
+
18
+ input :url, :id_token_fhir_user
19
+ input :smart_credentials, type: :oauth_credentials
20
+
21
+ fhir_client do
22
+ url :url
23
+ oauth_credentials :smart_credentials
24
+ headers 'Origin' => Inferno::Application['inferno_host']
25
+ end
26
+
27
+ run do
28
+ valid_fhir_user_resource_types = ['Patient', 'Practitioner', 'RelatedPerson', 'Person']
29
+
30
+ fhir_user_segments = id_token_fhir_user.split('/')
31
+ fhir_user_resource_type = fhir_user_segments[-2]
32
+ fhir_user_id = fhir_user_segments.last
33
+
34
+ assert valid_fhir_user_resource_types.include?(fhir_user_resource_type),
35
+ "ID token `fhirUser` claim does not refer to a valid resource type: #{id_token_fhir_user}"
36
+
37
+ fhir_read(fhir_user_resource_type, fhir_user_id)
38
+
39
+ assert_response_status(200)
40
+
41
+ inferno_origin = Inferno::Application['inferno_host']
42
+ cors_allow_origin = request.response_header('Access-Control-Allow-Origin')&.value
43
+ assert cors_allow_origin.present?, 'No `Access-Control-Allow-Origin` header received.'
44
+ assert cors_allow_origin == inferno_origin || cors_allow_origin == '*',
45
+ "`Access-Control-Allow-Origin` must be `#{inferno_origin}`, but received: `#{cors_allow_origin}`"
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ module SMARTAppLaunch
2
+ class CORSTokenExchangeTest < Inferno::Test
3
+ title 'SMART Token Endpoint Enables Cross-Origin Resource Sharing (CORS)'
4
+ description %(
5
+ The SMART [Considerations for Cross-Origin Resource Sharing (CORS) support](http://hl7.org/fhir/smart-app-launch/STU2.2/app-launch.html#considerations-for-cross-origin-resource-sharing-cors-support)
6
+ specifies that servers that support purely browser-based apps SHALL enable Cross-Origin Resource Sharing (CORS)
7
+ as follows:
8
+
9
+ - For requests from a client's registered origin(s), CORS configuration permits access to the token
10
+ endpoint
11
+
12
+ This test verifies that the token endpoint contains the appropriate CORS header in the response.
13
+ )
14
+ id :smart_cors_token_exchange
15
+
16
+ uses_request :cors_token_request
17
+
18
+ input :client_auth_type
19
+
20
+ run do
21
+ omit_if client_auth_type != 'public', %(
22
+ Client type is not public, Cross-Origin Resource Sharing (CORS) is not required to be supported for
23
+ non-public client types
24
+ )
25
+
26
+ skip_if request.status != 200, 'Previous request was unsuccessful, cannot check for CORS support'
27
+
28
+ inferno_origin = Inferno::Application['inferno_host']
29
+ cors_header = request.response_header('Access-Control-Allow-Origin')&.value
30
+
31
+ assert cors_header == inferno_origin || cors_header == '*',
32
+ "Request must have `Access-Control-Allow-Origin` header containing `#{inferno_origin}`"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ require_relative 'url_helpers'
2
+
3
+ module SMARTAppLaunch
4
+ class CORSWellKnownEndpointTest < Inferno::Test
5
+ include URLHelpers
6
+
7
+ title 'SMART .well-known/smart-configuration Endpoint Enables Cross-Origin Resource Sharing (CORS)'
8
+ id :smart_cors_well_known_endpoint
9
+ description %(
10
+ The SMART [Considerations for Cross-Origin Resource Sharing (CORS) support](http://hl7.org/fhir/smart-app-launch/STU2.2/app-launch.html#considerations-for-cross-origin-resource-sharing-cors-support)
11
+ specifies that servers that support purely browser-based apps SHALL enable Cross-Origin Resource Sharing (CORS)
12
+ as follows:
13
+
14
+ - For requests from any origin, CORS configuration permits access to the public discovery endpoints
15
+ (.well-known/smart-configuration and metadata).
16
+
17
+ This test verifies that the .well-known/smart-configuration request is returned with the appropriate CORS header.
18
+ )
19
+ optional
20
+
21
+ input :url,
22
+ title: 'FHIR Endpoint',
23
+ description: 'URL of the FHIR endpoint used by SMART applications'
24
+
25
+ run do
26
+ well_known_configuration_url = "#{url.chomp('/')}/.well-known/smart-configuration"
27
+ inferno_origin = Inferno::Application['inferno_host']
28
+
29
+ get(well_known_configuration_url,
30
+ headers: { 'Accept' => 'application/json',
31
+ 'Origin' => inferno_origin })
32
+ assert_response_status(200)
33
+
34
+ cors_allow_origin = request.response_header('Access-Control-Allow-Origin')&.value
35
+ assert cors_allow_origin.present?, 'No `Access-Control-Allow-Origin` header received.'
36
+ assert cors_allow_origin == inferno_origin || cors_allow_origin == '*',
37
+ "`Access-Control-Allow-Origin` must be `#{inferno_origin}`, but received: `#{cors_allow_origin}`"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'cors_metadata_request_test'
2
+ require_relative 'cors_well_known_endpoint_test'
3
+ require_relative 'discovery_stu2_group'
4
+
5
+ module SMARTAppLaunch
6
+ class DiscoverySTU22Group < DiscoverySTU2Group
7
+ id :smart_discovery_stu2_2
8
+
9
+ test from: :smart_cors_well_known_endpoint
10
+ test from: :smart_cors_metadata_request
11
+ end
12
+ end
@@ -1,5 +1,7 @@
1
1
  require_relative 'ehr_launch_group_stu2'
2
2
  require_relative 'token_response_body_test_stu2_2'
3
+ require_relative 'cors_token_exchange_test'
4
+ require_relative 'token_exchange_stu2_2_test'
3
5
 
4
6
  module SMARTAppLaunch
5
7
  class EHRLaunchGroupSTU22 < EHRLaunchGroupSTU2
@@ -46,9 +48,21 @@ module SMARTAppLaunch
46
48
  }
47
49
  )
48
50
 
51
+ test from: :smart_token_exchange_stu2_2
52
+
53
+ token_exchange_index = children.find_index { |child| child.id.to_s.end_with? 'smart_token_exchange' }
54
+ children[token_exchange_index] = children.pop
55
+
49
56
  test from: :smart_token_response_body_stu2_2
50
57
 
51
58
  token_response_body_index = children.find_index { |child| child.id.to_s.end_with? 'token_response_body' }
52
59
  children[token_response_body_index] = children.pop
60
+
61
+ test from: :smart_cors_token_exchange,
62
+ config: {
63
+ requests: {
64
+ cors_token_request: { name: :ehr_token }
65
+ }
66
+ }
53
67
  end
54
68
  end