smart_app_launch_test_kit 0.2.2 → 0.3.0

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: 99071ac48c50bc9184c429d8ac6d6a82c257a62b543b0300ffce76bb5428cd3e
4
- data.tar.gz: 96ab8b622c5bcdbb803f38bb3fac3b954e09ed509ca50eb498fcb33a6f8a50a5
3
+ metadata.gz: 97f3e4dca10ecb9dfe4aa30802d90f4272dd32ffd10715fa7b3a0855a04b5c8d
4
+ data.tar.gz: 016a700551ef524e7bdc7f8871beb03f7297dc3cba39e5b4b53349b22f22ed53
5
5
  SHA512:
6
- metadata.gz: 5ecbf51ed63307f358311b3e14b63827a1653a0697f79b3d85333577b72109eda60721cdf1a26acda174a0099df2ac3f710bb4371429789dab51744a23375915
7
- data.tar.gz: d79ef7288453f232d1b4365dc271cabcc84436e94c8c5c0a02b7554521b16f05c0291eda15093a118fc8aa909577043ce5bb0ef0919c97d6abde81dcb6195bd5
6
+ metadata.gz: 519d2bb8c5bde6a7c5c28f04ec17bfdcff37c7270b6216707a05db4b04c94269d244c6a1888dd97a0c25c5a50764d4969a08c2774dcb636db7fd274301184427
7
+ data.tar.gz: eda1f5484f72de3a82c34eb1d0424a2b10a327baeb93d6e6df8f94be7a7e3ef378e5e6510378f62e7d9387e56424b42b52f4524fc557302d3a5ddab0654c782e
@@ -126,6 +126,8 @@ module SMARTAppLaunch
126
126
  oauth2_params
127
127
  )
128
128
 
