smart_app_launch_test_kit 0.4.5 → 0.5.0

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