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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7da125d1c3d1b6665088989e563aa9a046fc9e651ab3b1616e153cee1d695a6e
4
- data.tar.gz: 329bf68903d2b72988bfbdd1c0525ec1a933c5450b285fc001c4d28d44552f2f
3
+ metadata.gz: 758773637de38a995aa7943da1291685f655e97f829c2e11d7adfc54d129ad42
4
+ data.tar.gz: b0c2adfcf695418617999e414a0d85766e440e943787d811ffb54218810fee2c
5
5
  SHA512:
6
- metadata.gz: '081f7d57660ef9446376fd1fd07753b00014258f9162b3ffc14f57165caa4ca255d3dc970483b30236a7fd9bbfec49c0bda9becb6c3a20f6805e679b6fc24814'
7
- data.tar.gz: ee1f2ea1d9b75980516d2098528b229eabbacea1fc305c1242aacff60e1fbd7bf06a2d7b98788f313c000492264e9f5ef79b120ebeb0bd7e7e124e3147a48a47
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
- oauth2_params['launch'] = launch if self.class.inputs.include?(:launch)
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
- code_verifier = SecureRandom.uuid
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 = smart_authorization_url
101
-
102
- authorization_url +=
103
- if authorization_url.include? '?'
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](http://hl7.org/fhir/smart-app-launch/conformance/index.html).
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](http://hl7.org/fhir/smart-app-launch/index.html)
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](http://hl7.org/fhir/smart-app-launch/index.html#ehr-launch-sequence)
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](http://hl7.org/fhir/smart-app-launch/index.html#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](http://hl7.org/fhir/smart-app-launch/), Applications can
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](http://hl7.org/fhir/smart-app-launch/)
40
- * [Scopes for requesting identity data](http://hl7.org/fhir/smart-app-launch/scopes-and-launch-context/index.html#scopes-for-requesting-identity-data)
41
- * [Apps Requesting Authorization](http://hl7.org/fhir/smart-app-launch/#step-1-app-asks-for-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](http://www.hl7.org/fhir/smart-app-launch/scopes-and-launch-context/index.html#scopes-for-requesting-identity-data)
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 tokenis signed using
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](http://www.hl7.org/fhir/smart-app-launch/scopes-and-launch-context/index.html#scopes-for-requesting-identity-data)
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: false,
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](http://hl7.org/fhir/smart-app-launch/#standalone-launch-sequence)
18
- Sequence allows an app, like Inferno, to be launched independent of an
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](http://hl7.org/fhir/smart-app-launch/#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
- assert received_scopes.split.sort == old_received_scopes.split.sort,
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 successfuly
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](http://www.hl7.org/fhir/smart-app-launch/#step-5-later-app-uses-a-refresh-token-to-obtain-a-new-access-token).
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](http://hl7.org/fhir/smart-app-launch/#step-5-later-app-uses-a-refresh-token-to-obtain-a-new-access-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
@@ -1,3 +1,3 @@
1
1
  module SMARTAppLaunch
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.3'
3
3
  end
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.0
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-02-28 00:00:00.000000000 Z
11
+ date: 2022-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inferno_core