cybersource_rest_client 0.0.79 → 0.0.81
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/lib/AuthenticationSDK/authentication/jwt/JwtToken.rb +17 -7
- data/lib/AuthenticationSDK/core/Authorization.rb +2 -2
- data/lib/AuthenticationSDK/core/MerchantConfig.rb +278 -23
- data/lib/AuthenticationSDK/util/Cache.rb +158 -8
- data/lib/AuthenticationSDK/util/CachedMLEKId.rb +17 -0
- data/lib/AuthenticationSDK/util/CertificateUtility.rb +109 -29
- data/lib/AuthenticationSDK/util/Constants.rb +6 -0
- data/lib/AuthenticationSDK/util/JWT/JWTExceptions.rb +81 -0
- data/lib/AuthenticationSDK/util/JWT/JWTUtility.rb +154 -0
- data/lib/AuthenticationSDK/util/MLEUtility.rb +167 -11
- data/lib/AuthenticationSDK/util/Utility.rb +37 -1
- data/lib/cybersource_rest_client/api/bank_account_validation_api.rb +13 -5
- data/lib/cybersource_rest_client/api/batches_api.rb +50 -18
- data/lib/cybersource_rest_client/api/billing_agreements_api.rb +33 -9
- data/lib/cybersource_rest_client/api/bin_lookup_api.rb +11 -3
- data/lib/cybersource_rest_client/api/capture_api.rb +11 -3
- data/lib/cybersource_rest_client/api/chargeback_details_api.rb +11 -3
- data/lib/cybersource_rest_client/api/chargeback_summaries_api.rb +11 -3
- data/lib/cybersource_rest_client/api/conversion_details_api.rb +11 -3
- data/lib/cybersource_rest_client/api/create_new_webhooks_api.rb +35 -11
- data/lib/cybersource_rest_client/api/credit_api.rb +11 -3
- data/lib/cybersource_rest_client/api/customer_api.rb +44 -12
- data/lib/cybersource_rest_client/api/customer_payment_instrument_api.rb +55 -15
- data/lib/cybersource_rest_client/api/customer_shipping_address_api.rb +55 -15
- data/lib/cybersource_rest_client/api/decision_manager_api.rb +57 -17
- data/lib/cybersource_rest_client/api/device_de_association_api.rb +24 -8
- data/lib/cybersource_rest_client/api/device_search_api.rb +26 -10
- data/lib/cybersource_rest_client/api/download_dtd_api.rb +11 -3
- data/lib/cybersource_rest_client/api/download_xsd_api.rb +11 -3
- data/lib/cybersource_rest_client/api/emv_tag_details_api.rb +22 -6
- data/lib/cybersource_rest_client/api/enrollment_api.rb +104 -0
- data/lib/cybersource_rest_client/api/flex_api_api.rb +11 -3
- data/lib/cybersource_rest_client/api/instructions_api.rb +452 -0
- data/lib/cybersource_rest_client/api/instrument_identifier_api.rb +66 -18
- data/lib/cybersource_rest_client/api/interchange_clearing_level_details_api.rb +11 -3
- data/lib/cybersource_rest_client/api/invoice_settings_api.rb +22 -6
- data/lib/cybersource_rest_client/api/invoices_api.rb +77 -21
- data/lib/cybersource_rest_client/api/manage_webhooks_api.rb +81 -25
- data/lib/cybersource_rest_client/api/merchant_boarding_api.rb +24 -8
- data/lib/cybersource_rest_client/api/merchant_defined_fields_api.rb +50 -18
- data/lib/cybersource_rest_client/api/microform_integration_api.rb +11 -3
- data/lib/cybersource_rest_client/api/net_fundings_api.rb +11 -3
- data/lib/cybersource_rest_client/api/notification_of_changes_api.rb +11 -3
- data/lib/cybersource_rest_client/api/offers_api.rb +24 -8
- data/lib/cybersource_rest_client/api/orders_api.rb +22 -6
- data/lib/cybersource_rest_client/api/payer_authentication_api.rb +33 -9
- data/lib/cybersource_rest_client/api/payment_batch_summaries_api.rb +11 -3
- data/lib/cybersource_rest_client/api/payment_instrument_api.rb +44 -12
- data/lib/cybersource_rest_client/api/payment_links_api.rb +44 -12
- data/lib/cybersource_rest_client/api/payment_tokens_api.rb +11 -3
- data/lib/cybersource_rest_client/api/payments_api.rb +66 -18
- data/lib/cybersource_rest_client/api/payouts_api.rb +11 -3
- data/lib/cybersource_rest_client/api/plans_api.rb +88 -24
- data/lib/cybersource_rest_client/api/purchase_and_refund_details_api.rb +11 -3
- data/lib/cybersource_rest_client/api/push_funds_api.rb +11 -3
- data/lib/cybersource_rest_client/api/refund_api.rb +22 -6
- data/lib/cybersource_rest_client/api/report_definitions_api.rb +22 -6
- data/lib/cybersource_rest_client/api/report_downloads_api.rb +11 -3
- data/lib/cybersource_rest_client/api/report_subscriptions_api.rb +55 -15
- data/lib/cybersource_rest_client/api/reports_api.rb +33 -9
- data/lib/cybersource_rest_client/api/retrieval_details_api.rb +11 -3
- data/lib/cybersource_rest_client/api/retrieval_summaries_api.rb +11 -3
- data/lib/cybersource_rest_client/api/reversal_api.rb +22 -6
- data/lib/cybersource_rest_client/api/search_transactions_api.rb +22 -6
- data/lib/cybersource_rest_client/api/secure_file_share_api.rb +22 -6
- data/lib/cybersource_rest_client/api/subscriptions_api.rb +97 -33
- data/lib/cybersource_rest_client/api/subscriptions_follow_ons_api.rb +22 -6
- data/lib/cybersource_rest_client/api/taxes_api.rb +22 -6
- data/lib/cybersource_rest_client/api/token_api.rb +24 -8
- data/lib/cybersource_rest_client/api/tokenize_api.rb +107 -0
- data/lib/cybersource_rest_client/api/tokenized_card_api.rb +126 -9
- data/lib/cybersource_rest_client/api/transaction_batches_api.rb +44 -12
- data/lib/cybersource_rest_client/api/transaction_details_api.rb +11 -3
- data/lib/cybersource_rest_client/api/transient_token_data_api.rb +22 -6
- data/lib/cybersource_rest_client/api/unified_checkout_capture_context_api.rb +11 -3
- data/lib/cybersource_rest_client/api/user_management_api.rb +11 -3
- data/lib/cybersource_rest_client/api/user_management_search_api.rb +11 -3
- data/lib/cybersource_rest_client/api/verification_api.rb +22 -6
- data/lib/cybersource_rest_client/api/void_api.rb +55 -15
- data/lib/cybersource_rest_client/api_client.rb +20 -3
- data/lib/cybersource_rest_client/models/acpv1instructions_decline_threshold.rb +232 -0
- data/lib/cybersource_rest_client/models/acpv1instructions_mandates.rb +405 -0
- data/lib/cybersource_rest_client/models/acpv1instructions_recurring_payment_information.rb +191 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconf_processor_info_payment_instrument_verifi_results.rb +213 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_confirmation_data.rb +229 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_merchant_information.rb +258 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_order_information.rb +377 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_order_information_shipping_details.rb +206 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_processor_information.rb +425 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_processor_information_payment_instrument.rb +190 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_attachments.rb +258 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_client_reference_information.rb +215 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_mandate_reference_data.rb +205 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_merchant_information.rb +334 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_merchant_information_merchant_descriptor.rb +250 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information.rb +228 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_amount_detail.rb +354 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_items.rb +367 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_items_additional_info.rb +231 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_items_policies.rb +346 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_line_items.rb +190 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_ship_to.rb +686 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_payment_options.rb +217 -0
- data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_transaction_data.rb +348 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_assurance_data.rb +313 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_authenticated_identities.rb +237 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_authentication_context.rb +191 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_bill_to.rb +400 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_buyer_information.rb +229 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_buyer_information_personal_identification.rb +212 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_consent_data.rb +297 -0
- data/lib/cybersource_rest_client/models/{rbsv1subscriptions_client_reference_information.rb → acpv1tokens_consumer_identity.rb} +73 -61
- data/lib/cybersource_rest_client/models/acpv1tokens_device_information.rb +378 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_device_information_device_data.rb +302 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_enrollment_reference_data.rb +207 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_payment_information.rb +215 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_payment_information_customer.rb +197 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_payment_information_instrument_identifier.rb +206 -0
- data/lib/cybersource_rest_client/models/acpv1tokens_payment_information_payment_instrument.rb +197 -0
- data/lib/cybersource_rest_client/models/agentic_cancel_purchase_intent_request.rb +257 -0
- data/lib/cybersource_rest_client/models/agentic_card_enrollment_bad_request_response400.rb +189 -0
- data/lib/cybersource_rest_client/models/agentic_card_enrollment_bad_request_response400_error.rb +238 -0
- data/lib/cybersource_rest_client/models/agentic_card_enrollment_bad_request_response400_error_detail.rb +224 -0
- data/lib/cybersource_rest_client/models/agentic_card_enrollment_request.rb +325 -0
- data/lib/cybersource_rest_client/models/agentic_card_enrollment_response200.rb +206 -0
- data/lib/cybersource_rest_client/models/agentic_card_enrollment_response202.rb +219 -0
- data/lib/cybersource_rest_client/models/agentic_confirm_transaction_events_request.rb +247 -0
- data/lib/cybersource_rest_client/models/agentic_confirm_transaction_events_response202.rb +195 -0
- data/lib/cybersource_rest_client/models/agentic_create_purchase_intent_request.rb +327 -0
- data/lib/cybersource_rest_client/models/agentic_create_purchase_intent_response200.rb +222 -0
- data/lib/cybersource_rest_client/models/agentic_pending_purchase_intent_response202.rb +241 -0
- data/lib/cybersource_rest_client/models/agentic_retrieve_payment_credentials_request.rb +247 -0
- data/lib/cybersource_rest_client/models/agentic_retrieve_payment_credentials_response200.rb +200 -0
- data/lib/cybersource_rest_client/models/{rbsv1plans_client_reference_information.rb → agentic_retrieve_payment_credentials_response200_transaction_response_complete.rb} +52 -47
- data/lib/cybersource_rest_client/models/agentic_retrieve_payment_credentials_response200_transaction_response_with_pending_events.rb +235 -0
- data/lib/cybersource_rest_client/models/agentic_update_purchase_intent_request.rb +315 -0
- data/lib/cybersource_rest_client/models/boardingv1registrations_organization_information_business_information.rb +36 -1
- data/lib/cybersource_rest_client/models/boardingv1registrations_organization_information_business_information_localized_names.rb +254 -0
- data/lib/cybersource_rest_client/models/create_plan_request.rb +1 -11
- data/lib/cybersource_rest_client/models/create_subscription_request.rb +1 -1
- data/lib/cybersource_rest_client/models/create_subscription_request_1.rb +1 -1
- data/lib/cybersource_rest_client/models/create_subscription_response.rb +15 -5
- data/lib/cybersource_rest_client/models/generate_unified_checkout_capture_context_request.rb +13 -2
- data/lib/cybersource_rest_client/models/get_all_subscriptions_response_client_reference_information.rb +196 -0
- data/lib/cybersource_rest_client/models/get_all_subscriptions_response_subscriptions.rb +11 -1
- data/lib/cybersource_rest_client/models/get_subscription_response.rb +11 -1
- data/lib/cybersource_rest_client/models/get_subscription_response_1_payment_instrument.rb +1 -1
- data/lib/cybersource_rest_client/models/get_subscription_response_1_payment_instrument_buyer_information.rb +1 -1
- data/lib/cybersource_rest_client/models/get_subscription_response_1_shipping_address.rb +1 -1
- data/lib/cybersource_rest_client/models/get_subscription_response_reactivation_information.rb +22 -22
- data/lib/cybersource_rest_client/models/inline_response_200.rb +9 -44
- data/lib/cybersource_rest_client/models/inline_response_200_1.rb +29 -31
- data/lib/cybersource_rest_client/models/inline_response_200_10.rb +33 -37
- data/lib/cybersource_rest_client/models/{inline_response_200_9_devices.rb → inline_response_200_10_devices.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_9_payment_processor_to_terminal_map.rb → inline_response_200_10_payment_processor_to_terminal_map.rb} +1 -1
- data/lib/cybersource_rest_client/models/inline_response_200_11.rb +47 -86
- data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded.rb → inline_response_200_11__embedded.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded__links.rb → inline_response_200_11__embedded__links.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded__links_reports.rb → inline_response_200_11__embedded__links_reports.rb} +1 -1
- data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded_batches.rb → inline_response_200_11__embedded_batches.rb} +3 -3
- data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded_totals.rb → inline_response_200_11__embedded_totals.rb} +1 -1
- data/lib/cybersource_rest_client/models/inline_response_200_11__links.rb +16 -17
- data/lib/cybersource_rest_client/models/inline_response_200_12.rb +47 -49
- data/lib/cybersource_rest_client/models/inline_response_200_12__links.rb +201 -0
- data/lib/cybersource_rest_client/models/{inline_response_200_11__links_report.rb → inline_response_200_12__links_report.rb} +1 -1
- data/lib/cybersource_rest_client/models/{inline_response_200_11_billing.rb → inline_response_200_12_billing.rb} +1 -1
- data/lib/cybersource_rest_client/models/inline_response_200_13.rb +102 -31
- data/lib/cybersource_rest_client/models/{inline_response_200_12_records.rb → inline_response_200_13_records.rb} +3 -3
- data/lib/cybersource_rest_client/models/{inline_response_200_12_response_record.rb → inline_response_200_13_response_record.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_12_response_record_additional_updates.rb → inline_response_200_13_response_record_additional_updates.rb} +1 -1
- data/lib/cybersource_rest_client/models/{inline_response_200_12_source_record.rb → inline_response_200_13_source_record.rb} +1 -1
- data/lib/cybersource_rest_client/models/inline_response_200_14.rb +18 -84
- data/lib/cybersource_rest_client/models/inline_response_200_15.rb +287 -0
- data/lib/cybersource_rest_client/models/{inline_response_200_14_client_reference_information.rb → inline_response_200_15_client_reference_information.rb} +1 -1
- data/lib/cybersource_rest_client/models/{inline_response_200_content.rb → inline_response_200_1_content.rb} +1 -1
- data/lib/cybersource_rest_client/models/inline_response_200_2.rb +32 -103
- data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded.rb → inline_response_200_2__embedded.rb} +3 -3
- data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_capture.rb → inline_response_200_2__embedded_capture.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_capture__links.rb → inline_response_200_2__embedded_capture__links.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_capture__links_self.rb → inline_response_200_2__embedded_capture__links_self.rb} +1 -1
- data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_reversal.rb → inline_response_200_2__embedded_reversal.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_reversal__links.rb → inline_response_200_2__embedded_reversal__links.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_reversal__links_self.rb → inline_response_200_2__embedded_reversal__links_self.rb} +1 -1
- data/lib/cybersource_rest_client/models/inline_response_200_3.rb +100 -54
- data/lib/cybersource_rest_client/models/inline_response_200_4.rb +65 -25
- data/lib/cybersource_rest_client/models/{inline_response_200_3_integration_information.rb → inline_response_200_4_integration_information.rb} +2 -2
- data/lib/cybersource_rest_client/models/{inline_response_200_3_integration_information_tenant_configurations.rb → inline_response_200_4_integration_information_tenant_configurations.rb} +1 -1
- data/lib/cybersource_rest_client/models/inline_response_200_5.rb +25 -126
- data/lib/cybersource_rest_client/models/inline_response_200_6.rb +1 -12
- data/lib/cybersource_rest_client/models/inline_response_200_7.rb +129 -51
- data/lib/cybersource_rest_client/models/inline_response_200_8.rb +55 -10
- data/lib/cybersource_rest_client/models/{inline_response_200_7_devices.rb → inline_response_200_8_devices.rb} +1 -1
- data/lib/cybersource_rest_client/models/inline_response_200_9.rb +10 -55
- data/lib/cybersource_rest_client/models/{inline_response_200_10__links.rb → inline_response_200_details.rb} +18 -17
- data/lib/cybersource_rest_client/models/inline_response_200_errors.rb +213 -0
- data/lib/cybersource_rest_client/models/inline_response_200_responses.rb +224 -0
- data/lib/cybersource_rest_client/models/inline_response_201_3_setups_payments.rb +15 -5
- data/lib/cybersource_rest_client/models/patch_customer_payment_instrument_request.rb +9 -9
- data/lib/cybersource_rest_client/models/patch_customer_request.rb +9 -9
- data/lib/cybersource_rest_client/models/patch_customer_shipping_address_request.rb +3 -3
- data/lib/cybersource_rest_client/models/patch_payment_instrument_request.rb +9 -9
- data/lib/cybersource_rest_client/models/payment_instrument_list_1__embedded_payment_instruments.rb +8 -8
- data/lib/cybersource_rest_client/models/payment_instrument_list__embedded.rb +1 -1
- data/lib/cybersource_rest_client/models/payments_products.rb +15 -5
- data/lib/cybersource_rest_client/models/post_customer_payment_instrument_request.rb +9 -9
- data/lib/cybersource_rest_client/models/post_customer_request.rb +9 -9
- data/lib/cybersource_rest_client/models/post_customer_shipping_address_request.rb +3 -3
- data/lib/cybersource_rest_client/models/post_issuer_life_cycle_simulation_request.rb +211 -0
- data/lib/cybersource_rest_client/models/post_payment_instrument_request.rb +9 -9
- data/lib/cybersource_rest_client/models/post_tokenize_request.rb +199 -0
- data/lib/cybersource_rest_client/models/ptsv2payments_aggregator_information.rb +22 -5
- data/lib/cybersource_rest_client/models/ptsv2payments_travel_information_transit_airline_ancillary_information.rb +22 -5
- data/lib/cybersource_rest_client/models/ptsv2payments_travel_information_transit_airline_ancillary_information_service.rb +39 -5
- data/lib/cybersource_rest_client/models/ptsv2paymentsidrefunds_travel_information.rb +246 -0
- data/lib/cybersource_rest_client/models/ptsv2paymentsidrefunds_travel_information_transit.rb +189 -0
- data/lib/cybersource_rest_client/models/ptsv2paymentsidrefunds_travel_information_transit_airline.rb +889 -0
- data/lib/cybersource_rest_client/models/ptsv2paymentsidrefunds_travel_information_transit_airline_ancillary_information.rb +259 -0
- data/lib/cybersource_rest_client/models/{rbsv1subscriptions_client_reference_information_partner.rb → ptsv2paymentsidrefunds_travel_information_transit_airline_ancillary_information_service.rb} +24 -24
- data/lib/cybersource_rest_client/models/refund_capture_request.rb +1 -1
- data/lib/cybersource_rest_client/models/refund_payment_request.rb +1 -1
- data/lib/cybersource_rest_client/models/shipping_address_list_for_customer__embedded.rb +1 -1
- data/lib/cybersource_rest_client/models/tms_issuerlifecycleeventsimulations_metadata_card_art_combined_asset.rb +190 -0
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_merchant_information.rb → tms_merchant_information.rb} +2 -2
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_merchant_information_merchant_descriptor.rb → tms_merchant_information_merchant_descriptor.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_buyer_information_issued_by.rb → tmsv2tokenize_default_payment_instrument_buyer_info_issued_by.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_buyer_information_personal_identification.rb → tmsv2tokenize_default_payment_instrument_buyer_info_personal_identification.rb} +2 -2
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_card_tokenized_information.rb → tmsv2tokenize_default_payment_instrument_card_tokenized_info.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_instrument_identifier.rb → tmsv2tokenize_default_payment_instrument_instrument_identifier.rb} +1 -1
- data/lib/cybersource_rest_client/models/tmsv2tokenize_processing_information.rb +205 -0
- data/lib/cybersource_rest_client/models/tmsv2tokenize_token_information.rb +247 -0
- data/lib/cybersource_rest_client/models/tmsv2tokenize_token_information_customer.rb +289 -0
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded.rb → tmsv2tokenize_token_information_customer__embedded.rb} +3 -3
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument.rb} +10 -10
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument__embedded.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument__embedded.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument__links.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument__links.rb} +3 -3
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument__links_self.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument__links_self.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_bank_account.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument_bank_account.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_bill_to.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument_bill_to.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_buyer_information.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument_buyer_information.rb} +2 -2
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_card.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument_card.rb} +2 -2
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_metadata.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument_metadata.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_shipping_address.rb → tmsv2tokenize_token_information_customer__embedded_default_shipping_address.rb} +4 -4
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_shipping_address__links.rb → tmsv2tokenize_token_information_customer__embedded_default_shipping_address__links.rb} +3 -3
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_shipping_address__links_customer.rb → tmsv2tokenize_token_information_customer__embedded_default_shipping_address__links_customer.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_shipping_address__links_self.rb → tmsv2tokenize_token_information_customer__embedded_default_shipping_address__links_self.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_shipping_address_metadata.rb → tmsv2tokenize_token_information_customer__embedded_default_shipping_address_metadata.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_shipping_address_ship_to.rb → tmsv2tokenize_token_information_customer__embedded_default_shipping_address_ship_to.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__links.rb → tmsv2tokenize_token_information_customer__links.rb} +4 -4
- data/lib/cybersource_rest_client/models/{tmsv2customers__links_payment_instruments.rb → tmsv2tokenize_token_information_customer__links_payment_instruments.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__links_self.rb → tmsv2tokenize_token_information_customer__links_self.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers__links_shipping_address.rb → tmsv2tokenize_token_information_customer__links_shipping_address.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers_buyer_information.rb → tmsv2tokenize_token_information_customer_buyer_information.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers_client_reference_information.rb → tmsv2tokenize_token_information_customer_client_reference_information.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers_default_payment_instrument.rb → tmsv2tokenize_token_information_customer_default_payment_instrument.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers_default_shipping_address.rb → tmsv2tokenize_token_information_customer_default_shipping_address.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers_merchant_defined_information.rb → tmsv2tokenize_token_information_customer_merchant_defined_information.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers_metadata.rb → tmsv2tokenize_token_information_customer_metadata.rb} +1 -1
- data/lib/cybersource_rest_client/models/{tmsv2customers_object_information.rb → tmsv2tokenize_token_information_customer_object_information.rb} +1 -1
- data/lib/cybersource_rest_client/models/tmsv2tokenizedcardstokenized_card_idissuerlifecycleeventsimulations_card.rb +230 -0
- data/lib/cybersource_rest_client/models/tmsv2tokenizedcardstokenized_card_idissuerlifecycleeventsimulations_metadata.rb +189 -0
- data/lib/cybersource_rest_client/models/tmsv2tokenizedcardstokenized_card_idissuerlifecycleeventsimulations_metadata_card_art.rb +189 -0
- data/lib/cybersource_rest_client/models/update_subscription.rb +1 -1
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data.rb +28 -6
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_buyer_information.rb +41 -5
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_buyer_information_personal_identification.rb +1 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_client_reference_information_partner.rb +3 -3
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_consumer_authentication_information.rb +24 -5
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_device_information.rb +196 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_merchant_defined_information.rb +3 -2
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_merchant_information_merchant_descriptor.rb +124 -5
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information.rb +15 -5
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_amount_details.rb +15 -5
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_amount_details_tax_details.rb +213 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_invoice_details.rb +213 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_line_items.rb +30 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_line_items_passenger.rb +8 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_line_items_tax_details.rb +7 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_payment_information.rb +189 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_payment_information_card.rb +196 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_processing_information.rb +1 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_processing_information_authorization_options.rb +74 -5
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_processing_information_authorization_options_initiator.rb +1 -0
- data/lib/cybersource_rest_client/models/upv1capturecontexts_data_recipient_information.rb +39 -5
- data/lib/cybersource_rest_client/models/upv1capturecontexts_order_information.rb +1 -0
- data/lib/cybersource_rest_client/utilities/capture_context/capture_context_parsing_utility.rb +113 -0
- data/lib/cybersource_rest_client/utilities/capture_context/public_key_fetcher.rb +131 -0
- data/lib/cybersource_rest_client/utilities/jwe_utility.rb +1 -1
- data/lib/cybersource_rest_client.rb +144 -62
- metadata +151 -65
- /data/lib/AuthenticationSDK/util/{JWEUtility.rb → AuthJWEUtility.rb} +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Cache value object to store MLE KID data
|
|
2
|
+
class CachedMLEKId
|
|
3
|
+
attr_accessor :kid, :last_modified_timestamp
|
|
4
|
+
|
|
5
|
+
def initialize(kid = nil, last_modified_timestamp = nil)
|
|
6
|
+
@kid = kid
|
|
7
|
+
@last_modified_timestamp = last_modified_timestamp
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_s
|
|
11
|
+
"CachedMLEKId(kid: #{@kid ? 'present' : 'nil'}, last_modified_timestamp: #{@last_modified_timestamp})"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def empty?
|
|
15
|
+
@kid.nil? && @last_modified_timestamp.nil?
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -7,34 +7,6 @@ public
|
|
|
7
7
|
class CertificateUtility
|
|
8
8
|
@@logger
|
|
9
9
|
|
|
10
|
-
def self.getCertificateCollectionAndPrivateKeyFromP12(certificateFilePath, merchantConfig)
|
|
11
|
-
if !CertificateUtility.class_variable_defined?(:@@logger) || @@logger.nil?
|
|
12
|
-
@@logger = Log.new merchantConfig.log_config, "CertificateUtility"
|
|
13
|
-
end
|
|
14
|
-
logger = @@logger.logger
|
|
15
|
-
|
|
16
|
-
p12File = File.binread(certificateFilePath)
|
|
17
|
-
p12Object = OpenSSL::PKCS12.new(p12File, merchantConfig.keyPass)
|
|
18
|
-
|
|
19
|
-
privateKey = OpenSSL::PKey::RSA.new(p12Object.key)
|
|
20
|
-
|
|
21
|
-
primaryX5Certificate = p12Object.certificate
|
|
22
|
-
additionalX5Certificates = p12Object.ca_certs
|
|
23
|
-
|
|
24
|
-
certificateList = [primaryX5Certificate]
|
|
25
|
-
certificateList.concat(additionalX5Certificates) if additionalX5Certificates
|
|
26
|
-
|
|
27
|
-
return [privateKey, certificateList]
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.getCertificateBasedOnKeyAlias(certificateList, keyAlias)
|
|
31
|
-
return nil if certificateList.nil?
|
|
32
|
-
|
|
33
|
-
certificateList.find do |cert|
|
|
34
|
-
cert.subject.to_a.any? { |_, value, _| value.include?(keyAlias) }
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
10
|
def self.getCertificatesFromPemFile(certificateFilePath)
|
|
39
11
|
pem_data = File.read(certificateFilePath)
|
|
40
12
|
certificateList = []
|
|
@@ -121,4 +93,112 @@ public
|
|
|
121
93
|
raise IOError, "#{pathType} is not readable: #{path}"
|
|
122
94
|
end
|
|
123
95
|
end
|
|
124
|
-
|
|
96
|
+
|
|
97
|
+
def self.read_private_key_from_p12(p12_file_path, password)
|
|
98
|
+
begin
|
|
99
|
+
# `password` should be a String in Ruby
|
|
100
|
+
raise ArgumentError, "password must be a String" unless password.is_a?(String)
|
|
101
|
+
|
|
102
|
+
data = File.binread(p12_file_path)
|
|
103
|
+
pkcs12 = OpenSSL::PKCS12.new(data, password)
|
|
104
|
+
|
|
105
|
+
key = pkcs12.key
|
|
106
|
+
raise "No private key found in the P12 file" if key.nil?
|
|
107
|
+
|
|
108
|
+
jwk_private_key = self.convert_key_to_JWK(key)
|
|
109
|
+
return jwk_private_key
|
|
110
|
+
rescue OpenSSL::PKCS12::PKCS12Error => e
|
|
111
|
+
raise "Could not recover key from P12: #{e.message}"
|
|
112
|
+
rescue Errno::ENOENT => e
|
|
113
|
+
raise "P12 file not found: #{p12_file_path}"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def self.load_private_key_from_pem_file(key_file_path, password = nil)
|
|
118
|
+
begin
|
|
119
|
+
pem_data = File.binread(key_file_path)
|
|
120
|
+
|
|
121
|
+
# OpenSSL::PKey.read supports:
|
|
122
|
+
# - "BEGIN RSA/EC/PRIVATE KEY" (PKCS#1), encrypted or not (Proc-Type/DEK-Info)
|
|
123
|
+
# - "BEGIN PRIVATE KEY" (PKCS#8 unencrypted)
|
|
124
|
+
# - "BEGIN ENCRYPTED PRIVATE KEY" (PKCS#8 encrypted)
|
|
125
|
+
rsa_key = OpenSSL::PKey.read(pem_data, password)
|
|
126
|
+
jwk_private_key = self.convert_key_to_JWK(rsa_key)
|
|
127
|
+
return jwk_private_key
|
|
128
|
+
rescue OpenSSL::PKey::PKeyError => e
|
|
129
|
+
# Missing password for an encrypted PEM
|
|
130
|
+
if pem_data =~ /(BEGIN ENCRYPTED PRIVATE KEY|Proc-Type:\s*4,ENCRYPTED)/ && (password.nil? || password.to_s.empty?)
|
|
131
|
+
raise ArgumentError, "Private key is password protected, but no password was provided."
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Wrong password (common OpenSSL messages)
|
|
135
|
+
if password && e.message =~ /(bad decrypt|bad password|mac verify failure)/i
|
|
136
|
+
logger&.error("Failed to decrypt PKCS#8 private key - incorrect password provided")
|
|
137
|
+
raise ArgumentError, "Password is incorrect for the encrypted private key. Error: #{e.message}"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Unsupported/invalid PEM contents
|
|
141
|
+
raise ArgumentError, "Unsupported PEM object or invalid key: #{e.message}"
|
|
142
|
+
rescue Errno::ENOENT
|
|
143
|
+
raise ArgumentError, "PEM file not found: #{key_file_path}"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def self.convert_key_to_JWK(keyValue, password=nil)
|
|
148
|
+
if !keyValue.nil?
|
|
149
|
+
case keyValue
|
|
150
|
+
when String
|
|
151
|
+
begin
|
|
152
|
+
if keyValue.encoding == Encoding::UTF_8
|
|
153
|
+
# This is for PEM formatted string
|
|
154
|
+
encrypted = keyValue.include?('BEGIN ENCRYPTED PRIVATE KEY')
|
|
155
|
+
pkey = nil
|
|
156
|
+
|
|
157
|
+
key = begin
|
|
158
|
+
if encrypted
|
|
159
|
+
if password.nil? || password.empty?
|
|
160
|
+
raise ArgumentError, "Encrypted PEM detected, but no password was provided."
|
|
161
|
+
end
|
|
162
|
+
pkey = OpenSSL::PKey.read(keyValue, password)
|
|
163
|
+
else
|
|
164
|
+
# Try without password first
|
|
165
|
+
pkey = OpenSSL::PKey.read(keyValue)
|
|
166
|
+
end
|
|
167
|
+
rescue OpenSSL::PKey::PKeyError
|
|
168
|
+
# If initial attempt failed and a password was provided, retry with password
|
|
169
|
+
if !password.nil? && !password.empty?
|
|
170
|
+
begin
|
|
171
|
+
pkey = OpenSSL::PKey.read(keyValue, password)
|
|
172
|
+
rescue OpenSSL::PKey::PKeyError => e
|
|
173
|
+
raise "Failed to load PEM private key. Incorrect password or corrupted/unsupported format. OpenSSL: #{e.message}"
|
|
174
|
+
end
|
|
175
|
+
else
|
|
176
|
+
raise "Failed to load PEM private key. Invalid key format or password required."
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
keyValue = JOSE::JWK.from_key(pkey)
|
|
180
|
+
else
|
|
181
|
+
# This is for P12 formatted string
|
|
182
|
+
begin
|
|
183
|
+
if !password.nil? && !password.empty?
|
|
184
|
+
pkey = OpenSSL::PKCS12.new(keyValue, password)
|
|
185
|
+
else
|
|
186
|
+
pkey = OpenSSL::PKCS12.new(keyValue)
|
|
187
|
+
end
|
|
188
|
+
rescue OpenSSL::PKCS12::PKCS12Error => e
|
|
189
|
+
raise "Could not recover key from P12 data: #{e.message}"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
key = pkey.key
|
|
193
|
+
raise "No private key found in the P12 data" if key.nil?
|
|
194
|
+
keyValue = JOSE::JWK.from_key(key)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
when OpenSSL::PKey::RSA
|
|
198
|
+
keyValue = JOSE::JWK.from_pem(keyValue.to_pem)
|
|
199
|
+
else
|
|
200
|
+
keyValue = JOSE::JWK.from_key(keyValue)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
@@ -175,4 +175,10 @@
|
|
|
175
175
|
MLE_CACHE_IDENTIFIER_FOR_P12_CERT = "mleCertFromP12"
|
|
176
176
|
|
|
177
177
|
DEFAULT_KEY_FILE_PATH = File.join(Dir.pwd, "resources")
|
|
178
|
+
|
|
179
|
+
MLE_CACHE_KEY_IDENTIFIER_FOR_RESPONSE_PRIVATE_KEY = "mleResponsePrivateKeyFromFile"
|
|
180
|
+
|
|
181
|
+
PUBLIC_KEY_CACHE_IDENTIFIER = "FlexV2PublicKeys"
|
|
182
|
+
|
|
183
|
+
RESPONSE_MLE_P12_PFX_CACHE_IDENTIFIER = "_responseMleP12Pfx"
|
|
178
184
|
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CyberSource
|
|
4
|
+
module Authentication
|
|
5
|
+
module Util
|
|
6
|
+
module JWT
|
|
7
|
+
# Base JWT Exception Class
|
|
8
|
+
#
|
|
9
|
+
# Provides enhanced exception handling for JWT-related operations with
|
|
10
|
+
# error chaining and detailed stack trace information.
|
|
11
|
+
class JWTException < StandardError
|
|
12
|
+
# @param message [String] Error message describing the exception
|
|
13
|
+
# @param cause [Exception, nil] Optional underlying cause of the error
|
|
14
|
+
def initialize(message = '', cause = nil)
|
|
15
|
+
super(message)
|
|
16
|
+
set_backtrace(cause.backtrace) if cause&.backtrace
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Boolean] True if a cause exception exists
|
|
20
|
+
def has_cause?
|
|
21
|
+
!cause.nil?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [String] Exception string with cause information
|
|
25
|
+
def to_s
|
|
26
|
+
return super unless has_cause?
|
|
27
|
+
|
|
28
|
+
"#{super}\nCaused by: #{cause}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Array<Exception>] Array of exceptions in the chain
|
|
32
|
+
def exception_chain
|
|
33
|
+
chain = [self]
|
|
34
|
+
current = cause
|
|
35
|
+
|
|
36
|
+
while current
|
|
37
|
+
chain << current
|
|
38
|
+
current = current.cause
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
chain
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @return [Exception] The root cause of the exception chain
|
|
45
|
+
def root_cause
|
|
46
|
+
exception_chain.last
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [Array<String>] Error messages from all exceptions in the chain
|
|
50
|
+
def cause_chain_messages
|
|
51
|
+
exception_chain.map(&:message)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @param highlight [Boolean] Whether to highlight the message
|
|
55
|
+
# @param order [Symbol] :top or :bottom, determines message order
|
|
56
|
+
# @return [String] Detailed error message with all causes
|
|
57
|
+
def full_message(highlight: false, order: :top, **)
|
|
58
|
+
messages = exception_chain.each_with_index.map do |exception, index|
|
|
59
|
+
prefix = index.zero? ? '' : 'Caused by: '
|
|
60
|
+
"#{prefix}#{exception.class}: #{exception.message}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
order == :bottom ? messages.reverse.join("\n") : messages.join("\n")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Thrown when a JSON Web Key (JWK) is invalid or malformed
|
|
68
|
+
class InvalidJwkException < JWTException
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Thrown when a JWT token is invalid, malformed, or cannot be processed
|
|
72
|
+
class InvalidJwtException < JWTException
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Thrown when JWT signature validation fails
|
|
76
|
+
class JwtSignatureValidationException < JWTException
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'jwt'
|
|
4
|
+
require 'json'
|
|
5
|
+
require_relative 'JWTExceptions'
|
|
6
|
+
|
|
7
|
+
module CyberSource
|
|
8
|
+
module Authentication
|
|
9
|
+
module Util
|
|
10
|
+
module JWT
|
|
11
|
+
# JWT Utility Class
|
|
12
|
+
#
|
|
13
|
+
# Provides JWT parsing, verification, and JWK handling functionality.
|
|
14
|
+
#
|
|
15
|
+
# @category Class
|
|
16
|
+
# @package CyberSource::Authentication::Util::JWT
|
|
17
|
+
# @author CyberSource
|
|
18
|
+
class JWTUtility
|
|
19
|
+
# Supported JWT algorithms
|
|
20
|
+
SUPPORTED_ALGORITHMS = %w[RS256 RS384 RS512].freeze
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
# Parses a JWT token and extracts its header, payload, and signature components
|
|
24
|
+
#
|
|
25
|
+
# @param jwt_token [String] The JWT token to parse
|
|
26
|
+
#
|
|
27
|
+
# @return [Hash] Hash containing header, payload, signature, and raw parts
|
|
28
|
+
# @raise [InvalidJwtException] If the JWT token is invalid or malformed
|
|
29
|
+
def parse(jwt_token)
|
|
30
|
+
raise InvalidJwtException.new('JWT token is null or undefined') if jwt_token.to_s.empty?
|
|
31
|
+
|
|
32
|
+
token_parts = jwt_token.split('.')
|
|
33
|
+
if token_parts.length != 3
|
|
34
|
+
raise InvalidJwtException.new('Invalid JWT token format: expected 3 parts separated by dots')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if token_parts.any?(&:empty?)
|
|
38
|
+
raise InvalidJwtException.new('Malformed JWT : JWT provided does not conform to the proper structure for JWT')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
header = JSON.parse(::JWT::Base64.url_decode(token_parts[0]))
|
|
43
|
+
payload = JSON.parse(::JWT::Base64.url_decode(token_parts[1]))
|
|
44
|
+
signature = token_parts[2]
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
header: header,
|
|
48
|
+
payload: payload,
|
|
49
|
+
signature: signature,
|
|
50
|
+
raw_header: token_parts[0],
|
|
51
|
+
raw_payload: token_parts[1]
|
|
52
|
+
}
|
|
53
|
+
rescue StandardError => e
|
|
54
|
+
raise InvalidJwtException.new("Malformed JWT cannot be parsed: #{e.message}", e)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Verifies a JWT token using an RSA public key
|
|
59
|
+
#
|
|
60
|
+
# @param jwt_token [String] The JWT token to verify
|
|
61
|
+
# @param public_key [String, Hash] The RSA public key (JWK Hash or JSON string)
|
|
62
|
+
#
|
|
63
|
+
# @return [void]
|
|
64
|
+
# @raise [InvalidJwtException] If JWT parsing fails
|
|
65
|
+
# @raise [JwtSignatureValidationException] If signature verification fails
|
|
66
|
+
# @raise [InvalidJwkException] If the public key is invalid
|
|
67
|
+
# @raise [JSON::ParserError] If JSON parsing fails
|
|
68
|
+
def verify_jwt(jwt_token, public_key)
|
|
69
|
+
raise JwtSignatureValidationException.new('No public key found') if public_key.to_s.empty?
|
|
70
|
+
raise JwtSignatureValidationException.new('JWT token is null or undefined') if jwt_token.to_s.empty?
|
|
71
|
+
|
|
72
|
+
parsed_token = parse(jwt_token)
|
|
73
|
+
header = parsed_token[:header]
|
|
74
|
+
|
|
75
|
+
if header['alg'].nil? || header['alg'].to_s.empty?
|
|
76
|
+
raise JwtSignatureValidationException.new('JWT header missing algorithm (alg) field')
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
algorithm = header['alg']
|
|
80
|
+
unless SUPPORTED_ALGORITHMS.include?(algorithm)
|
|
81
|
+
supported_algs = SUPPORTED_ALGORITHMS.join(', ')
|
|
82
|
+
raise JwtSignatureValidationException.new(
|
|
83
|
+
format('Unsupported JWT algorithm: %s. Supported algorithms: %s', algorithm, supported_algs)
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
jwk_key = validate_and_parse_jwk(public_key)
|
|
88
|
+
jwk_key['alg'] ||= algorithm
|
|
89
|
+
|
|
90
|
+
begin
|
|
91
|
+
rsa_key = jwk_to_rsa_key(jwk_key)
|
|
92
|
+
::JWT.decode(jwt_token, rsa_key, true, { algorithm: algorithm })
|
|
93
|
+
|
|
94
|
+
rescue ::JWT::VerificationError => e
|
|
95
|
+
raise JwtSignatureValidationException.new('JWT signature verification failed', e)
|
|
96
|
+
rescue ::JWT::ExpiredSignature => e
|
|
97
|
+
raise JwtSignatureValidationException.new('JWT has expired (exp claim)', e)
|
|
98
|
+
rescue ::JWT::ImmatureSignature => e
|
|
99
|
+
raise JwtSignatureValidationException.new('JWT not yet valid (nbf claim)', e)
|
|
100
|
+
rescue ::JWT::DecodeError => e
|
|
101
|
+
raise JwtSignatureValidationException.new("JWT verification failed: #{e.message}", e)
|
|
102
|
+
rescue JwtSignatureValidationException, InvalidJwtException
|
|
103
|
+
raise
|
|
104
|
+
rescue StandardError => e
|
|
105
|
+
raise JwtSignatureValidationException.new("JWT verification failed: #{e.message}", e)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# Validates and parses a JWK (JSON Web Key)
|
|
112
|
+
#
|
|
113
|
+
# @param public_key [String, Hash] The public key to validate (JWK Hash or JSON string)
|
|
114
|
+
#
|
|
115
|
+
# @return [Hash] The parsed and validated JWK
|
|
116
|
+
# @raise [InvalidJwkException] If the JWK is invalid or not an RSA key
|
|
117
|
+
def validate_and_parse_jwk(public_key)
|
|
118
|
+
return public_key if public_key.is_a?(Hash) && public_key.key?('kty')
|
|
119
|
+
|
|
120
|
+
jwk_hash = if public_key.is_a?(String)
|
|
121
|
+
begin
|
|
122
|
+
JSON.parse(public_key)
|
|
123
|
+
rescue JSON::ParserError => e
|
|
124
|
+
raise InvalidJwkException.new('Invalid public key JSON format', e)
|
|
125
|
+
end
|
|
126
|
+
else
|
|
127
|
+
raise InvalidJwkException.new('Invalid public key format. Expected JWK object or JSON string.')
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
raise InvalidJwkException.new('Public key must be an RSA key (kty: RSA)') if jwk_hash['kty'] != 'RSA'
|
|
131
|
+
raise InvalidJwkException.new('Invalid RSA JWK: missing required parameters (n, e)') unless jwk_hash['n'] && jwk_hash['e']
|
|
132
|
+
|
|
133
|
+
jwk_hash
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Converts a JWK to an RSA key object
|
|
137
|
+
#
|
|
138
|
+
# @param jwk [Hash] The JWK to convert
|
|
139
|
+
#
|
|
140
|
+
# @return [OpenSSL::PKey::RSA] The RSA key object
|
|
141
|
+
# @raise [InvalidJwkException] If conversion fails
|
|
142
|
+
def jwk_to_rsa_key(jwk)
|
|
143
|
+
# Use jwt gem's JWK support for OpenSSL 3.0+ compatibility
|
|
144
|
+
# This handles both OpenSSL 1.x and 3.0+ internally
|
|
145
|
+
::JWT::JWK.import(jwk).keypair
|
|
146
|
+
rescue StandardError => e
|
|
147
|
+
raise InvalidJwkException.new("Failed to convert JWK to RSA key: #{e.message}", e)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
require_relative '../logging/log_factory.rb'
|
|
2
2
|
require 'jose'
|
|
3
|
+
require 'json'
|
|
3
4
|
require_relative './Cache'
|
|
5
|
+
require_relative './Constants'
|
|
6
|
+
require_relative './ExceptionHandler'
|
|
7
|
+
require_relative './AuthJWEUtility'
|
|
4
8
|
|
|
5
9
|
public
|
|
6
10
|
class MLEUtility
|
|
@@ -16,10 +20,10 @@ public
|
|
|
16
20
|
is_mle_for_api = !merchant_config.disableRequestMLEForMandatoryApisGlobally
|
|
17
21
|
end
|
|
18
22
|
|
|
19
|
-
if merchant_config.
|
|
23
|
+
if !merchant_config.internalMapToControlRequestMLEonAPI.nil? && !merchant_config.internalMapToControlRequestMLEonAPI.empty? && operation_ids
|
|
20
24
|
operation_ids.each do |operation_id|
|
|
21
|
-
if merchant_config.
|
|
22
|
-
is_mle_for_api = merchant_config.
|
|
25
|
+
if merchant_config.internalMapToControlRequestMLEonAPI.key?(operation_id)
|
|
26
|
+
is_mle_for_api = merchant_config.internalMapToControlRequestMLEonAPI[operation_id]
|
|
23
27
|
break
|
|
24
28
|
end
|
|
25
29
|
end
|
|
@@ -45,11 +49,7 @@ public
|
|
|
45
49
|
end
|
|
46
50
|
|
|
47
51
|
begin
|
|
48
|
-
serial_number = extract_serial_number_from_certificate(mleCertificate)
|
|
49
|
-
if serial_number.nil?
|
|
50
|
-
@log_obj.logger.error('Serial number not found in certificate for MLE')
|
|
51
|
-
raise StandardError.new('Serial number not found in MLE certificate')
|
|
52
|
-
end
|
|
52
|
+
serial_number = self.extract_serial_number_from_certificate(mleCertificate)
|
|
53
53
|
|
|
54
54
|
jwk = JOSE::JWK.from_key(mleCertificate.public_key)
|
|
55
55
|
if jwk.nil?
|
|
@@ -66,7 +66,7 @@ public
|
|
|
66
66
|
jwe = JOSE::JWE.block_encrypt(jwk, requestBody, headers)
|
|
67
67
|
|
|
68
68
|
compact_jwe = jwe.compact
|
|
69
|
-
mle_request_body = create_request_payload(compact_jwe)
|
|
69
|
+
mle_request_body = self.create_request_payload(compact_jwe)
|
|
70
70
|
@log_obj.logger.debug('LOG_REQUEST_AFTER_MLE: ' + mle_request_body)
|
|
71
71
|
return mle_request_body
|
|
72
72
|
rescue StandardError => e
|
|
@@ -76,14 +76,170 @@ public
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def self.extract_serial_number_from_certificate(certificate)
|
|
79
|
-
|
|
79
|
+
raise StandardError.new('Certificate cannot be nil') if certificate.nil?
|
|
80
|
+
raise StandardError.new('Certificate subject and issuer cannot both be empty') if certificate.subject.to_s.empty? && certificate.issuer.to_s.empty?
|
|
80
81
|
certificate.subject.to_a.each do |attribute|
|
|
81
82
|
return attribute[1] if attribute[0].include?('serialNumber')
|
|
82
83
|
end
|
|
83
|
-
|
|
84
|
+
raise StandardError.new('Serial number not found in certificate subject')
|
|
84
85
|
end
|
|
85
86
|
|
|
86
87
|
def self.create_request_payload(compact_jwe)
|
|
87
88
|
"{ \"encryptedRequest\": \"#{compact_jwe}\" }"
|
|
88
89
|
end
|
|
90
|
+
|
|
91
|
+
def self.check_is_response_mle_for_api(merchant_config, operation_ids)
|
|
92
|
+
isResponseMLEForApi = false
|
|
93
|
+
|
|
94
|
+
if merchant_config.enableResponseMleGlobally
|
|
95
|
+
isResponseMLEForApi = true
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# operation_ids is an array of the multiple public function for apiCallFunction such as apiCall, apiCallAsync
|
|
99
|
+
# Control the Response MLE only from map
|
|
100
|
+
# Special Note: If API expect MLE Response mandatory and map is saying to receive non MLE response then API might throw an error from CyberSource
|
|
101
|
+
if merchant_config.internalMapToControlResponseMLEonAPI
|
|
102
|
+
operation_ids.each do |operation_id|
|
|
103
|
+
if merchant_config.internalMapToControlResponseMLEonAPI.key?(operation_id)
|
|
104
|
+
isResponseMLEForApi = merchant_config.internalMapToControlResponseMLEonAPI[operation_id]
|
|
105
|
+
break
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
isResponseMLEForApi
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.check_is_mle_encrypted_response(responseBody)
|
|
114
|
+
return false if responseBody.nil? || responseBody.strip.empty?
|
|
115
|
+
|
|
116
|
+
begin
|
|
117
|
+
jsonObject = JSON.parse(responseBody)
|
|
118
|
+
return false unless jsonObject.is_a?(Hash) && jsonObject.size == 1
|
|
119
|
+
|
|
120
|
+
jsonObject.key?('encryptedResponse') && jsonObject['encryptedResponse'].is_a?(String)
|
|
121
|
+
rescue JSON::ParserError, TypeError
|
|
122
|
+
false
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.decrypt_mle_response_payload(merchantConfig, responseBody)
|
|
127
|
+
@log_obj ||= Log.new(merchantConfig.log_config, 'MLEUtility')
|
|
128
|
+
|
|
129
|
+
if !self.check_is_mle_encrypted_response(responseBody)
|
|
130
|
+
raise StandardError.new('Response body is not MLE encrypted.')
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
mlePrivateKey = self.get_mle_response_private_key(merchantConfig)
|
|
134
|
+
jweResponseToken = self.get_response_mle_token(responseBody)
|
|
135
|
+
|
|
136
|
+
# When mle token is empty or null then fall back to non mle encrypted response
|
|
137
|
+
if jweResponseToken.nil? || jweResponseToken.strip.empty?
|
|
138
|
+
return responseBody
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
begin
|
|
142
|
+
@log_obj.logger.info("LOG_NETWORK_RESPONSE_BEFORE_MLE_DECRYPTION: #{responseBody}")
|
|
143
|
+
|
|
144
|
+
decryptedResponse = AuthJWEUtility.decrypt_jwe_using_private_key(mlePrivateKey, jweResponseToken)
|
|
145
|
+
|
|
146
|
+
@log_obj.logger.info("LOG_NETWORK_RESPONSE_AFTER_MLE_DECRYPTION: #{decryptedResponse}")
|
|
147
|
+
|
|
148
|
+
return decryptedResponse
|
|
149
|
+
rescue => e
|
|
150
|
+
raise StandardError.new(Constants::ERROR_PREFIX + "An error occurred during MLE decryption: #{e.message}")
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.get_response_mle_token(responseBody)
|
|
155
|
+
@log_obj ||= Log.new(merchantConfig.log_config, 'MLEUtility')
|
|
156
|
+
|
|
157
|
+
begin
|
|
158
|
+
jsonObject = JSON.parse(responseBody)
|
|
159
|
+
token = jsonObject['encryptedResponse']
|
|
160
|
+
token.is_a?(String) ? token : nil
|
|
161
|
+
rescue JSON::ParserError, TypeError => e
|
|
162
|
+
err = StandardError.new(Constants::ERROR_PREFIX + "Failed to extract Response MLE token: #{e.message}")
|
|
163
|
+
@log_obj.logger.error(ExceptionHandler.new.new_api_exception err)
|
|
164
|
+
raise err
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
private_class_method :get_response_mle_token
|
|
169
|
+
|
|
170
|
+
def self.get_mle_response_private_key(merchantConfig)
|
|
171
|
+
@log_obj ||= Log.new(merchantConfig.log_config, 'MLEUtility')
|
|
172
|
+
|
|
173
|
+
# First priority - Return private key provided in merchant config, if any
|
|
174
|
+
if !merchantConfig.responseMlePrivateKey.nil? && !merchantConfig.responseMlePrivateKey.to_s.strip.empty?
|
|
175
|
+
return merchantConfig.responseMlePrivateKey
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Second priority - Return private key loaded from merchantConfig.responseMlePrivateKeyFilePath
|
|
179
|
+
responseMlePrivateKey = Cache.new.getMLEResponsePrivateKeyFromFilePath(merchantConfig)
|
|
180
|
+
return responseMlePrivateKey
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
private_class_method :get_mle_response_private_key
|
|
184
|
+
|
|
185
|
+
def self.validate_and_auto_extract_response_mle_kid(merchant_config)
|
|
186
|
+
@log_obj ||= Log.new(merchant_config.log_config, 'MLEUtility')
|
|
187
|
+
|
|
188
|
+
if !merchant_config.responseMlePrivateKey.nil? && !merchant_config.responseMlePrivateKey.to_s.strip.empty?
|
|
189
|
+
@log_obj.logger.debug('responseMlePrivateKey is provided directly, using configured responseMleKID')
|
|
190
|
+
return merchant_config.responseMleKID
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
@log_obj.logger.debug('Validating responseMleKID for JWT token generation')
|
|
194
|
+
cybs_kid = nil
|
|
195
|
+
p12_file = false
|
|
196
|
+
|
|
197
|
+
# File path validity
|
|
198
|
+
begin
|
|
199
|
+
CertificateUtility.validatePathAndFile(merchant_config.responseMlePrivateKeyFilePath, 'responseMlePrivateKeyFilePath', merchant_config.log_config)
|
|
200
|
+
extension = File.extname(merchant_config.responseMlePrivateKeyFilePath).delete_prefix('.').downcase
|
|
201
|
+
if extension == 'p12' || extension == 'pfx'
|
|
202
|
+
p12_file = true
|
|
203
|
+
end
|
|
204
|
+
rescue IOError => e
|
|
205
|
+
@log_obj.logger.debug('No valid private key file path provided, skipping auto-extraction')
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
if p12_file
|
|
209
|
+
@log_obj.logger.debug('P12/PFX file detected, checking if it is a CyberSource certificate')
|
|
210
|
+
cached_data = Cache.new.get_mle_kid_data_from_cache(merchant_config)
|
|
211
|
+
if !cached_data.nil?
|
|
212
|
+
if !cached_data.kid.nil?
|
|
213
|
+
# KID present means it's a CyberSource P12, use it
|
|
214
|
+
cybs_kid = cached_data.kid
|
|
215
|
+
else
|
|
216
|
+
# KID is null means either non-CyberSource P12 or extraction failed
|
|
217
|
+
@log_obj.logger.debug('Private key file is not a CyberSource generated P12/PFX file, skipping auto-extraction')
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
else
|
|
221
|
+
@log_obj.logger.debug('Private key file is not a P12/PFX file, skipping auto-extraction')
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
if !cybs_kid.nil?
|
|
225
|
+
@log_obj.logger.debug('Successfully auto-extracted responseMleKID from CyberSource P12 certificate')
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
configured_kid = merchant_config.responseMleKID
|
|
229
|
+
if cybs_kid.nil? && configured_kid.nil?
|
|
230
|
+
raise StandardError.new('responseMleKID is required when response MLE is enabled. ' +
|
|
231
|
+
'Could not auto-extract from certificate and no manual configuration provided. ' +
|
|
232
|
+
'Please provide responseMleKID explicitly in your configuration.'
|
|
233
|
+
)
|
|
234
|
+
elsif cybs_kid.nil?
|
|
235
|
+
@log_obj.logger.debug('Using manually configured responseMleKID')
|
|
236
|
+
return configured_kid
|
|
237
|
+
elsif configured_kid.nil?
|
|
238
|
+
@log_obj.logger.debug('Using auto-extracted responseMleKID from CyberSource certificate')
|
|
239
|
+
return cybs_kid
|
|
240
|
+
elsif cybs_kid != configured_kid
|
|
241
|
+
@log_obj.logger.warn('Auto-extracted responseMleKID does not match manually configured responseMleKID. Using configured value as preference')
|
|
242
|
+
end
|
|
243
|
+
return configured_kid
|
|
244
|
+
end
|
|
89
245
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'openssl'
|
|
2
2
|
require 'base64'
|
|
3
|
+
require_relative '../util/Constants.rb'
|
|
3
4
|
|
|
4
5
|
public
|
|
5
6
|
|
|
@@ -32,5 +33,40 @@ public
|
|
|
32
33
|
end
|
|
33
34
|
return tempResponseCodeMessage
|
|
34
35
|
end
|
|
35
|
-
end
|
|
36
36
|
|
|
37
|
+
def self.getCertificateBasedOnKeyAlias(certificateList, keyAlias)
|
|
38
|
+
return nil if certificateList.nil?
|
|
39
|
+
|
|
40
|
+
certificateList.find do |cert|
|
|
41
|
+
cert.subject.to_a.any? { |_, value, _| value.include?(keyAlias) }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.getCertificateCollectionAndPrivateKeyFromP12(certificateFilePath, keyPass)
|
|
46
|
+
p12File = File.binread(certificateFilePath)
|
|
47
|
+
p12Object = OpenSSL::PKCS12.new(p12File, keyPass)
|
|
48
|
+
|
|
49
|
+
privateKey = OpenSSL::PKey::RSA.new(p12Object.key)
|
|
50
|
+
|
|
51
|
+
primaryX5Certificate = p12Object.certificate
|
|
52
|
+
additionalX5Certificates = p12Object.ca_certs
|
|
53
|
+
|
|
54
|
+
certificateList = [primaryX5Certificate]
|
|
55
|
+
certificateList.concat(additionalX5Certificates) if additionalX5Certificates
|
|
56
|
+
|
|
57
|
+
return [privateKey, certificateList]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.isP12GeneratedByCyberSource(filePath, password, logger = nil)
|
|
61
|
+
begin
|
|
62
|
+
_, certificateList = getCertificateCollectionAndPrivateKeyFromP12(filePath, password)
|
|
63
|
+
|
|
64
|
+
foundCertificate = getCertificateBasedOnKeyAlias(certificateList, Constants::DEFAULT_ALIAS_FOR_MLE_CERT)
|
|
65
|
+
|
|
66
|
+
return !foundCertificate.nil?
|
|
67
|
+
rescue => e
|
|
68
|
+
logger&.error("Error while checking if P12 is generated by CyberSource: #{e.message}")
|
|
69
|
+
return false
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|