smart_app_launch_test_kit 0.1.0 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/smart_app_launch/app_redirect_test.rb +24 -17
- data/lib/smart_app_launch/discovery_group.rb +2 -2
- data/lib/smart_app_launch/ehr_launch_group.rb +2 -2
- data/lib/smart_app_launch/openid_connect_group.rb +4 -4
- data/lib/smart_app_launch/openid_required_configuration_fields_test.rb +1 -1
- data/lib/smart_app_launch/openid_token_header_test.rb +2 -2
- data/lib/smart_app_launch/openid_token_payload_test.rb +6 -1
- data/lib/smart_app_launch/standalone_launch_group.rb +3 -3
- data/lib/smart_app_launch/token_payload_validation.rb +6 -0
- data/lib/smart_app_launch/token_refresh_body_test.rb +3 -2
- data/lib/smart_app_launch/token_refresh_group.rb +3 -3
- data/lib/smart_app_launch/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 758773637de38a995aa7943da1291685f655e97f829c2e11d7adfc54d129ad42
|
4
|
+
data.tar.gz: b0c2adfcf695418617999e414a0d85766e440e943787d811ffb54218810fee2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b9aabc2d05bf3b3a3fe49f35fe0be2e634f7c774d86d3d6a0129aa1cd424f1c5cebd03c84c24855445a0baf95ac23c730d614e9f628a946b5ac8d5ca0b6f8fa
|
7
|
+
data.tar.gz: b287eaf62940d60d904af996c0cbbd90d59ba68ce79cdbe6400a20515b9eccb6aa0ff6c094bd07cfd86b928a11c3b6e7e740c896d125c62f5da65a857450ed38
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
1
3
|
module SMARTAppLaunch
|
2
4
|
class AppRedirectTest < Inferno::Test
|
3
5
|
title 'OAuth server redirects client browser to app redirect URI'
|
@@ -63,8 +65,18 @@ module SMARTAppLaunch
|
|
63
65
|
)
|
64
66
|
end
|
65
67
|
|
68
|
+
def authorization_url_builder(url, params)
|
69
|
+
uri = URI(url)
|
70
|
+
|
71
|
+
# because the URL might have paramters on it
|
72
|
+
original_parameters = Hash[URI.decode_www_form(uri.query || '')]
|
73
|
+
new_params = original_parameters.merge(params)
|
74
|
+
|
75
|
+
uri.query = URI.encode_www_form(new_params)
|
76
|
+
uri.to_s
|
77
|
+
end
|
78
|
+
|
66
79
|
run do
|
67
|
-
info(config.options[:redirect_uri])
|
68
80
|
assert_valid_http_uri(
|
69
81
|
smart_authorization_url,
|
70
82
|
"OAuth2 Authorization Endpoint '#{smart_authorization_url}' is not a valid URI"
|
@@ -81,10 +93,15 @@ module SMARTAppLaunch
|
|
81
93
|
'aud' => aud
|
82
94
|
}
|
83
95
|
|
84
|
-
|
96
|
+
if config.options[:launch]
|
97
|
+
oauth2_params['launch'] = config.options[:launch]
|
98
|
+
elsif self.class.inputs.include?(:launch)
|
99
|
+
oauth2_params['launch'] = launch
|
100
|
+
end
|
85
101
|
|
86
102
|
if use_pkce == 'true'
|
87
|
-
|
103
|
+
# code verifier must be between 43 and 128 characters
|
104
|
+
code_verifier = SecureRandom.uuid + '-' + SecureRandom.uuid
|
88
105
|
code_challenge =
|
89
106
|
if pkce_code_challenge_method == 'S256'
|
90
107
|
self.class.calculate_s256_challenge(code_verifier)
|
@@ -97,20 +114,10 @@ module SMARTAppLaunch
|
|
97
114
|
oauth2_params.merge!('code_challenge' => code_challenge, 'code_challenge_method' => pkce_code_challenge_method)
|
98
115
|
end
|
99
116
|
|
100
|
-
authorization_url =
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
'&'
|
105
|
-
else
|
106
|
-
'?'
|
107
|
-
end
|
108
|
-
|
109
|
-
oauth2_params.each do |key, value|
|
110
|
-
authorization_url += "#{key}=#{CGI.escape(value)}&"
|
111
|
-
end
|
112
|
-
|
113
|
-
authorization_url.chomp!('&')
|
117
|
+
authorization_url = authorization_url_builder(
|
118
|
+
smart_authorization_url,
|
119
|
+
oauth2_params
|
120
|
+
)
|
114
121
|
|
115
122
|
wait(
|
116
123
|
identifier: state,
|
@@ -8,7 +8,7 @@ module SMARTAppLaunch
|
|
8
8
|
|
9
9
|
The #{title} Sequence test looks for authorization endpoints and SMART
|
10
10
|
capabilities as described by the [SMART App Launch
|
11
|
-
Framework](
|
11
|
+
Framework](https://www.hl7.org/fhir/smart-app-launch/1.0.0/conformance/index.html).
|
12
12
|
The SMART launch framework uses OAuth 2.0 to *authorize* apps, like
|
13
13
|
Inferno, to access certain information on a FHIR server. The
|
14
14
|
authorization service accessed at the endpoint allows users to give
|
@@ -31,7 +31,7 @@ module SMARTAppLaunch
|
|
31
31
|
|
32
32
|
For more information see:
|
33
33
|
|
34
|
-
* [SMART App Launch Framework](
|
34
|
+
* [SMART App Launch Framework](https://www.hl7.org/fhir/smart-app-launch/1.0.0/conformance/index.html)
|
35
35
|
* [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749)
|
36
36
|
* [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html)
|
37
37
|
)
|
@@ -16,7 +16,7 @@ module SMARTAppLaunch
|
|
16
16
|
# Background
|
17
17
|
|
18
18
|
The [EHR
|
19
|
-
Launch](
|
19
|
+
Launch](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html#ehr-launch-sequence)
|
20
20
|
is one of two ways in which an app can be launched, the other being
|
21
21
|
Standalone launch. In an EHR launch, the app is launched from an
|
22
22
|
existing EHR session or portal by a redirect to the registered launch
|
@@ -35,7 +35,7 @@ module SMARTAppLaunch
|
|
35
35
|
|
36
36
|
For more information on the #{title} see:
|
37
37
|
|
38
|
-
* [SMART EHR Launch Sequence](
|
38
|
+
* [SMART EHR Launch Sequence](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html#ehr-launch-sequence)
|
39
39
|
)
|
40
40
|
|
41
41
|
config(
|
@@ -18,7 +18,7 @@ module SMARTAppLaunch
|
|
18
18
|
|
19
19
|
OpenID Connect (OIDC) provides the ability to verify the identity of the
|
20
20
|
authorizing user. Within the [SMART App Launch
|
21
|
-
Framework](
|
21
|
+
Framework](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html), Applications can
|
22
22
|
request an `id_token` be provided with by including the `openid fhirUser`
|
23
23
|
scopes when requesting authorization.
|
24
24
|
|
@@ -36,9 +36,9 @@ module SMARTAppLaunch
|
|
36
36
|
|
37
37
|
For more information see:
|
38
38
|
|
39
|
-
* [SMART App Launch Framework](
|
40
|
-
* [Scopes for requesting identity data](
|
41
|
-
* [Apps Requesting Authorization](
|
39
|
+
* [SMART App Launch Framework](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html)
|
40
|
+
* [Scopes for requesting identity data](https://www.hl7.org/fhir/smart-app-launch/1.0.0/scopes-and-launch-context/index.html#scopes-for-requesting-identity-data)
|
41
|
+
* [Apps Requesting Authorization](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html#step-1-app-asks-for-authorization)
|
42
42
|
* [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html)
|
43
43
|
)
|
44
44
|
|
@@ -9,7 +9,7 @@ module SMARTAppLaunch
|
|
9
9
|
`id_token_signing_alg_values_supported`.
|
10
10
|
|
11
11
|
Additionally, the [SMART App Launch
|
12
|
-
Framework](
|
12
|
+
Framework](https://www.hl7.org/fhir/smart-app-launch/1.0.0/scopes-and-launch-context/index.html#scopes-for-requesting-identity-data)
|
13
13
|
requires that the RSA SHA-256 signing algorithm be supported.
|
14
14
|
)
|
15
15
|
|
@@ -3,9 +3,9 @@ module SMARTAppLaunch
|
|
3
3
|
id :smart_openid_token_header
|
4
4
|
title 'ID token header contains required information'
|
5
5
|
description %(
|
6
|
-
Verify that the id token header indicates that the
|
6
|
+
Verify that the id token header indicates that the token is signed using
|
7
7
|
RSA SHA-256 [as required by the SMART app launch
|
8
|
-
framework](
|
8
|
+
framework](https://www.hl7.org/fhir/smart-app-launch/1.0.0/scopes-and-launch-context/index.html#scopes-for-requesting-identity-data)
|
9
9
|
and that the key used to sign the token can be identified in the JWKS.
|
10
10
|
)
|
11
11
|
|
@@ -13,6 +13,7 @@ module SMARTAppLaunch
|
|
13
13
|
configuration
|
14
14
|
- `aud` must match the client ID
|
15
15
|
- `exp` must represent a time in the future
|
16
|
+
- `sub` must be a non-blank string not exceeding 255 characters in length
|
16
17
|
)
|
17
18
|
|
18
19
|
REQUIRED_CLAIMS = ['iss', 'sub', 'aud', 'exp', 'iat'].freeze
|
@@ -47,7 +48,7 @@ module SMARTAppLaunch
|
|
47
48
|
verify_not_before: false,
|
48
49
|
verify_iat: false,
|
49
50
|
verify_jti: false,
|
50
|
-
verify_sub:
|
51
|
+
verify_sub: true,
|
51
52
|
verify_iss: true,
|
52
53
|
verify_aud: true
|
53
54
|
)
|
@@ -55,6 +56,10 @@ module SMARTAppLaunch
|
|
55
56
|
assert false, "Token validation error: #{e.message}"
|
56
57
|
end
|
57
58
|
|
59
|
+
sub_value = payload['sub']
|
60
|
+
assert !sub_value.blank?, "ID token `sub` claim is blank"
|
61
|
+
assert sub_value.length < 256, "ID token `sub` claim exceeds 255 characters in length"
|
62
|
+
|
58
63
|
missing_claims = required_claims - payload.keys
|
59
64
|
missing_claims_string = missing_claims.map { |claim| "`#{claim}`" }.join(', ')
|
60
65
|
|
@@ -14,8 +14,8 @@ module SMARTAppLaunch
|
|
14
14
|
# Background
|
15
15
|
|
16
16
|
The [Standalone
|
17
|
-
Launch](
|
18
|
-
|
17
|
+
Launch Sequence](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html#standalone-launch-sequence)
|
18
|
+
allows an app, like Inferno, to be launched independent of an
|
19
19
|
existing EHR session. It is one of the two launch methods described in
|
20
20
|
the SMART App Launch Framework alongside EHR Launch. The app will
|
21
21
|
request authorization for the provided scope from the authorization
|
@@ -31,7 +31,7 @@ module SMARTAppLaunch
|
|
31
31
|
|
32
32
|
For more information on the #{title}:
|
33
33
|
|
34
|
-
* [Standalone Launch Sequence](
|
34
|
+
* [Standalone Launch Sequence](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html#standalone-launch-sequence)
|
35
35
|
)
|
36
36
|
|
37
37
|
config(
|
@@ -28,6 +28,12 @@ module SMARTAppLaunch
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
def validate_scope_subset(received_scopes, original_scopes)
|
32
|
+
extra_scopes = received_scopes.split - original_scopes.split
|
33
|
+
assert extra_scopes.empty?, "Token response contained scopes which are not a subset of the scope granted to the "\
|
34
|
+
"original access token: #{extra_scopes.join(', ')}"
|
35
|
+
end
|
36
|
+
|
31
37
|
def validate_token_field_types(body)
|
32
38
|
STRING_FIELDS
|
33
39
|
.select { |field| body[field].present? }
|
@@ -11,6 +11,8 @@ module SMARTAppLaunch
|
|
11
11
|
an access token or a message indicating that the authorization request
|
12
12
|
has been denied. `access_token`, `expires_in`, `token_type`, and `scope` are
|
13
13
|
required. `access_token` must be `Bearer`.
|
14
|
+
|
15
|
+
Scopes returned must be a strict subset of the scopes granted in the original launch.
|
14
16
|
)
|
15
17
|
input :received_scopes
|
16
18
|
output :refresh_token, :access_token, :token_retrieval_time, :expires_in, :received_scopes
|
@@ -36,8 +38,7 @@ module SMARTAppLaunch
|
|
36
38
|
validate_token_field_types(body)
|
37
39
|
validate_token_type(body)
|
38
40
|
|
39
|
-
|
40
|
-
'Received scopes not equal to originally granted scopes'
|
41
|
+
validate_scope_subset(received_scopes, old_received_scopes)
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
@@ -10,7 +10,7 @@ module SMARTAppLaunch
|
|
10
10
|
description %(
|
11
11
|
# Background
|
12
12
|
|
13
|
-
The #{title} Sequence tests the ability of the system to
|
13
|
+
The #{title} Sequence tests the ability of the system to successfully
|
14
14
|
exchange a refresh token for an access token. Refresh tokens are typically
|
15
15
|
longer lived than access tokens and allow client applications to obtain a
|
16
16
|
new access token Refresh tokens themselves cannot provide access to
|
@@ -18,7 +18,7 @@ module SMARTAppLaunch
|
|
18
18
|
|
19
19
|
Token refreshes are accomplished through a `POST` request to the token
|
20
20
|
exchange endpoint as described in the [SMART App Launch
|
21
|
-
Framework](
|
21
|
+
Framework](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html#step-5-later-app-uses-a-refresh-token-to-obtain-a-new-access-token).
|
22
22
|
|
23
23
|
# Test Methodology
|
24
24
|
|
@@ -31,7 +31,7 @@ module SMARTAppLaunch
|
|
31
31
|
* [The OAuth 2.0 Authorization
|
32
32
|
Framework](https://tools.ietf.org/html/rfc6749)
|
33
33
|
* [Using a refresh token to obtain a new access
|
34
|
-
token](
|
34
|
+
token](https://www.hl7.org/fhir/smart-app-launch/1.0.0/index.html#step-5-later-app-uses-a-refresh-token-to-obtain-a-new-access-token)
|
35
35
|
)
|
36
36
|
|
37
37
|
test from: :smart_token_refresh
|
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.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen MacVicar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inferno_core
|