diff --git a/app/controllers/v0/map_services_controller.rb b/app/controllers/v0/map_services_controller.rb index b796ae041f5..18c792454b5 100644 --- a/app/controllers/v0/map_services_controller.rb +++ b/app/controllers/v0/map_services_controller.rb @@ -11,7 +11,7 @@ def token result = MAP::SecurityToken::Service.new.token(application: params[:application].to_sym, icn:, cache: false) render json: result, status: :ok - rescue Common::Client::Errors::ClientError, Common::Exceptions::GatewayTimeout + rescue Common::Client::Errors::ClientError, Common::Exceptions::GatewayTimeout, JWT::DecodeError render json: sts_client_error, status: :bad_gateway rescue MAP::SecurityToken::Errors::ApplicationMismatchError render json: application_mismatch_error, status: :bad_request diff --git a/config/betamocks/services_config.yml b/config/betamocks/services_config.yml index 9d6fbe9e039..ebbadcaa5b9 100644 --- a/config/betamocks/services_config.yml +++ b/config/betamocks/services_config.yml @@ -908,6 +908,9 @@ - :method: :post :path: "/sts/oauth/v1/token" :file_path: "map/secure_token_service/token" + - :method: :get + :path: "/sts/oauth/v1/jwks" + :file_path: "map/secure_token_service/jwks" # Sign Up Service Terms API - :name: "MAP SUS" diff --git a/lib/map/security_token/configuration.rb b/lib/map/security_token/configuration.rb index baccf972fe7..6814cacb7e4 100644 --- a/lib/map/security_token/configuration.rb +++ b/lib/map/security_token/configuration.rb @@ -34,6 +34,18 @@ def client_cert_path Settings.map_services.client_cert_path end + def jwks_cache_key + 'map_public_jwks' + end + + def jwks_cache_expiration + 30.minutes + end + + def public_jwks_path + '/sts/oauth/v1/jwks' + end + def service_name 'map_security_token_service' end @@ -66,7 +78,7 @@ def client_assertion_patient_id_type 'icn' end - def logging_prefix + def log_prefix '[MAP][SecurityToken][Service]' end diff --git a/lib/map/security_token/service.rb b/lib/map/security_token/service.rb index 63c0d026866..e3e66468bd6 100644 --- a/lib/map/security_token/service.rb +++ b/lib/map/security_token/service.rb @@ -2,29 +2,35 @@ require 'map/security_token/configuration' require 'map/security_token/errors' +require 'sign_in/public_jwks' module MAP module SecurityToken class Service < Common::Client::Base + include SignIn::PublicJwks configuration Configuration def token(application:, icn:, cache: true) cached_response = true - Rails.logger.info("#{config.logging_prefix} token request", { application:, icn: }) + Rails.logger.info("#{config.log_prefix} token request", { application:, icn: }) token = Rails.cache.fetch("map_sts_token_#{application}_#{icn}", expires_in: 5.minutes, force: !cache) do cached_response = false request_token(application, icn) end - Rails.logger.info("#{config.logging_prefix} token success", { application:, icn:, cached_response: }) + Rails.logger.info("#{config.log_prefix} token success", { application:, icn:, cached_response: }) token rescue Common::Client::Errors::ParsingError => e - Rails.logger.error("#{config.logging_prefix} token failed, parsing error", application:, icn:, - context: e.message) + Rails.logger.error("#{config.log_prefix} token failed, parsing error", application:, icn:, + context: e.message) + raise e + rescue JWT::DecodeError => e + Rails.logger.error("#{config.log_prefix} token failed, JWT decode error", application:, icn:, + context: e.message) raise e rescue Common::Client::Errors::ClientError => e parse_and_raise_error(e, icn, application) rescue Common::Exceptions::GatewayTimeout => e - Rails.logger.error("#{config.logging_prefix} token failed, gateway timeout", application:, icn:) + Rails.logger.error("#{config.log_prefix} token failed, gateway timeout", application:, icn:) raise e rescue Errors::ApplicationMismatchError => e Rails.logger.error(e.message, application:, icn:) @@ -49,7 +55,7 @@ def parse_and_raise_error(e, icn, application) error_source = status >= 500 ? 'server' : 'client' parse_body = e.body.presence || {} context = { error: parse_body['error'] } - message = "#{config.logging_prefix} token failed, #{error_source} error" + message = "#{config.log_prefix} token failed, #{error_source} error" Rails.logger.error(message, status:, application:, icn:, context:) raise e, "#{message}, status: #{status}, application: #{application}, icn: #{icn}, context: #{context}" @@ -57,17 +63,25 @@ def parse_and_raise_error(e, icn, application) def parse_response(response, application, icn) response_body = response.body + validate_map_token(response_body['access_token']) { access_token: response_body['access_token'], expiration: Time.zone.now + response_body['expires_in'] } + rescue JWT::DecodeError => e + raise e rescue => e - message = "#{config.logging_prefix} token failed, response unknown" + message = "#{config.log_prefix} token failed, response unknown" Rails.logger.error(message, application:, icn:) raise e, "#{message}, application: #{application}, icn: #{icn}" end + def validate_map_token(encoded_token) + public_keys = public_jwks.keys.map(&:public_key) + JWT.decode(encoded_token, public_keys, true, { algorithms: ['RS512'] }) + end + def client_id_from_application(application) case application when :chatbot @@ -79,14 +93,12 @@ def client_id_from_application(application) when :appointments config.appointments_client_id else - raise Errors::ApplicationMismatchError, "#{config.logging_prefix} token failed, application mismatch detected" + raise Errors::ApplicationMismatchError, "#{config.log_prefix} token failed, application mismatch detected" end end def token_params(application, icn) - unless icn - raise Errors::MissingICNError, "#{config.logging_prefix} token failed, ICN not present in access token" - end + raise Errors::MissingICNError, "#{config.log_prefix} token failed, ICN not present in access token" unless icn client_id = client_id_from_application(application) URI.encode_www_form({ grant_type: config.grant_type, diff --git a/modules/check_in/spec/requests/check_in/v2/sessions/appointments_spec.rb b/modules/check_in/spec/requests/check_in/v2/sessions/appointments_spec.rb index 0578be530f0..c82666ad409 100644 --- a/modules/check_in/spec/requests/check_in/v2/sessions/appointments_spec.rb +++ b/modules/check_in/spec/requests/check_in/v2/sessions/appointments_spec.rb @@ -212,7 +212,7 @@ VCR.use_cassette 'check_in/clinics/get_clinics_200' do VCR.use_cassette 'check_in/facilities/get_facilities_200' do VCR.use_cassette 'check_in/appointments/get_appointments_200' do - VCR.use_cassette 'check_in/map/security_token_service_200' do + VCR.use_cassette 'map/security_token_service_200_response' do get "/check_in/v2/sessions/#{id}/appointments", params: { start: start_date, end: end_date } end end @@ -302,7 +302,7 @@ VCR.use_cassette 'check_in/clinics/get_clinics_200' do VCR.use_cassette 'check_in/facilities/get_facilities_200' do VCR.use_cassette 'check_in/appointments/get_appointments_without_location_200' do - VCR.use_cassette 'check_in/map/security_token_service_200' do + VCR.use_cassette 'map/security_token_service_200_response' do get "/check_in/v2/sessions/#{id}/appointments", params: { start: start_date, end: end_date } end end @@ -390,7 +390,7 @@ it 'returns appointments' do VCR.use_cassette 'check_in/facilities/get_facilities_200' do VCR.use_cassette 'check_in/appointments/get_appointments_without_clinic_200' do - VCR.use_cassette 'check_in/map/security_token_service_200' do + VCR.use_cassette 'map/security_token_service_200_response' do get "/check_in/v2/sessions/#{id}/appointments", params: { start: start_date, end: end_date } end end @@ -417,7 +417,7 @@ it 'returns error' do VCR.use_cassette 'check_in/appointments/get_appointments_500' do - VCR.use_cassette 'check_in/map/security_token_service_200' do + VCR.use_cassette 'map/security_token_service_200_response' do get "/check_in/v2/sessions/#{id}/appointments", params: { start: start_date, end: end_date } end end @@ -444,7 +444,7 @@ it 'returns error' do VCR.use_cassette 'check_in/facilities/get_facilities_500' do VCR.use_cassette 'check_in/appointments/get_appointments_200' do - VCR.use_cassette 'check_in/map/security_token_service_200' do + VCR.use_cassette 'map/security_token_service_200_response' do get "/check_in/v2/sessions/#{id}/appointments", params: { start: start_date, end: end_date } end end @@ -473,7 +473,7 @@ VCR.use_cassette 'check_in/clinics/get_clinics_500' do VCR.use_cassette 'check_in/facilities/get_facilities_200' do VCR.use_cassette 'check_in/appointments/get_appointments_200' do - VCR.use_cassette 'check_in/map/security_token_service_200' do + VCR.use_cassette 'map/security_token_service_200_response' do get "/check_in/v2/sessions/#{id}/appointments", params: { start: start_date, end: end_date } end end diff --git a/spec/fixtures/map/jwks.json b/spec/fixtures/map/jwks.json new file mode 100644 index 00000000000..691e787f95e --- /dev/null +++ b/spec/fixtures/map/jwks.json @@ -0,0 +1,12 @@ +{ + "keys": [ + { + "kty": "RSA", + "e": "AQAB", + "use": "sig", + "kid": "c9233bd7a62406b325c3cbf9778ea1ec75fa6de587640ee6d522e1bda2251277", + "alg": "RS512", + "n": "rGRLjxGb2ygtXWEEC99h5Z__PrAAqf0_wXQcFDnbV1bCp2rfv1xprPS-Mhi_mLh4YVBVKfD5vz0X9eHq1ieua_prgIgloT4doOzphkPTVoALQcm7HmBEWOs3r_nOIZMyOomPb-i4EqNITqD-qEdxGce5-GuopT1BotKzwtX5m7YlqviLFvyCQIRxr1C8GspAjyrODZVTTiKN0nyQKO3EUQZ2ietC52sbnSlnFOHbIpRP1mBrRvkELYIk8gfInMNvSk98SeWd2dDGe48OKNAzR2zGWYwIvxChBAoxahQ1Rh89WF1zKWIRTxYTuBJP3owBJdcfDcvTxovW5y6ciL0KyJKkZgyRJuBvIt8P9tEus8ef9s_3dRnKJi46uRolre5snXWIAAf-fUZvHdnwPLfANgqpNauVPwjtC_MGvbXYALdyCpIUmuRhWX_OHWYl7PTjllMezjVNylSK-2QVc6M7U3OXt00Q8poRKEUquowNPgbNaQnBzOtOEnpqCNIl0_86Qf8QLoSbdF4B0Yr2LJPraPsFxT3xdbcg9bS8vvGWJ2a2KmLqDKmpm6e9Cr3QZ-2-rUBn4KURjnV2KWQM-6tYwUTV0o467OaCNwkUSOqaPUuMbRHR7L5YTuA8BkJsPv_6pZe3VD74N9kbSMlt7RC2Qo2FCyxRwUtdSzTjheJwrvs" + } + ] +} \ No newline at end of file diff --git a/spec/lib/map/security_token/service_spec.rb b/spec/lib/map/security_token/service_spec.rb index 1ca9a7a6266..7a0f16594cf 100644 --- a/spec/lib/map/security_token/service_spec.rb +++ b/spec/lib/map/security_token/service_spec.rb @@ -14,8 +14,21 @@ let(:log_prefix) { '[MAP][SecurityToken][Service]' } let(:expected_request_message) { "#{log_prefix} token request" } let(:expected_request_payload) { { application:, icn: } } + let(:jwks_cache_key) { 'map_public_jwks' } + let(:jwk_payload) { JSON.parse(File.read('spec/fixtures/map/jwks.json'))['keys'].first } + let(:map_jwks) { JWT::JWK::Set.new([jwk_payload]) } + let(:redis_store) { ActiveSupport::Cache::RedisCacheStore.new(redis: MockRedis.new) } shared_examples 'STS token request' do + before do + allow(Rails).to receive(:cache).and_return(redis_store) + Rails.cache.write(jwks_cache_key, map_jwks) + end + + after do + Rails.cache.clear + end + it 'logs the token request' do VCR.use_cassette('map/security_token_service_200_response') do expect(Rails.logger).to receive(:info).with(expected_request_message, expected_request_payload) @@ -144,6 +157,49 @@ let(:expected_log_message) { "#{log_prefix} token success" } let(:expected_log_payload) { { application:, icn:, cached_response: false } } + context 'when validating the response token' do + before do + described_class.configuration.instance_variable_set(:@public_jwks, nil) + allow(Rails.logger).to receive(:info) + end + + context 'when obtaining the MAP STS JWKs' do + context 'and the MAP STS JWKs are not cached' do + before { Rails.cache.clear } + + it 'makes a request to the MAP STS JWKs endpoint' do + VCR.use_cassette('map/security_token_service_200_response') do + expect(Rails.logger).to receive(:info).with("#{log_prefix} Get Public JWKs Success") + subject + end + end + end + + context 'and the MAP STS JWKs are cached' do + it 'does not make a request to the MAP STS JWKs endpoint' do + VCR.use_cassette('map/security_token_service_200_response') do + expect(Rails.cache).not_to receive(:write).with(jwks_cache_key, anything) + expect(Rails.logger).not_to receive(:info).with("#{log_prefix} Get Public JWKs Success") + subject + end + end + end + end + + context 'when response is an invalid token', + vcr: { cassette_name: 'map/security_token_service_200_invalid_token' } do + let(:expected_error) { JWT::DecodeError } + let(:expected_error_context) { 'Signature verification failed' } + let(:expected_logger_message) { "#{log_prefix} token failed, JWT decode error" } + let(:expected_log_values) { { application:, icn:, context: expected_error_context } } + + it 'raises a JWT Decode error and creates a log' do + expect(Rails.logger).to receive(:error).with(expected_logger_message, expected_log_values) + expect { subject }.to raise_exception(expected_error, expected_error_context) + end + end + end + it 'logs a token success message', vcr: { cassette_name: 'map/security_token_service_200_response' } do expect(Rails.logger).to receive(:info).with(expected_request_message, { application:, icn: }) diff --git a/spec/lib/map/sign_up/service_spec.rb b/spec/lib/map/sign_up/service_spec.rb index 4192942a627..7f49b69a4ec 100644 --- a/spec/lib/map/sign_up/service_spec.rb +++ b/spec/lib/map/sign_up/service_spec.rb @@ -126,7 +126,7 @@ let(:expected_log_message) { "#{log_prefix} agreements accept success, icn: #{icn}" } before do - Timecop.freeze(Time.zone.local(2023, 1, 1, 12, 0, 0)) + Timecop.freeze(Time.zone.local(2024, 9, 1, 12, 0, 0)) allow(Rails.logger).to receive(:info) end diff --git a/spec/requests/v0/map_services_spec.rb b/spec/requests/v0/map_services_spec.rb index ffc05c67261..4198b4d2e57 100644 --- a/spec/requests/v0/map_services_spec.rb +++ b/spec/requests/v0/map_services_spec.rb @@ -93,7 +93,25 @@ end end - context 'when MAP STS client returns an access token', + context 'when MAP STS client returns an invalid token', + vcr: { cassette_name: 'map/security_token_service_200_invalid_token' } do + it 'responds with error details in response body' do + call_endpoint + expect(JSON.parse(response.body)).to eq( + { + 'error' => 'server_error', + 'error_description' => 'STS failed to return a valid token.' + } + ) + end + + it 'returns HTTP status bad_gateway' do + call_endpoint + expect(response).to have_http_status(:bad_gateway) + end + end + + context 'when MAP STS client returns a valid access token', vcr: { cassette_name: 'map/security_token_service_200_response' } do it 'responds with STS-issued token in response body' do call_endpoint diff --git a/spec/support/vcr_cassettes/check_in/map/security_token_service_401.yml b/spec/support/vcr_cassettes/check_in/map/security_token_service_401.yml deleted file mode 100644 index 501d3d68937..00000000000 --- a/spec/support/vcr_cassettes/check_in/map/security_token_service_401.yml +++ /dev/null @@ -1,72 +0,0 @@ ---- -http_interactions: - - request: - method: post - uri: https://veteran.apps-staging.va.gov/sts/oauth/v1/token - body: - encoding: US-ASCII - string: grant_type=client_credentials&client_id=c7d6e0fc9a39&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJhbGciOiJSUzUxMiJ9.eyJyb2xlIjoidmV0ZXJhbiIsInBhdGllbnRfaWQiOiJzb21lLWljbiIsInBhdGllbnRfaWRfdHlwZSI6ImljbiIsInN1YiI6ImM3ZDZlMGZjOWEzOSIsImp0aSI6IjIwODllOWFlLTZiNDctNGJkNy05NzNiLTczMzM4NjgzYTVkYiIsImlzcyI6ImM3ZDZlMGZjOWEzOSIsImF1ZCI6Imh0dHBzOi8vZ29vZ2xlLmNvbS9zdHMvb2F1dGgvdjEvdG9rZW4iLCJuYmYiOjE2OTI5MjE5NjcsImV4cCI6MTY5MjkyMjI2N30.VXzWaXBjk83TNA39VTApJQSG9inwyUioYouGXeqkEWicSP3oLb-CNFpkEgkMNccz6SpAlYIJ_KYKRFAA1rQv8Gp5LzIv_YM2WFJUYxpF02-fAhYzl6SkOLwD86Yto6a8JbFrNPL9uYxG1vmTZgl_vk2dmNFpnQ3gf8bXc2GOBAM2gc3tzNjv1M18dVtObX6zw7ZG7drxw7itzZnkDLTU9217XyOgSFQvA0czRiiRcfsXb6LIB7A1k7MpQy6KA3UDBQ7sbuXkaFZiJo2tSDG3PXScTHBtqmqejCt68906wiBf_ACeI4TQPH4ogoTrnfb9oprQyKp8xMlwwKYAMih12g - headers: - Accept: - - application/json - Content-Type: - - application/x-www-form-urlencoded - User-Agent: - - Vets.gov Agent - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - response: - status: - code: 401 - message: Unauthorized - headers: - Content-Type: - - application/json; charset=utf-8 - X-Frame-Options: - - allow-from https://nextgenid-mbetenantworkflow.azurewebsites.net - X-Xss-Protection: - - 1; mode=block - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Permitted-Cross-Domain-Policies: - - none - Referrer-Policy: - - strict-origin-when-cross-origin - Content-Security-Policy: - - frame-ancestors https://nextgenid-mbetenantworkflow.azurewebsites.net - Etag: - - W/"dba68a519b00d7f452e79971a398650f" - X-Request-Id: - - 5b1d220c-4b01-4409-b9a5-367ab3c99ca9 - X-Runtime: - - '0.026178' - Strict-Transport-Security: - - max-age=63072000; includeSubDomains - X-Node: - - sandbox-core-02.idmeinc.net - Vary: - - Accept-Encoding - Expires: - - Wed, 26 Jul 2023 19:56:07 GMT - Cache-Control: - - max-age=0, no-cache, no-store - Pragma: - - no-cache - Date: - - Wed, 26 Jul 2023 19:56:07 GMT - Content-Length: - - '14658' - Connection: - - keep-alive - Server-Timing: - - ak_p; desc="1690401366974_1752320020_1303469004_11342_12901_31_-_-";dur=1 - - cdn-cache; desc=MISS - - edge; dur=68 - - origin; dur=46 - body: - encoding: UTF-8 - string: '{"error":"invalid_client"}' - recorded_at: Wed, 26 Oct 2022 18:30:02 GMT -recorded_with: VCR 6.1.0 diff --git a/spec/support/vcr_cassettes/check_in/map/security_token_service_200.yml b/spec/support/vcr_cassettes/map/security_token_service_200_invalid_token.yml similarity index 60% rename from spec/support/vcr_cassettes/check_in/map/security_token_service_200.yml rename to spec/support/vcr_cassettes/map/security_token_service_200_invalid_token.yml index 14d618ccc38..348bb3687b4 100644 --- a/spec/support/vcr_cassettes/check_in/map/security_token_service_200.yml +++ b/spec/support/vcr_cassettes/map/security_token_service_200_invalid_token.yml @@ -69,4 +69,73 @@ http_interactions: encoding: UTF-8 string: '{"access_token":"eyJhbGciOiJSUzUxMiJ9.eyJsYXN0TmFtZSI6Im9hdXRoLWNsaWVudCIsInN1YiI6ImM3ZDZlMGZjOWEzOSIsImF1dGhlbnRpY2F0ZWQiOnRydWUsImF1dGhlbnRpY2F0aW9uQXV0aG9yaXR5IjoiZ292LnZhLm1vYmlsZS5vYXV0aC52MSIsImlkVHlwZSI6Ik1PQklMRV9PQVVUSF9TVFNfQ0xJRU5UX0lEIiwiaXNzIjoiZ292LnZhLnZhbWYudXNlcnNlcnZpY2UudjIiLCJvbkJlaGFsZk9mIjp7ImlkVHlwZSI6ImljbiIsImlkIjoiMTAxMjcwNDY4NlYxNTk4ODcifSwidmFtZi5hdXRoLnJlc291cmNlcyI6WyJeLiooXC8pP3NpdGVbc10_XC8oZGZuLSk_NDUzXC9wYXRpZW50W3NdP1wvMzUxODVcL2FwcG9pbnRtZW50cyhcLy4qKT8kIiwiXi4qKFwvKT9wYXRpZW50W3NdP1wvRURJUElcLzE2MDc2OTQ5MDMoXC8uKik_JCIsIl4uKihcLyk_cGF0aWVudFtzXT9cLyhJQ05cLyk_MTAxMjcwNDY4NlYxNTk4ODcoXC8uKik_JCJdLCJ2ZXJzaW9uIjoyLjgsImZpcnN0TmFtZSI6IlZBLmdvdiBTaWdudXAgKFNRQSkiLCJhdWQiOiJjN2Q2ZTBmYzlhMzkiLCJuYmYiOjE2OTI5MjExMTMsInNzdCI6MTY5MjkyMTI5MywidmFtZi5hdXRoLnJvbGVzIjpbInZldGVyYW4iXSwidXNlclR5cGUiOiJvbi1iZWhhbGYtb2YiLCJleHAiOjE2OTI5MjIxOTMsImlhdCI6MTY5MjkyMTI5MywianRpIjoiMzQ2M2I4YjQtM2Y5Zi00ZTZiLWIzYjItNzBlMGEwOGM4OTE4In0.LXAxWbzCmVZEothmkV3CFi5Jitx8MYnmkPSIqOkWghOz2wZJV7SX96bBhZ3zK5xUYlxwQ_ElwKU3otb47IeWK3XflbW1K1m8HbZ5qtKgfofv4sk0xM7UEafRQdmLGQOX0ClqbmMrNss12z5Ay0BSBpltoBGekKyRcwRerhP35o4d0uHKDY8JanhljylZupfO8e5Kpx8R0UfL1rXRXjhAWTbf23oJOB8onvJ_RZz1YHXQU-M34-faj_iHKrms3t9h7n3fhJKYciYOAfxN2feeOpFJ95Zt-mJGARUY3ryeIXFm5HJjL1KTjZ1eB9NmX7H2ST3uqax0PY5biYiiwX1a2g","token_type":"Bearer","expires_in":899}' recorded_at: Wed, 26 Oct 2022 18:30:02 GMT +- request: + method: get + uri: https://veteran.apps-staging.va.gov/sts/oauth/v1/jwks + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + Content-Type: + - application/x-www-form-urlencoded + User-Agent: + - Vets.gov Agent + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=utf-8 + X-Frame-Options: + - allow-from https://nextgenid-mbetenantworkflow.azurewebsites.net + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Content-Security-Policy: + - frame-ancestors https://nextgenid-mbetenantworkflow.azurewebsites.net + Etag: + - W/"dba68a519b00d7f452e79971a398650f" + X-Request-Id: + - 5b1d220c-4b01-4409-b9a5-367ab3c99ca9 + X-Runtime: + - '0.026178' + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Node: + - sandbox-core-02.idmeinc.net + Vary: + - Accept-Encoding + Expires: + - Wed, 26 Jul 2023 19:56:07 GMT + Cache-Control: + - max-age=0, no-cache, no-store + Pragma: + - no-cache + Date: + - Wed, 26 Jul 2023 19:56:07 GMT + Content-Length: + - '14658' + Connection: + - keep-alive + Server-Timing: + - ak_p; desc="1690401366974_1752320020_1303469004_11342_12901_31_-_-";dur=1 + - cdn-cache; desc=MISS + - edge; dur=68 + - origin; dur=46 + body: + encoding: UTF-8 + string: '{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"c9233bd7a62406b325c3cbf9778ea1ec75fa6de587640ee6d522e1bda2251277","alg":"RS512","n":"rGRLjxGb2ygtXWEEC99h5Z__PrAAqf0_wXQcFDnbV1bCp2rfv1xprPS-Mhi_mLh4YVBVKfD5vz0X9eHq1ieua_prgIgloT4doOzphkPTVoALQcm7HmBEWOs3r_nOIZMyOomPb-i4EqNITqD-qEdxGce5-GuopT1BotKzwtX5m7YlqviLFvyCQIRxr1C8GspAjyrODZVTTiKN0nyQKO3EUQZ2ietC52sbnSlnFOHbIpRP1mBrRvkELYIk8gfInMNvSk98SeWd2dDGe48OKNAzR2zGWYwIvxChBAoxahQ1Rh89WF1zKWIRTxYTuBJP3owBJdcfDcvTxovW5y6ciL0KyJKkZgyRJuBvIt8P9tEus8ef9s_3dRnKJi46uRolre5snXWIAAf-fUZvHdnwPLfANgqpNauVPwjtC_MGvbXYALdyCpIUmuRhWX_OHWYl7PTjllMezjVNylSK-2QVc6M7U3OXt00Q8poRKEUquowNPgbNaQnBzOtOEnpqCNIl0_86Qf8QLoSbdF4B0Yr2LJPraPsFxT3xdbcg9bS8vvGWJ2a2KmLqDKmpm6e9Cr3QZ-2-rUBn4KURjnV2KWQM-6tYwUTV0o467OaCNwkUSOqaPUuMbRHR7L5YTuA8BkJsPv_6pZe3VD74N9kbSMlt7RC2Qo2FCyxRwUtdSzTjheJwrvs"}]}' + recorded_at: Wed, 26 Oct 2022 18:30:02 GMT recorded_with: VCR 6.1.0 diff --git a/spec/support/vcr_cassettes/map/security_token_service_200_response.yml b/spec/support/vcr_cassettes/map/security_token_service_200_response.yml index 14d618ccc38..417e0d3f6a7 100644 --- a/spec/support/vcr_cassettes/map/security_token_service_200_response.yml +++ b/spec/support/vcr_cassettes/map/security_token_service_200_response.yml @@ -67,6 +67,75 @@ http_interactions: - origin; dur=46 body: encoding: UTF-8 - string: '{"access_token":"eyJhbGciOiJSUzUxMiJ9.eyJsYXN0TmFtZSI6Im9hdXRoLWNsaWVudCIsInN1YiI6ImM3ZDZlMGZjOWEzOSIsImF1dGhlbnRpY2F0ZWQiOnRydWUsImF1dGhlbnRpY2F0aW9uQXV0aG9yaXR5IjoiZ292LnZhLm1vYmlsZS5vYXV0aC52MSIsImlkVHlwZSI6Ik1PQklMRV9PQVVUSF9TVFNfQ0xJRU5UX0lEIiwiaXNzIjoiZ292LnZhLnZhbWYudXNlcnNlcnZpY2UudjIiLCJvbkJlaGFsZk9mIjp7ImlkVHlwZSI6ImljbiIsImlkIjoiMTAxMjcwNDY4NlYxNTk4ODcifSwidmFtZi5hdXRoLnJlc291cmNlcyI6WyJeLiooXC8pP3NpdGVbc10_XC8oZGZuLSk_NDUzXC9wYXRpZW50W3NdP1wvMzUxODVcL2FwcG9pbnRtZW50cyhcLy4qKT8kIiwiXi4qKFwvKT9wYXRpZW50W3NdP1wvRURJUElcLzE2MDc2OTQ5MDMoXC8uKik_JCIsIl4uKihcLyk_cGF0aWVudFtzXT9cLyhJQ05cLyk_MTAxMjcwNDY4NlYxNTk4ODcoXC8uKik_JCJdLCJ2ZXJzaW9uIjoyLjgsImZpcnN0TmFtZSI6IlZBLmdvdiBTaWdudXAgKFNRQSkiLCJhdWQiOiJjN2Q2ZTBmYzlhMzkiLCJuYmYiOjE2OTI5MjExMTMsInNzdCI6MTY5MjkyMTI5MywidmFtZi5hdXRoLnJvbGVzIjpbInZldGVyYW4iXSwidXNlclR5cGUiOiJvbi1iZWhhbGYtb2YiLCJleHAiOjE2OTI5MjIxOTMsImlhdCI6MTY5MjkyMTI5MywianRpIjoiMzQ2M2I4YjQtM2Y5Zi00ZTZiLWIzYjItNzBlMGEwOGM4OTE4In0.LXAxWbzCmVZEothmkV3CFi5Jitx8MYnmkPSIqOkWghOz2wZJV7SX96bBhZ3zK5xUYlxwQ_ElwKU3otb47IeWK3XflbW1K1m8HbZ5qtKgfofv4sk0xM7UEafRQdmLGQOX0ClqbmMrNss12z5Ay0BSBpltoBGekKyRcwRerhP35o4d0uHKDY8JanhljylZupfO8e5Kpx8R0UfL1rXRXjhAWTbf23oJOB8onvJ_RZz1YHXQU-M34-faj_iHKrms3t9h7n3fhJKYciYOAfxN2feeOpFJ95Zt-mJGARUY3ryeIXFm5HJjL1KTjZ1eB9NmX7H2ST3uqax0PY5biYiiwX1a2g","token_type":"Bearer","expires_in":899}' + string: '{"access_token":"eyJhbGciOiJSUzUxMiJ9.eyJsYXN0TmFtZSI6Im9hdXRoLWNsaWVudCIsInN1YiI6ImM3ZDZlMGZjOWEzOSIsImF1dGhlbnRpY2F0ZWQiOnRydWUsImF1dGhlbnRpY2F0aW9uQXV0aG9yaXR5IjoiZ292LnZhLm1vYmlsZS5vYXV0aC52MSIsImlkVHlwZSI6Ik1PQklMRV9PQVVUSF9TVFNfQ0xJRU5UX0lEIiwiaXNzIjoiZ292LnZhLnZhbWYudXNlcnNlcnZpY2UudjIiLCJvbkJlaGFsZk9mIjp7ImlkVHlwZSI6ImljbiIsImlkIjoiMTAxMjcwNDY4NlYxNTk4ODcifSwidmFtZi5hdXRoLnJlc291cmNlcyI6WyJeLiooLyk_c2l0ZVtzXT8vKGRmbi0pPzQ1My9wYXRpZW50W3NdPy8zNTE4NS9hcHBvaW50bWVudHMoLy4qKT8kIiwiXi4qKC8pP3BhdGllbnRbc10_L0VESVBJLzE2MDc2OTQ5MDMoLy4qKT8kIiwiXi4qKC8pP3BhdGllbnRbc10_LyhJQ04vKT8xMDEyNzA0Njg2VjE1OTg4NygvLiopPyQiXSwidmVyc2lvbiI6Mi44LCJmaXJzdE5hbWUiOiJWQS5nb3YgU2lnbnVwIChTUUEpIiwiYXVkIjoiYzdkNmUwZmM5YTM5IiwibmJmIjoxNjkyOTIxMTEzLCJzc3QiOjE2OTI5MjEyOTMsInZhbWYuYXV0aC5yb2xlcyI6WyJ2ZXRlcmFuIl0sInVzZXJUeXBlIjoib24tYmVoYWxmLW9mIiwiZXhwIjoyMDkyOTIyMTkzLCJpYXQiOjE2OTI5MjEyOTMsImp0aSI6IjM0NjNiOGI0LTNmOWYtNGU2Yi1iM2IyLTcwZTBhMDhjODkxOCJ9.Hbl4IWvV6zsPS9oeFAtzeCTMxPvlPkmJy11WzOLk4TV3-XEwn3c5rRz1ZISpOGiFsnmOq4faYpiLS8g3QCyjetJSbH9JU1QSXU9s6xGbBTGg1rmWzUyePUbvMukPsF5Ig-oqdTs_K58J3ylUOANJKv6DRd3PsYjlWvMqpyiNH63NCqmvN2RyhUO_Q4sRw-lA-sFhGBvuUeeiZL9kt9UeuwTvKJLR5eYhwB_aZI4XLoF3Cmlnje4p8hxaRMzGF6h_9WbA0j8M0GP1r5NkAoVqgmZ2Cs9WwTViOd7xKFLkdX67ZYRyvbjvoejrvkl85Vi2cWTAH7piCeQSRx3r_Dg-fw-53iu5IHC_0nhwhx-VdvSIoSGya_qRowzEzOaITQv5JxXZzgh2Cb5HdzcFBPb6k-MB_rSZh6htSpF9g64vzHGlJjOwa4zUQcab6QnIayJcg8OjF0JK5rtUe3_Vl3Y2_S-0RdogORNW61swjlG7UcZxUegn4Ac3XOxlHKEBUDCeZK_6nWzPmYJzUSPlVU_vQCnF04kCE34dlH3LGgpaT_s_aysyILl7J76hvl526muHx_3dyoliGgDB08LAJtXn56NeqrGzmnv_sli0V-spB4h6bnvMdqc1YSXARpoRiKms9l8SLspyWRikhreMzzon1ajUdXS0mEroxPPJZCq_s9c","token_type":"Bearer","expires_in":899}' + recorded_at: Wed, 26 Oct 2022 18:30:02 GMT +- request: + method: get + uri: https://veteran.apps-staging.va.gov/sts/oauth/v1/jwks + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + Content-Type: + - application/x-www-form-urlencoded + User-Agent: + - Vets.gov Agent + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=utf-8 + X-Frame-Options: + - allow-from https://nextgenid-mbetenantworkflow.azurewebsites.net + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Content-Security-Policy: + - frame-ancestors https://nextgenid-mbetenantworkflow.azurewebsites.net + Etag: + - W/"dba68a519b00d7f452e79971a398650f" + X-Request-Id: + - 5b1d220c-4b01-4409-b9a5-367ab3c99ca9 + X-Runtime: + - '0.026178' + Strict-Transport-Security: + - max-age=63072000; includeSubDomains + X-Node: + - sandbox-core-02.idmeinc.net + Vary: + - Accept-Encoding + Expires: + - Wed, 26 Jul 2023 19:56:07 GMT + Cache-Control: + - max-age=0, no-cache, no-store + Pragma: + - no-cache + Date: + - Wed, 26 Jul 2023 19:56:07 GMT + Content-Length: + - '14658' + Connection: + - keep-alive + Server-Timing: + - ak_p; desc="1690401366974_1752320020_1303469004_11342_12901_31_-_-";dur=1 + - cdn-cache; desc=MISS + - edge; dur=68 + - origin; dur=46 + body: + encoding: UTF-8 + string: '{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"c9233bd7a62406b325c3cbf9778ea1ec75fa6de587640ee6d522e1bda2251277","alg":"RS512","n":"rGRLjxGb2ygtXWEEC99h5Z__PrAAqf0_wXQcFDnbV1bCp2rfv1xprPS-Mhi_mLh4YVBVKfD5vz0X9eHq1ieua_prgIgloT4doOzphkPTVoALQcm7HmBEWOs3r_nOIZMyOomPb-i4EqNITqD-qEdxGce5-GuopT1BotKzwtX5m7YlqviLFvyCQIRxr1C8GspAjyrODZVTTiKN0nyQKO3EUQZ2ietC52sbnSlnFOHbIpRP1mBrRvkELYIk8gfInMNvSk98SeWd2dDGe48OKNAzR2zGWYwIvxChBAoxahQ1Rh89WF1zKWIRTxYTuBJP3owBJdcfDcvTxovW5y6ciL0KyJKkZgyRJuBvIt8P9tEus8ef9s_3dRnKJi46uRolre5snXWIAAf-fUZvHdnwPLfANgqpNauVPwjtC_MGvbXYALdyCpIUmuRhWX_OHWYl7PTjllMezjVNylSK-2QVc6M7U3OXt00Q8poRKEUquowNPgbNaQnBzOtOEnpqCNIl0_86Qf8QLoSbdF4B0Yr2LJPraPsFxT3xdbcg9bS8vvGWJ2a2KmLqDKmpm6e9Cr3QZ-2-rUBn4KURjnV2KWQM-6tYwUTV0o467OaCNwkUSOqaPUuMbRHR7L5YTuA8BkJsPv_6pZe3VD74N9kbSMlt7RC2Qo2FCyxRwUtdSzTjheJwrvs"}]}' recorded_at: Wed, 26 Oct 2022 18:30:02 GMT recorded_with: VCR 6.1.0 diff --git a/spec/support/vcr_cassettes/map/sign_up_service_200_responses.yml b/spec/support/vcr_cassettes/map/sign_up_service_200_responses.yml index 3c0ea903a8f..33abefd9213 100644 --- a/spec/support/vcr_cassettes/map/sign_up_service_200_responses.yml +++ b/spec/support/vcr_cassettes/map/sign_up_service_200_responses.yml @@ -74,7 +74,7 @@ http_interactions: uri: https://cerner.apps-staging.va.gov/signup/v1/patients/10101V964144/agreements body: encoding: US-ASCII - string: '{"responseDate":"2023-01-01T12:00:00.000Z","icn":"10101V964144","signatureName":"some-signature-name","version":3,"legalDisplayVersion":1.0}' + string: '{"responseDate":"2024-09-01T12:00:00.000Z","icn":"10101V964144","signatureName":"some-signature-name","version":3,"legalDisplayVersion":1.0}' headers: Accept: - application/json