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.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 047dcb8643e2524e9bdcd7653db652640f08e672085d18fd589d4a50e717cd08
|
4
|
+
data.tar.gz: cf7fe4c64a2e9c9bb9e50bcc2176e7ee5a8c5cac6a970376fb29b8d31e50ca96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|