129
+ info("Inferno redirecting browser to #{authorization_url}.")
130
+
129
131
  wait(
130
132
  identifier: state,
131
133
  message: wait_message(authorization_url)
@@ -0,0 +1,63 @@
1
+ require 'jwt'
2
+
3
+ require_relative 'jwks'
4
+
5
+ module SMARTAppLaunch
6
+ class ClientAssertionBuilder
7
+ def self.build(...)
8
+ new(...).client_assertion
9
+ end
10
+
11
+ attr_reader :aud,
12
+ :client_assertion_type,
13
+ :content_type,
14
+ :client_auth_encryption_method,
15
+ :exp,
16
+ :grant_type,
17
+ :iss,
18
+ :jti,
19
+ :sub
20
+
21
+ def initialize(
22
+ client_auth_encryption_method:,
23
+ iss:,
24
+ sub:,
25
+ aud:,
26
+ exp: 5.minutes.from_now.to_i,
27
+ jti: SecureRandom.hex(32)
28
+ )
29
+ @client_auth_encryption_method = client_auth_encryption_method
30
+ @iss = iss
31
+ @sub = sub
32
+ @aud = aud
33
+ @content_type = content_type
34
+ @grant_type = grant_type
35
+ @client_assertion_type = client_assertion_type
36
+ @exp = exp
37
+ @jti = jti
38
+ end
39
+
40
+ def private_key
41
+ @private_key ||=
42
+ JWKS.jwks
43
+ .find { |key| key[:key_ops]&.include?('sign') && key[:alg] == client_auth_encryption_method }
44
+ end
45
+
46
+ def jwt_payload
47
+ { iss:, sub:, aud:, exp:, jti: }.compact
48
+ end
49
+
50
+ def kid
51
+ private_key.kid
52
+ end
53
+
54
+ def signing_key
55
+ private_key.signing_key
56
+ end
57
+
58
+ def client_assertion
59
+ @client_assertion ||=
60
+ JWT.encode jwt_payload, signing_key, client_auth_encryption_method, { alg: client_auth_encryption_method, kid:, typ: 'JWT' }
61
+ end
62
+ end
63
+ end
@@ -48,7 +48,8 @@ module SMARTAppLaunch
48
48
  client_secret: {
49
49
  name: :ehr_client_secret,
50
50
  title: 'EHR Launch Client Secret',
51
- description: 'Client Secret provided during registration of Inferno as an EHR launch application'
51
+ description: 'Client Secret provided during registration of Inferno as an EHR launch application. ' \
52
+ 'Only for clients using confidential symmetric authentication.'
52
53
  },
53
54
  requested_scopes: {
54
55
  name: :ehr_requested_scopes,
@@ -1,5 +1,6 @@
1
1
  require_relative 'app_redirect_test_stu2'
2
2
  require_relative 'ehr_launch_group'
3
+ require_relative 'token_exchange_stu2_test'
3
4
 
4
5
  module SMARTAppLaunch
5
6
  class EHRLaunchGroupSTU2 < EHRLaunchGroup
@@ -52,5 +53,12 @@ module SMARTAppLaunch
52
53
 
53
54
  redirect_index = children.find_index { |child| child.id.to_s.end_with? 'app_redirect' }
54
55
  children[redirect_index] = children.pop
56
+
57
+ test from: :smart_token_exchange_stu2
58
+
59
+ token_exchange_index = children.find_index { |child| child.id.to_s.end_with? 'token_exchange' }
60
+ children[token_exchange_index] = children.pop
61
+
62
+ children[token_exchange_index].id(:smart_token_exchange)
55
63
  end
56
64
  end
@@ -0,0 +1,27 @@
1
+ require 'jwt'
2
+
3
+ module SMARTAppLaunch
4
+ class JWKS
5
+ class << self
6
+ def jwks_json
7
+ @jwks_json ||=
8
+ JSON.pretty_generate(
9
+ { keys: jwks.export[:keys].select { |key| key[:key_ops]&.include?('verify') } }
10
+ )
11
+ end
12
+
13
+ def default_jwks_path
14
+ @default_jwks_path ||= File.join(__dir__, 'smart_jwks.json')
15
+ end
16
+
17
+ def jwks_path
18
+ @jwks_path ||=
19
+ ENV.fetch('SMART_JWKS_PATH', default_jwks_path)
20
+ end
21
+
22
+ def jwks
23
+ @jwks ||= JWT::JWK::Set.new(JSON.parse(File.read(jwks_path)))
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,58 @@
1
+ {
2
+ "keys":
3
+ [{
4
+ "kty": "EC",
5
+ "crv": "P-384",
6
+ "x": "JQKTsV6PT5Szf4QtDA1qrs0EJ1pbimQmM2SKvzOlIAqlph3h1OHmZ2i7MXahIF2C",
7
+ "y": "bRWWQRJBgDa6CTgwofYrHjVGcO-A7WNEnu4oJA5OUJPPPpczgx1g2NsfinK-D2Rw",
8
+ "use": "sig",
9
+ "key_ops": [
10
+ "verify"
11
+ ],
12
+ "ext": true,
13
+ "kid": "4b49a739d1eb115b3225f4cf9beb6d1b",
14
+ "alg": "ES384"
15
+ },
16
+ {
17
+ "kty": "EC",
18
+ "crv": "P-384",
19
+ "d": "kDkn55p7gryKk2tj6z2ij7ExUnhi0ngxXosvqa73y7epwgthFqaJwApmiXXU2yhK",
20
+ "x": "JQKTsV6PT5Szf4QtDA1qrs0EJ1pbimQmM2SKvzOlIAqlph3h1OHmZ2i7MXahIF2C",
21
+ "y": "bRWWQRJBgDa6CTgwofYrHjVGcO-A7WNEnu4oJA5OUJPPPpczgx1g2NsfinK-D2Rw",
22
+ "key_ops": [
23
+ "sign"
24
+ ],
25
+ "ext": true,
26
+ "kid": "4b49a739d1eb115b3225f4cf9beb6d1b",
27
+ "alg": "ES384"
28
+ },
29
+ {
30
+ "kty": "RSA",
31
+ "alg": "RS384",
32
+ "n": "vjbIzTqiY8K8zApeNng5ekNNIxJfXAue9BjoMrZ9Qy9m7yIA-tf6muEupEXWhq70tC7vIGLqJJ4O8m7yiH8H2qklX2mCAMg3xG3nbykY2X7JXtW9P8VIdG0sAMt5aZQnUGCgSS3n0qaooGn2LUlTGIR88Qi-4Nrao9_3Ki3UCiICeCiAE224jGCg0OlQU6qj2gEB3o-DWJFlG_dz1y-Mxo5ivaeM0vWuodjDrp-aiabJcSF_dx26sdC9dZdBKXFDq0t19I9S9AyGpGDJwzGRtWHY6LsskNHLvo8Zb5AsJ9eRZKpnh30SYBZI9WHtzU85M9WQqdScR69Vyp-6Uhfbvw",
33
+ "e": "AQAB",
34
+ "use": "sig",
35
+ "key_ops": [
36
+ "verify"
37
+ ],
38
+ "ext": true,
39
+ "kid": "b41528b6f37a9500edb8a905a595bdd7"
40
+ },
41
+ {
42
+ "kty": "RSA",
43
+ "alg": "RS384",
44
+ "n": "vjbIzTqiY8K8zApeNng5ekNNIxJfXAue9BjoMrZ9Qy9m7yIA-tf6muEupEXWhq70tC7vIGLqJJ4O8m7yiH8H2qklX2mCAMg3xG3nbykY2X7JXtW9P8VIdG0sAMt5aZQnUGCgSS3n0qaooGn2LUlTGIR88Qi-4Nrao9_3Ki3UCiICeCiAE224jGCg0OlQU6qj2gEB3o-DWJFlG_dz1y-Mxo5ivaeM0vWuodjDrp-aiabJcSF_dx26sdC9dZdBKXFDq0t19I9S9AyGpGDJwzGRtWHY6LsskNHLvo8Zb5AsJ9eRZKpnh30SYBZI9WHtzU85M9WQqdScR69Vyp-6Uhfbvw",
45
+ "e": "AQAB",
46
+ "d": "rriV9GYimi5by7TOW4xNh6_gYBHVRDBsft2OFF8qapdVHt2GNuRDDxc_B6ga6TY2Enh2MLKLTr1dD3W4FIdTCJiMerrorp07FJS7nJEMgWQDxrfgkX4_EqrhW42L5d4vypYnRXEEW6u4gzkx5uFOkdvJBIK7CsIdSaBFYhochnynNgvbKWasi4rl2hayEH8tdf3B7Z6OIH9alspBTaq3j_zJt_KkrpYEzIUb4UgALB5NTWn5YKr0Avk_asOg8YfjViQwO9ASGaWjQeJ2Rx8OEQwBMQHSDMCSWNiWmYOu9PcwSZFc1vLxqzyIM8QrQSJHCCMo_wGYgke_r0CLeONHEQ",
47
+ "p": "5hH_QApWGeobRi1n7XbMfJYohB8K3JDPa0MspfplHpJ-17JiGG2sNoBdBcpaPRf9OX48P8VqO0qrSSRAk-I-uO6OO9BHbIukXJILqnY2JmurYzbcYbt5FVbknlHRJojkF6-7sFBazpueUlOnXCw7X7Z_SkfNE4QX5Ejm2Zm5mek",
48
+ "q": "06bZz7c7K9s1-aEZsxYnLJ9eTpKlt1tIBDA_LwIh5W3w259pes2kUtimbnkyOf-V2ZIERsFCh5s-S9IOEMvAIa6M5j9GW1ILNT7AcHIUfcyFcH-FF8BU_KJdRP5PXnIXFdYcylvsdoIdchy1AaUIzyiKRCU3HBYI75hez0l_F2c",
49
+ "dp": "h_sVIXW6hCCRND48EedIX06k7conMkxIu_39ErDXOWWeoMAnKIcR5TijQnviL__QxD1vQMXezuKIMHfDz2RGbClbWdD1lhtG7wvG515tDPJQXxia0wzqOQmdoFF9S8hXAAT26vPjaAAkaEZXQaxG_4Au5elgNWu6b0wDXZN1Vpk",
50
+ "dq": "GqS0YpuUTU8JGmWXUJ4HTGy7eHSpe8134V8ZdRd1oOYYHe2RX64nc25mdR24nuh3uq3Q7_9AGsYGL5E_yAl-JD9O6WUpvDE1y_wcSYty3Os0GRdUb8r8Z9kgmKDS6Pa_xTXw5eBwgfKbNlQ6zPwzgbB-x1lP-K8lbNPni3ybDR0",
51
+ "qi": "cqQfoi0sM5Su8ZOhznmdWrDIQB28H6fBKiabgaIKkbWZV4e0nwFvLquHjPOvv4Ao8iEGU5dyhvg0n5BKYPi-4mp6M6OA1sy0NrTr7EsKSYGyu2pBq9rw4oAYTM2LXKg6K-awgUUlkc451IwxHBAe15PWCBM3kvLQeijNid0Vz5I",
52
+ "key_ops": [
53
+ "sign"
54
+ ],
55
+ "ext": true,
56
+ "kid": "b41528b6f37a9500edb8a905a595bdd7"
57
+ }]
58
+ }
@@ -1,5 +1,6 @@
1
1
  require 'tls_test_kit'
2
2
 
3
+ require_relative 'jwks'
3
4
  require_relative 'version'
4
5
  require_relative 'discovery_stu1_group'
5
6
  require_relative 'standalone_launch_group'
@@ -21,15 +22,39 @@ module SMARTAppLaunch
21
22
  request.query_parameters['state']
22
23
  end
23
24
 
25
+ route(
26
+ :get,
27
+ '/.well-known/jwks.json',
28
+ ->(_env) { [200, { 'Content-Type' => 'application/json' }, [JWKS.jwks_json]] }
29
+ )
30
+
24
31
  config options: {
25
32
  redirect_uri: "#{Inferno::Application['base_url']}/custom/smart/redirect",
26
33
  launch_uri: "#{Inferno::Application['base_url']}/custom/smart/launch"
27
34
  }
28
35
 
36
+ description <<~DESCRIPTION
37
+ The SMART App Launch Test Suite verifies that systems correctly implement
38
+ the [SMART App Launch IG](http://hl7.org/fhir/smart-app-launch/1.0.0/)
39
+ for providing authorization and/or authentication services to client
40
+ applications accessing HL7® FHIR® APIs. To get started, please first register
41
+ the Inferno client as a SMART App with the following information:
42
+
43
+ * SMART Launch URI: `#{config.options[:launch_uri]}`
44
+ * OAuth Redirect URI: `#{config.options[:redirect_uri]}`
45
+ DESCRIPTION
46
+
29
47
  group do
30
48
  title 'Standalone Launch'
31
49
  id :smart_full_standalone_launch
32
50
 
51
+ input_instructions <<~INSTRUCTIONS
52
+ Please register the Inferno client as a SMART App with the following
53
+ information:
54
+
55
+ * OAuth Redirect URI: `#{config.options[:redirect_uri]}`
56
+ INSTRUCTIONS
57
+
33
58
  run_as_group
34
59
 
35
60
  group from: :smart_discovery
@@ -92,6 +117,14 @@ module SMARTAppLaunch
92
117
  title 'EHR Launch'
93
118
  id :smart_full_ehr_launch
94
119
 
120
+ input_instructions <<~INSTRUCTIONS
121
+ Please register the Inferno client as a SMART App with the following
122
+ information:
123
+
124
+ * SMART Launch URI: `#{config.options[:launch_uri]}`
125
+ * OAuth Redirect URI: `#{config.options[:redirect_uri]}`
126
+ INSTRUCTIONS
127
+
95
128
  run_as_group
96
129
 
97
130
  group from: :smart_discovery
@@ -1,5 +1,6 @@
1
1
  require 'tls_test_kit'
2
2
 
3
+ require_relative 'jwks'
3
4
  require_relative 'version'
4
5
  require_relative 'discovery_stu2_group'
5
6
  require_relative 'standalone_launch_group_stu2'
@@ -21,6 +22,12 @@ module SMARTAppLaunch
21
22
  request.query_parameters['state']
22
23
  end
23
24
 
25
+ route(
26
+ :get,
27
+ '/.well-known/jwks.json',
28
+ ->(_env) { [200, { 'Content-Type' => 'application/json' }, [JWKS.jwks_json]] }
29
+ )
30
+
24
31
  @post_auth_page = File.read(File.join(__dir__, 'post_auth.html'))
25
32
  post_auth_handler = proc { [200, {}, [@post_auth_page]] }
26
33
 
@@ -32,10 +39,38 @@ module SMARTAppLaunch
32
39
  post_authorization_uri: "#{Inferno::Application['base_url']}/custom/smart_stu2/post_auth"
33
40
  }
34
41
 
42
+ description <<~DESCRIPTION
43
+ The SMART App Launch Test Suite verifies that systems correctly implement
44
+ the [SMART App Launch IG](http://hl7.org/fhir/smart-app-launch/STU2/)
45
+ for providing authorization and/or authentication services to client
46
+ applications accessing HL7® FHIR® APIs. To get started, please first register
47
+ the Inferno client as a SMART App with the following information:
48
+
49
+ * SMART Launch URI: `#{config.options[:launch_uri]}`
50
+ * OAuth Redirect URI: `#{config.options[:redirect_uri]}`
51
+
52
+ If using asymmetric client authentication, register Inferno with the
53
+ following JWK Set URL:
54
+
55
+ * `#{Inferno::Application[:base_url]}/custom/smart_stu2/.well-known/jwks.json`
56
+ DESCRIPTION
57
+
35
58
  group do
36
59
  title 'Standalone Launch'
37
60
  id :smart_full_standalone_launch
38
61
 
62
+ input_instructions <<~INSTRUCTIONS
63
+ Please register the Inferno client as a SMART App with the following
64
+ information:
65
+
66
+ * OAuth Redirect URI: `#{config.options[:redirect_uri]}`
67
+
68
+ If using asymmetric client authentication, register Inferno with the
69
+ following JWK Set URL:
70
+
71
+ * `#{Inferno::Application[:base_url]}/custom/smart_stu2/.well-known/jwks.json`
72
+ INSTRUCTIONS
73
+
39
74
  run_as_group
40
75
 
41
76
  group from: :smart_discovery_stu2
@@ -98,6 +133,19 @@ module SMARTAppLaunch
98
133
  title 'EHR Launch'
99
134
  id :smart_full_ehr_launch
100
135
 
136
+ input_instructions <<~INSTRUCTIONS
137
+ Please register the Inferno client as a SMART App with the following
138
+ information:
139
+
140
+ * SMART Launch URI: `#{config.options[:launch_uri]}`
141
+ * OAuth Redirect URI: `#{config.options[:redirect_uri]}`
142
+
143
+ If using asymmetric client authentication, register Inferno with the
144
+ following JWK Set URL:
145
+
146
+ * `#{Inferno::Application[:base_url]}/custom/smart_stu2/.well-known/jwks.json`
147
+ INSTRUCTIONS
148
+
101
149
  run_as_group
102
150
 
103
151
  group from: :smart_discovery_stu2
@@ -44,7 +44,8 @@ module SMARTAppLaunch
44
44
  client_secret: {
45
45
  name: :standalone_client_secret,
46
46
  title: 'Standalone Client Secret',
47
- description: 'Client Secret provided during registration of Inferno as a standalone application'
47
+ description: 'Client Secret provided during registration of Inferno as a standalone application. ' \
48
+ 'Only for clients using confidential symmetric authentication.'
48
49
  },
49
50
  requested_scopes: {
50
51
  name: :standalone_requested_scopes,
@@ -1,4 +1,5 @@
1
1
  require_relative 'app_redirect_test_stu2'
2
+ require_relative 'token_exchange_stu2_test'
2
3
  require_relative 'standalone_launch_group'
3
4
 
4
5
  module SMARTAppLaunch
@@ -48,5 +49,12 @@ module SMARTAppLaunch
48
49
 
49
50
  redirect_index = children.find_index { |child| child.id.to_s.end_with? 'app_redirect' }
50
51
  children[redirect_index] = children.pop
52
+
53
+ test from: :smart_token_exchange_stu2
54
+
55
+ token_exchange_index = children.find_index { |child| child.id.to_s.end_with? 'token_exchange' }
56
+ children[token_exchange_index] = children.pop
57
+
58
+ children[token_exchange_index].id('smart_token_exchange')
51
59
  end
52
60
  end
@@ -0,0 +1,91 @@
1
+ require_relative 'client_assertion_builder'
2
+ require_relative 'token_exchange_test'
3
+
4
+ module SMARTAppLaunch
5
+ class TokenExchangeSTU2Test < TokenExchangeTest
6
+ title 'OAuth token exchange request succeeds when supplied correct information'
7
+ description %(
8
+ After obtaining an authorization code, the app trades the code for an
9
+ access token via HTTP POST to the EHR authorization server's token
10
+ endpoint URL, using content-type application/x-www-form-urlencoded, as
11
+ described in section [4.1.3 of
12
+ RFC6749](https://tools.ietf.org/html/rfc6749#section-4.1.3).
13
+ )
14
+ id :smart_token_exchange_stu2
15
+
16
+ input :client_auth_encryption_method,
17
+ title: 'Encryption Method (Confidential Asymmetric Client Auth Only)',
18
+ type: 'radio',
19
+ default: 'ES384',
20
+ options: {
21
+ list_options: [
22
+ {
23
+ label: 'ES384',
24
+ value: 'ES384'
25
+ },
26
+ {
27
+ label: 'RS384',
28
+ value: 'RS384'
29
+ }
30
+ ]
31
+ }
32
+
33
+ input :client_auth_type,
34
+ title: 'Client Authentication Method',
35
+ type: 'radio',
36
+ options: {
37
+ list_options: [
38
+ {
39
+ label: 'Public',
40
+ value: 'public'
41
+ },
42
+ {
43
+ label: 'Confidential Symmetric',
44
+ value: 'confidential_symmetric'
45
+ },
46
+ {
47
+ label: 'Confidential Asymmetric',
48
+ value: 'confidential_asymmetric'
49
+ }
50
+ ]
51
+ }
52
+
53
+ config(
54
+ inputs: {
55
+ use_pkce: {
56
+ default: 'true',
57
+ options: {
58
+ list_options: [
59
+ {
60
+ label: 'Enabled',
61
+ value: 'true'
62
+ }
63
+ ]
64
+ }
65
+ }
66
+ }
67
+ )
68
+
69
+ def add_credentials_to_request(oauth2_params, oauth2_headers)
70
+ if client_auth_type == 'confidential_symmetric'
71
+ assert client_secret.present?,
72
+ "A client secret must be provided when using confidential symmetric client authentication."
73
+
74
+ client_credentials = "#{client_id}:#{client_secret}"
75
+ oauth2_headers['Authorization'] = "Basic #{Base64.strict_encode64(client_credentials)}"
76
+ elsif client_auth_type == 'public'
77
+ oauth2_params[:client_id] = client_id
78
+ else
79
+ oauth2_params.merge!(
80
+ client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
81
+ client_assertion: ClientAssertionBuilder.build(
82
+ iss: client_id,
83
+ sub: client_id,
84
+ aud: smart_token_url,
85
+ client_auth_encryption_method: client_auth_encryption_method
86
+ )
87
+ )
88
+ end
89
+ end
90
+ end
91
+ end
@@ -38,22 +38,26 @@ module SMARTAppLaunch
38
38
 
39
39
  config options: { redirect_uri: "#{Inferno::Application['base_url']}/custom/smart/redirect" }
40
40
 
41
+ def add_credentials_to_request(oauth2_params, oauth2_headers)
42
+ if client_secret.present?
43
+ client_credentials = "#{client_id}:#{client_secret}"
44
+ oauth2_headers['Authorization'] = "Basic #{Base64.strict_encode64(client_credentials)}"
45
+ else
46
+ oauth2_params[:client_id] = client_id
47
+ end
48
+ end
49
+
41
50
  run do
42
51
  skip_if request.query_parameters['error'].present?, 'Error during authorization request'
43
52
 
44
53
  oauth2_params = {
45
- grant_type: 'authorization_code',
46
54
  code: code,
47
- redirect_uri: config.options[:redirect_uri]
55
+ redirect_uri: config.options[:redirect_uri],
56
+ grant_type: 'authorization_code'
48
57
  }
49
58
  oauth2_headers = { 'Content-Type' => 'application/x-www-form-urlencoded' }
50
59
 
51
- if client_secret.present?
52
- client_credentials = "#{client_id}:#{client_secret}"
53
- oauth2_headers['Authorization'] = "Basic #{Base64.strict_encode64(client_credentials)}"
54
- else
55
- oauth2_params[:client_id] = client_id
56
- end
60
+ add_credentials_to_request(oauth2_params, oauth2_headers)
57
61
 
58
62
  if use_pkce == 'true'
59
63
  oauth2_params[:code_verifier] = pkce_code_verifier
@@ -1,3 +1,3 @@
1
1
  module SMARTAppLaunch
2
- VERSION = '0.2.2'.freeze
2
+ VERSION = '0.3.0'.freeze
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.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen MacVicar
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-03 00:00:00.000000000 Z
11
+ date: 2023-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inferno_core
@@ -134,11 +134,13 @@ files:
134
134
  - lib/smart_app_launch/app_launch_test.rb
135
135
  - lib/smart_app_launch/app_redirect_test.rb
136
136
  - lib/smart_app_launch/app_redirect_test_stu2.rb
137
+ - lib/smart_app_launch/client_assertion_builder.rb
137
138
  - lib/smart_app_launch/code_received_test.rb
138
139
  - lib/smart_app_launch/discovery_stu1_group.rb
139
140
  - lib/smart_app_launch/discovery_stu2_group.rb
140
141
  - lib/smart_app_launch/ehr_launch_group.rb
141
142
  - lib/smart_app_launch/ehr_launch_group_stu2.rb
143
+ - lib/smart_app_launch/jwks.rb
142
144
  - lib/smart_app_launch/launch_received_test.rb
143
145
  - lib/smart_app_launch/openid_connect_group.rb
144
146
  - lib/smart_app_launch/openid_decode_id_token_test.rb
@@ -149,10 +151,12 @@ files:
149
151
  - lib/smart_app_launch/openid_token_header_test.rb
150
152
  - lib/smart_app_launch/openid_token_payload_test.rb
151
153
  - lib/smart_app_launch/post_auth.html
154
+ - lib/smart_app_launch/smart_jwks.json
152
155
  - lib/smart_app_launch/smart_stu1_suite.rb
153
156
  - lib/smart_app_launch/smart_stu2_suite.rb
154
157
  - lib/smart_app_launch/standalone_launch_group.rb
155
158
  - lib/smart_app_launch/standalone_launch_group_stu2.rb
159
+ - lib/smart_app_launch/token_exchange_stu2_test.rb
156
160
  - lib/smart_app_launch/token_exchange_test.rb
157
161
  - lib/smart_app_launch/token_payload_validation.rb
158
162
  - lib/smart_app_launch/token_refresh_body_test.rb