smart_app_launch_test_kit 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/config/presets/SMART_RunClientAgainstServer.json.erb +79 -0
- data/config/presets/SMART_RunServerAgainstClient_ConfidentialAsymmetric.json.erb +183 -0
- data/config/presets/SMART_RunServerAgainstClient_ConfidentialSymmetric.json.erb +157 -0
- data/config/presets/SMART_RunServerAgainstClient_Public.json.erb +155 -0
- data/lib/smart_app_launch/backend_services_authorization_group.rb +0 -2
- data/lib/smart_app_launch/backend_services_authorization_request_success_test.rb +5 -2
- data/lib/smart_app_launch/backend_services_authorization_response_body_test.rb +6 -2
- data/lib/smart_app_launch/backend_services_invalid_client_assertion_test.rb +1 -1
- data/lib/smart_app_launch/backend_services_invalid_jwt_test.rb +1 -1
- data/lib/smart_app_launch/client_stu2_2_suite.rb +120 -0
- data/lib/smart_app_launch/client_suite/access_alca_interaction_test.rb +75 -0
- data/lib/smart_app_launch/client_suite/access_alcs_interaction_test.rb +75 -0
- data/lib/smart_app_launch/client_suite/access_alp_interaction_test.rb +75 -0
- data/lib/smart_app_launch/client_suite/access_bsca_interaction_test.rb +46 -0
- data/lib/smart_app_launch/client_suite/access_group.rb +85 -0
- data/lib/smart_app_launch/client_suite/authentication_verification.rb +86 -0
- data/lib/smart_app_launch/client_suite/authorization_request_verification_test.rb +108 -0
- data/lib/smart_app_launch/client_suite/client_descriptions.rb +114 -0
- data/lib/smart_app_launch/client_suite/client_options.rb +35 -0
- data/lib/smart_app_launch/client_suite/oidc_jwks.json +32 -0
- data/lib/smart_app_launch/client_suite/oidc_jwks.rb +27 -0
- data/lib/smart_app_launch/client_suite/registration_alca_group.rb +15 -0
- data/lib/smart_app_launch/client_suite/registration_alca_verification_test.rb +57 -0
- data/lib/smart_app_launch/client_suite/registration_alcs_group.rb +15 -0
- data/lib/smart_app_launch/client_suite/registration_alcs_verification_test.rb +56 -0
- data/lib/smart_app_launch/client_suite/registration_alp_group.rb +16 -0
- data/lib/smart_app_launch/client_suite/registration_alp_verification_test.rb +50 -0
- data/lib/smart_app_launch/client_suite/registration_bsca_group.rb +15 -0
- data/lib/smart_app_launch/client_suite/registration_bsca_verification_test.rb +40 -0
- data/lib/smart_app_launch/client_suite/registration_verification.rb +58 -0
- data/lib/smart_app_launch/client_suite/token_request_alca_verification_test.rb +53 -0
- data/lib/smart_app_launch/client_suite/token_request_alcs_verification_test.rb +53 -0
- data/lib/smart_app_launch/client_suite/token_request_alp_verification_test.rb +48 -0
- data/lib/smart_app_launch/client_suite/token_request_bsca_verification_test.rb +53 -0
- data/lib/smart_app_launch/client_suite/token_request_verification.rb +116 -0
- data/lib/smart_app_launch/client_suite/token_use_verification_test.rb +40 -0
- data/lib/smart_app_launch/docs/demo/FHIR Request.postman_collection.json +81 -0
- data/lib/smart_app_launch/docs/smart_stu2_2_client_suite_description.md +208 -0
- data/lib/smart_app_launch/endpoints/echoing_fhir_responder_endpoint.rb +96 -0
- data/lib/smart_app_launch/endpoints/mock_smart_server/authorization_endpoint.rb +27 -0
- data/lib/smart_app_launch/endpoints/mock_smart_server/introspection_endpoint.rb +33 -0
- data/lib/smart_app_launch/endpoints/mock_smart_server/smart_authorization_response_creation.rb +30 -0
- data/lib/smart_app_launch/endpoints/mock_smart_server/smart_introspection_response_creation.rb +46 -0
- data/lib/smart_app_launch/endpoints/mock_smart_server/smart_token_response_creation.rb +250 -0
- data/lib/smart_app_launch/endpoints/mock_smart_server/token_endpoint.rb +58 -0
- data/lib/smart_app_launch/endpoints/mock_smart_server.rb +278 -0
- data/lib/smart_app_launch/metadata.rb +21 -16
- data/lib/smart_app_launch/smart_stu2_2_suite.rb +2 -1
- data/lib/smart_app_launch/smart_stu2_suite.rb +2 -1
- data/lib/smart_app_launch/tags.rb +15 -0
- data/lib/smart_app_launch/token_introspection_response_group.rb +1 -1
- data/lib/smart_app_launch/token_payload_validation.rb +2 -2
- data/lib/smart_app_launch/urls.rb +52 -0
- data/lib/smart_app_launch/version.rb +2 -2
- data/lib/smart_app_launch_test_kit.rb +1 -0
- metadata +45 -2
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '../../tags'
|
3
|
+
require_relative '../mock_smart_server'
|
4
|
+
require_relative 'smart_introspection_response_creation'
|
5
|
+
|
6
|
+
module SMARTAppLaunch
|
7
|
+
module MockSMARTServer
|
8
|
+
class IntrospectionEndpoint < Inferno::DSL::SuiteEndpoint
|
9
|
+
include SMARTIntrospectionResponseCreation
|
10
|
+
|
11
|
+
def test_run_identifier
|
12
|
+
MockSMARTServer.issued_token_to_client_id(request.params[:token])
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_response
|
16
|
+
response.body = make_smart_introspection_response.to_json
|
17
|
+
response.headers['Cache-Control'] = 'no-store'
|
18
|
+
response.headers['Pragma'] = 'no-cache'
|
19
|
+
response.headers['Access-Control-Allow-Origin'] = '*'
|
20
|
+
response.content_type = 'application/json'
|
21
|
+
response.status = 200
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_result
|
25
|
+
nil # never update for now
|
26
|
+
end
|
27
|
+
|
28
|
+
def tags
|
29
|
+
[INTROSPECTION_TAG, SMART_TAG]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/smart_app_launch/endpoints/mock_smart_server/smart_authorization_response_creation.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../../tags'
|
2
|
+
require_relative '../mock_smart_server'
|
3
|
+
require_relative '../../client_suite/oidc_jwks'
|
4
|
+
|
5
|
+
module SMARTAppLaunch
|
6
|
+
module MockSMARTServer
|
7
|
+
module SMARTAuthorizationResponseCreation
|
8
|
+
def make_smart_authorization_response
|
9
|
+
redirect_uri = request.params[:redirect_uri]
|
10
|
+
if redirect_uri.blank?
|
11
|
+
response.status = 400
|
12
|
+
response.body = {
|
13
|
+
error: 'Bad request',
|
14
|
+
message: 'Missing required redirect_uri parameter.'}.to_json
|
15
|
+
response.content_type = 'application/json'
|
16
|
+
return
|
17
|
+
end
|
18
|
+
|
19
|
+
client_id = request.params[:client_id]
|
20
|
+
state = request.params[:state]
|
21
|
+
|
22
|
+
exp_min = 10
|
23
|
+
token = MockSMARTServer.client_id_to_token(client_id, exp_min)
|
24
|
+
query_string = "code=#{ERB::Util.url_encode(token)}&state=#{ERB::Util.url_encode(state)}"
|
25
|
+
response.headers['Location'] = "#{redirect_uri}#{redirect_uri.include?('?') ? '&' : '?'}#{query_string}"
|
26
|
+
response.status = 302
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/smart_app_launch/endpoints/mock_smart_server/smart_introspection_response_creation.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative '../../tags'
|
2
|
+
require_relative '../mock_smart_server'
|
3
|
+
|
4
|
+
module SMARTAppLaunch
|
5
|
+
module MockSMARTServer
|
6
|
+
module SMARTIntrospectionResponseCreation
|
7
|
+
def make_smart_introspection_response
|
8
|
+
target_token = request.params[:token]
|
9
|
+
introspection_inactive_response_body = { active: false }
|
10
|
+
|
11
|
+
return introspection_inactive_response_body if MockSMARTServer.token_expired?(target_token)
|
12
|
+
|
13
|
+
token_requests = Inferno::Repositories::Requests.new.tagged_requests(test_run.test_session_id, [TOKEN_TAG])
|
14
|
+
original_response_body = nil
|
15
|
+
original_token_request = token_requests.find do |request|
|
16
|
+
next unless request.status == 200
|
17
|
+
|
18
|
+
original_response_body = JSON.parse(request.response_body)
|
19
|
+
[original_response_body['access_token'], original_response_body['refresh_token']].include?(target_token)
|
20
|
+
end
|
21
|
+
return introspection_inactive_response_body unless original_token_request.present?
|
22
|
+
|
23
|
+
decoded_token = MockSMARTServer.decode_token(target_token)
|
24
|
+
introspection_active_response_body = {
|
25
|
+
active: true,
|
26
|
+
client_id: decoded_token['client_id'],
|
27
|
+
exp: decoded_token['expiration']
|
28
|
+
}
|
29
|
+
original_response_body.each do |element, value|
|
30
|
+
next if ['access_token', 'refresh_token', 'token_type', 'expires_in'].include?(element)
|
31
|
+
next if introspection_active_response_body.key?(element)
|
32
|
+
|
33
|
+
introspection_active_response_body[element] = value
|
34
|
+
end
|
35
|
+
if original_response_body.key?('id_token')
|
36
|
+
user_claims, _header = JWT.decode(original_response_body['id_token'], nil, false)
|
37
|
+
introspection_active_response_body['iss'] = user_claims['iss']
|
38
|
+
introspection_active_response_body['sub'] = user_claims['sub']
|
39
|
+
introspection_active_response_body['fhirUser'] = user_claims['fhirUser'] if user_claims['fhirUser'].present?
|
40
|
+
end
|
41
|
+
|
42
|
+
introspection_active_response_body
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require_relative '../../tags'
|
2
|
+
require_relative '../mock_smart_server'
|
3
|
+
require_relative '../../client_suite/oidc_jwks'
|
4
|
+
|
5
|
+
module SMARTAppLaunch
|
6
|
+
module MockSMARTServer
|
7
|
+
module SMARTTokenResponseCreation
|
8
|
+
def make_smart_authorization_code_token_response(smart_authentication_approach)
|
9
|
+
authorization_code = request.params[:code]
|
10
|
+
client_id = MockSMARTServer.issued_token_to_client_id(authorization_code)
|
11
|
+
return unless authenticated?(client_id, smart_authentication_approach)
|
12
|
+
|
13
|
+
if MockSMARTServer.token_expired?(authorization_code)
|
14
|
+
MockSMARTServer.update_response_for_expired_token(response, 'Authorization code')
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
authorization_request = MockSMARTServer.authorization_request_for_code(authorization_code,
|
19
|
+
test_run.test_session_id)
|
20
|
+
if authorization_request.blank?
|
21
|
+
MockSMARTServer.update_response_for_error(
|
22
|
+
response,
|
23
|
+
"no authorization request found for code #{authorization_code}"
|
24
|
+
)
|
25
|
+
return
|
26
|
+
end
|
27
|
+
auth_code_request_inputs = MockSMARTServer.authorization_code_request_details(authorization_request)
|
28
|
+
if auth_code_request_inputs.blank?
|
29
|
+
MockSMARTServer.update_response_for_error(
|
30
|
+
response,
|
31
|
+
'invalid authorization request details'
|
32
|
+
)
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
return if request.params[:code_verifier].present? && !smart_pkce_valid?(auth_code_request_inputs)
|
37
|
+
|
38
|
+
exp_min = 60
|
39
|
+
response_body = {
|
40
|
+
access_token: MockSMARTServer.client_id_to_token(client_id, exp_min),
|
41
|
+
token_type: 'Bearer',
|
42
|
+
expires_in: 60 * exp_min,
|
43
|
+
scope: auth_code_request_inputs['scope']
|
44
|
+
}
|
45
|
+
|
46
|
+
launch_context =
|
47
|
+
begin
|
48
|
+
input_string = JSON.parse(result.input_json)&.find do |input|
|
49
|
+
input['name'] == 'launch_context'
|
50
|
+
end&.dig('value')
|
51
|
+
JSON.parse(input_string) if input_string.present?
|
52
|
+
rescue JSON::ParserError
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
additional_context = smart_requested_scope_context(auth_code_request_inputs['scope'], authorization_code,
|
56
|
+
launch_context)
|
57
|
+
|
58
|
+
response.body = additional_context.merge(response_body).to_json # response body values take priority
|
59
|
+
response.headers['Cache-Control'] = 'no-store'
|
60
|
+
response.headers['Pragma'] = 'no-cache'
|
61
|
+
response.headers['Access-Control-Allow-Origin'] = '*'
|
62
|
+
response.content_type = 'application/json'
|
63
|
+
response.status = 200
|
64
|
+
end
|
65
|
+
|
66
|
+
def make_smart_refresh_token_response(smart_authentication_approach)
|
67
|
+
refresh_token = request.params[:refresh_token]
|
68
|
+
authorization_code = MockSMARTServer.refresh_token_to_authorization_code(refresh_token)
|
69
|
+
client_id = MockSMARTServer.issued_token_to_client_id(authorization_code)
|
70
|
+
return unless authenticated?(client_id, smart_authentication_approach)
|
71
|
+
|
72
|
+
# no expiration checks for refresh tokens
|
73
|
+
|
74
|
+
authorization_request = MockSMARTServer.authorization_request_for_code(authorization_code,
|
75
|
+
test_run.test_session_id)
|
76
|
+
if authorization_request.blank?
|
77
|
+
MockSMARTServer.update_response_for_error(
|
78
|
+
response,
|
79
|
+
"no authorization request found for refresh token #{refresh_token}"
|
80
|
+
)
|
81
|
+
return
|
82
|
+
end
|
83
|
+
auth_code_request_inputs = MockSMARTServer.authorization_code_request_details(authorization_request)
|
84
|
+
if auth_code_request_inputs.blank?
|
85
|
+
MockSMARTServer.update_response_for_error(
|
86
|
+
response,
|
87
|
+
'invalid authorization request details'
|
88
|
+
)
|
89
|
+
return
|
90
|
+
end
|
91
|
+
|
92
|
+
exp_min = 60
|
93
|
+
response_body = {
|
94
|
+
access_token: MockSMARTServer.client_id_to_token(client_id, exp_min),
|
95
|
+
token_type: 'Bearer',
|
96
|
+
expires_in: 60 * exp_min,
|
97
|
+
scope: request.params[:scope].present? ? request.params[:scope] : auth_code_request_inputs['scope']
|
98
|
+
}
|
99
|
+
|
100
|
+
launch_context =
|
101
|
+
begin
|
102
|
+
input_string = JSON.parse(result.input_json)&.find do |input|
|
103
|
+
input['name'] == 'launch_context'
|
104
|
+
end&.dig('value')
|
105
|
+
JSON.parse(input_string) if input_string.present?
|
106
|
+
rescue JSON::ParserError
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
additional_context = smart_requested_scope_context(auth_code_request_inputs['scope'], authorization_code,
|
110
|
+
launch_context)
|
111
|
+
|
112
|
+
response.body = additional_context.merge(response_body).to_json # response body values take priority
|
113
|
+
response.headers['Cache-Control'] = 'no-store'
|
114
|
+
response.headers['Pragma'] = 'no-cache'
|
115
|
+
response.headers['Access-Control-Allow-Origin'] = '*'
|
116
|
+
response.content_type = 'application/json'
|
117
|
+
response.status = 200
|
118
|
+
end
|
119
|
+
|
120
|
+
def make_smart_client_credential_token_response
|
121
|
+
assertion = request.params[:client_assertion]
|
122
|
+
client_id = MockSMARTServer.client_id_from_client_assertion(assertion)
|
123
|
+
|
124
|
+
# by loading from DB rather than result inputs don't have to be associated with specific tests
|
125
|
+
# e.g., key set input present on registration and auth checks, not during wait tests
|
126
|
+
key_set_input = Inferno::Repositories::SessionData.new.load(
|
127
|
+
test_session_id: result.test_session_id, name: 'smart_jwk_set'
|
128
|
+
)
|
129
|
+
return unless confidential_asymmetric_authenticated?(key_set_input)
|
130
|
+
|
131
|
+
exp_min = 60
|
132
|
+
response_body = {
|
133
|
+
access_token: MockSMARTServer.client_id_to_token(client_id, exp_min),
|
134
|
+
token_type: 'Bearer',
|
135
|
+
expires_in: 60 * exp_min,
|
136
|
+
scope: request.params[:scope]
|
137
|
+
}
|
138
|
+
|
139
|
+
response.body = response_body.to_json
|
140
|
+
response.headers['Cache-Control'] = 'no-store'
|
141
|
+
response.headers['Pragma'] = 'no-cache'
|
142
|
+
response.headers['Access-Control-Allow-Origin'] = '*'
|
143
|
+
response.content_type = 'application/json'
|
144
|
+
response.status = 200
|
145
|
+
end
|
146
|
+
|
147
|
+
def smart_requested_scope_context(requested_scopes, authorization_code, launch_context)
|
148
|
+
context = launch_context.present? ? launch_context : {}
|
149
|
+
scopes_list = requested_scopes&.split || []
|
150
|
+
|
151
|
+
if scopes_list.include?('offline_access') || scopes_list.include?('online_access')
|
152
|
+
context[:refresh_token] = MockSMARTServer.authorization_code_to_refresh_token(authorization_code)
|
153
|
+
end
|
154
|
+
|
155
|
+
context[:id_token] = smart_construct_id_token(scopes_list.include?('fhirUser')) if scopes_list.include?('openid')
|
156
|
+
|
157
|
+
context
|
158
|
+
end
|
159
|
+
|
160
|
+
def smart_construct_id_token(include_fhir_user)
|
161
|
+
client_id = JSON.parse(result.input_json)&.find do |input|
|
162
|
+
input['name'] == 'client_id'
|
163
|
+
end&.dig('value')
|
164
|
+
fhir_user_relative_reference = JSON.parse(result.input_json)&.find do |input|
|
165
|
+
input['name'] == 'fhir_user_relative_reference'
|
166
|
+
end&.dig('value')
|
167
|
+
# TODO: how to generate the id - is this ok?
|
168
|
+
subject_id = if fhir_user_relative_reference.present?
|
169
|
+
fhir_user_relative_reference.downcase.gsub('/', '-')
|
170
|
+
else
|
171
|
+
SecureRandom.uuid
|
172
|
+
end
|
173
|
+
|
174
|
+
claims = {
|
175
|
+
iss: client_fhir_base_url,
|
176
|
+
sub: subject_id,
|
177
|
+
aud: client_id,
|
178
|
+
exp: 1.year.from_now.to_i,
|
179
|
+
iat: Time.now.to_i
|
180
|
+
}
|
181
|
+
if include_fhir_user && fhir_user_relative_reference.present?
|
182
|
+
claims[:fhirUser] = "#{client_fhir_base_url}/#{fhir_user_relative_reference}"
|
183
|
+
end
|
184
|
+
|
185
|
+
algorithm = 'RS256'
|
186
|
+
private_key = OIDCJWKS.jwks
|
187
|
+
.select { |key| key[:key_ops]&.include?('sign') }
|
188
|
+
.select { |key| key[:alg] == algorithm }
|
189
|
+
.first
|
190
|
+
|
191
|
+
JWT.encode claims, private_key.signing_key, algorithm, { alg: algorithm, kid: private_key.kid, typ: 'JWT' }
|
192
|
+
end
|
193
|
+
|
194
|
+
def smart_pkce_valid?(auth_code_request_inputs)
|
195
|
+
verifier = request.params[:code_verifier]
|
196
|
+
challenge = auth_code_request_inputs&.dig('code_challenge')
|
197
|
+
method = auth_code_request_inputs&.dig('code_challenge_method')
|
198
|
+
MockSMARTServer.pkce_valid?(verifier, challenge, method, response)
|
199
|
+
end
|
200
|
+
|
201
|
+
def authenticated?(client_id, smart_authentication_approach)
|
202
|
+
case smart_authentication_approach
|
203
|
+
when CONFIDENTIAL_ASYMMETRIC_TAG
|
204
|
+
key_set_input = Inferno::Repositories::SessionData.new.load(
|
205
|
+
test_session_id: result.test_session_id, name: 'smart_jwk_set'
|
206
|
+
)
|
207
|
+
return confidential_asymmetric_authenticated?(key_set_input)
|
208
|
+
when CONFIDENTIAL_SYMMETRIC_TAG
|
209
|
+
client_secret_input = Inferno::Repositories::SessionData.new.load(
|
210
|
+
test_session_id: result.test_session_id, name: 'smart_client_secret'
|
211
|
+
)
|
212
|
+
return confidential_symmetric_authenticated?(client_id, client_secret_input)
|
213
|
+
when PUBLIC_TAG
|
214
|
+
return true
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def confidential_asymmetric_authenticated?(jwks)
|
219
|
+
assertion = request.params[:client_assertion]
|
220
|
+
if assertion.blank?
|
221
|
+
MockSMARTServer.update_response_for_error(
|
222
|
+
response,
|
223
|
+
'client_assertion missing from confidential asymmetric client request'
|
224
|
+
)
|
225
|
+
return false
|
226
|
+
end
|
227
|
+
|
228
|
+
signature_error = MockSMARTServer.smart_assertion_signature_verification(assertion, jwks)
|
229
|
+
|
230
|
+
if signature_error.present?
|
231
|
+
MockSMARTServer.update_response_for_error(response, signature_error)
|
232
|
+
return false
|
233
|
+
end
|
234
|
+
|
235
|
+
true
|
236
|
+
end
|
237
|
+
|
238
|
+
def confidential_symmetric_authenticated?(client_id, client_secret)
|
239
|
+
auth_header_value = request.headers['authorization']
|
240
|
+
error = MockSMARTServer.confidential_symmetric_header_value_error(auth_header_value, client_id, client_secret)
|
241
|
+
if error.present?
|
242
|
+
MockSMARTServer.update_response_for_error(response, error)
|
243
|
+
return false
|
244
|
+
end
|
245
|
+
|
246
|
+
true
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '../../tags'
|
3
|
+
require_relative '../mock_smart_server'
|
4
|
+
require_relative 'smart_token_response_creation'
|
5
|
+
|
6
|
+
module SMARTAppLaunch
|
7
|
+
module MockSMARTServer
|
8
|
+
class TokenEndpoint < Inferno::DSL::SuiteEndpoint
|
9
|
+
include URLs
|
10
|
+
include SMARTTokenResponseCreation
|
11
|
+
|
12
|
+
def test_run_identifier
|
13
|
+
case request.params[:grant_type]
|
14
|
+
when CLIENT_CREDENTIALS_TAG
|
15
|
+
MockSMARTServer.client_id_from_client_assertion(request.params[:client_assertion])
|
16
|
+
when AUTHORIZATION_CODE_TAG
|
17
|
+
MockSMARTServer.issued_token_to_client_id(request.params[:code])
|
18
|
+
when REFRESH_TOKEN_TAG
|
19
|
+
MockSMARTServer.issued_token_to_client_id(
|
20
|
+
MockSMARTServer.refresh_token_to_authorization_code(request.params[:refresh_token])
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def make_response
|
26
|
+
suite_options_list = Inferno::Repositories::TestSessions.new.find(result.test_session_id)&.suite_options
|
27
|
+
suite_options_hash = suite_options_list&.map { |option| [option.id, option.value] }&.to_h
|
28
|
+
smart_authentication_approach = SMARTClientOptions.smart_authentication_approach(suite_options_hash)
|
29
|
+
|
30
|
+
case request.params[:grant_type]
|
31
|
+
when CLIENT_CREDENTIALS_TAG
|
32
|
+
make_smart_client_credential_token_response
|
33
|
+
when AUTHORIZATION_CODE_TAG
|
34
|
+
make_smart_authorization_code_token_response(smart_authentication_approach)
|
35
|
+
when REFRESH_TOKEN_TAG
|
36
|
+
make_smart_refresh_token_response(smart_authentication_approach)
|
37
|
+
else
|
38
|
+
MockSMARTServer.update_response_for_error(
|
39
|
+
response,
|
40
|
+
"unsupported grant_type: #{request.params[:grant_type]}"
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_result
|
46
|
+
nil # never update for now
|
47
|
+
end
|
48
|
+
|
49
|
+
def tags
|
50
|
+
tags = [TOKEN_TAG, SMART_TAG]
|
51
|
+
if [CLIENT_CREDENTIALS_TAG, AUTHORIZATION_CODE_TAG, REFRESH_TOKEN_TAG].include?(request.params[:grant_type])
|
52
|
+
tags << request.params[:grant_type]
|
53
|
+
end
|
54
|
+
tags
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|