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.
Files changed (291) hide show
  1. checksums.yaml +4 -4
  2. data/lib/AuthenticationSDK/authentication/jwt/JwtToken.rb +17 -7
  3. data/lib/AuthenticationSDK/core/Authorization.rb +2 -2
  4. data/lib/AuthenticationSDK/core/MerchantConfig.rb +278 -23
  5. data/lib/AuthenticationSDK/util/Cache.rb +158 -8
  6. data/lib/AuthenticationSDK/util/CachedMLEKId.rb +17 -0
  7. data/lib/AuthenticationSDK/util/CertificateUtility.rb +109 -29
  8. data/lib/AuthenticationSDK/util/Constants.rb +6 -0
  9. data/lib/AuthenticationSDK/util/JWT/JWTExceptions.rb +81 -0
  10. data/lib/AuthenticationSDK/util/JWT/JWTUtility.rb +154 -0
  11. data/lib/AuthenticationSDK/util/MLEUtility.rb +167 -11
  12. data/lib/AuthenticationSDK/util/Utility.rb +37 -1
  13. data/lib/cybersource_rest_client/api/bank_account_validation_api.rb +13 -5
  14. data/lib/cybersource_rest_client/api/batches_api.rb +50 -18
  15. data/lib/cybersource_rest_client/api/billing_agreements_api.rb +33 -9
  16. data/lib/cybersource_rest_client/api/bin_lookup_api.rb +11 -3
  17. data/lib/cybersource_rest_client/api/capture_api.rb +11 -3
  18. data/lib/cybersource_rest_client/api/chargeback_details_api.rb +11 -3
  19. data/lib/cybersource_rest_client/api/chargeback_summaries_api.rb +11 -3
  20. data/lib/cybersource_rest_client/api/conversion_details_api.rb +11 -3
  21. data/lib/cybersource_rest_client/api/create_new_webhooks_api.rb +35 -11
  22. data/lib/cybersource_rest_client/api/credit_api.rb +11 -3
  23. data/lib/cybersource_rest_client/api/customer_api.rb +44 -12
  24. data/lib/cybersource_rest_client/api/customer_payment_instrument_api.rb +55 -15
  25. data/lib/cybersource_rest_client/api/customer_shipping_address_api.rb +55 -15
  26. data/lib/cybersource_rest_client/api/decision_manager_api.rb +57 -17
  27. data/lib/cybersource_rest_client/api/device_de_association_api.rb +24 -8
  28. data/lib/cybersource_rest_client/api/device_search_api.rb +26 -10
  29. data/lib/cybersource_rest_client/api/download_dtd_api.rb +11 -3
  30. data/lib/cybersource_rest_client/api/download_xsd_api.rb +11 -3
  31. data/lib/cybersource_rest_client/api/emv_tag_details_api.rb +22 -6
  32. data/lib/cybersource_rest_client/api/enrollment_api.rb +104 -0
  33. data/lib/cybersource_rest_client/api/flex_api_api.rb +11 -3
  34. data/lib/cybersource_rest_client/api/instructions_api.rb +452 -0
  35. data/lib/cybersource_rest_client/api/instrument_identifier_api.rb +66 -18
  36. data/lib/cybersource_rest_client/api/interchange_clearing_level_details_api.rb +11 -3
  37. data/lib/cybersource_rest_client/api/invoice_settings_api.rb +22 -6
  38. data/lib/cybersource_rest_client/api/invoices_api.rb +77 -21
  39. data/lib/cybersource_rest_client/api/manage_webhooks_api.rb +81 -25
  40. data/lib/cybersource_rest_client/api/merchant_boarding_api.rb +24 -8
  41. data/lib/cybersource_rest_client/api/merchant_defined_fields_api.rb +50 -18
  42. data/lib/cybersource_rest_client/api/microform_integration_api.rb +11 -3
  43. data/lib/cybersource_rest_client/api/net_fundings_api.rb +11 -3
  44. data/lib/cybersource_rest_client/api/notification_of_changes_api.rb +11 -3
  45. data/lib/cybersource_rest_client/api/offers_api.rb +24 -8
  46. data/lib/cybersource_rest_client/api/orders_api.rb +22 -6
  47. data/lib/cybersource_rest_client/api/payer_authentication_api.rb +33 -9
  48. data/lib/cybersource_rest_client/api/payment_batch_summaries_api.rb +11 -3
  49. data/lib/cybersource_rest_client/api/payment_instrument_api.rb +44 -12
  50. data/lib/cybersource_rest_client/api/payment_links_api.rb +44 -12
  51. data/lib/cybersource_rest_client/api/payment_tokens_api.rb +11 -3
  52. data/lib/cybersource_rest_client/api/payments_api.rb +66 -18
  53. data/lib/cybersource_rest_client/api/payouts_api.rb +11 -3
  54. data/lib/cybersource_rest_client/api/plans_api.rb +88 -24
  55. data/lib/cybersource_rest_client/api/purchase_and_refund_details_api.rb +11 -3
  56. data/lib/cybersource_rest_client/api/push_funds_api.rb +11 -3
  57. data/lib/cybersource_rest_client/api/refund_api.rb +22 -6
  58. data/lib/cybersource_rest_client/api/report_definitions_api.rb +22 -6
  59. data/lib/cybersource_rest_client/api/report_downloads_api.rb +11 -3
  60. data/lib/cybersource_rest_client/api/report_subscriptions_api.rb +55 -15
  61. data/lib/cybersource_rest_client/api/reports_api.rb +33 -9
  62. data/lib/cybersource_rest_client/api/retrieval_details_api.rb +11 -3
  63. data/lib/cybersource_rest_client/api/retrieval_summaries_api.rb +11 -3
  64. data/lib/cybersource_rest_client/api/reversal_api.rb +22 -6
  65. data/lib/cybersource_rest_client/api/search_transactions_api.rb +22 -6
  66. data/lib/cybersource_rest_client/api/secure_file_share_api.rb +22 -6
  67. data/lib/cybersource_rest_client/api/subscriptions_api.rb +97 -33
  68. data/lib/cybersource_rest_client/api/subscriptions_follow_ons_api.rb +22 -6
  69. data/lib/cybersource_rest_client/api/taxes_api.rb +22 -6
  70. data/lib/cybersource_rest_client/api/token_api.rb +24 -8
  71. data/lib/cybersource_rest_client/api/tokenize_api.rb +107 -0
  72. data/lib/cybersource_rest_client/api/tokenized_card_api.rb +126 -9
  73. data/lib/cybersource_rest_client/api/transaction_batches_api.rb +44 -12
  74. data/lib/cybersource_rest_client/api/transaction_details_api.rb +11 -3
  75. data/lib/cybersource_rest_client/api/transient_token_data_api.rb +22 -6
  76. data/lib/cybersource_rest_client/api/unified_checkout_capture_context_api.rb +11 -3
  77. data/lib/cybersource_rest_client/api/user_management_api.rb +11 -3
  78. data/lib/cybersource_rest_client/api/user_management_search_api.rb +11 -3
  79. data/lib/cybersource_rest_client/api/verification_api.rb +22 -6
  80. data/lib/cybersource_rest_client/api/void_api.rb +55 -15
  81. data/lib/cybersource_rest_client/api_client.rb +20 -3
  82. data/lib/cybersource_rest_client/models/acpv1instructions_decline_threshold.rb +232 -0
  83. data/lib/cybersource_rest_client/models/acpv1instructions_mandates.rb +405 -0
  84. data/lib/cybersource_rest_client/models/acpv1instructions_recurring_payment_information.rb +191 -0
  85. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconf_processor_info_payment_instrument_verifi_results.rb +213 -0
  86. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_confirmation_data.rb +229 -0
  87. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_merchant_information.rb +258 -0
  88. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_order_information.rb +377 -0
  89. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_order_information_shipping_details.rb +206 -0
  90. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_processor_information.rb +425 -0
  91. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idconfirmations_processor_information_payment_instrument.rb +190 -0
  92. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_attachments.rb +258 -0
  93. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_client_reference_information.rb +215 -0
  94. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_mandate_reference_data.rb +205 -0
  95. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_merchant_information.rb +334 -0
  96. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_merchant_information_merchant_descriptor.rb +250 -0
  97. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information.rb +228 -0
  98. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_amount_detail.rb +354 -0
  99. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_items.rb +367 -0
  100. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_items_additional_info.rb +231 -0
  101. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_items_policies.rb +346 -0
  102. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_line_items.rb +190 -0
  103. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_order_information_ship_to.rb +686 -0
  104. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_payment_options.rb +217 -0
  105. data/lib/cybersource_rest_client/models/acpv1instructionsinstruction_idcredentials_transaction_data.rb +348 -0
  106. data/lib/cybersource_rest_client/models/acpv1tokens_assurance_data.rb +313 -0
  107. data/lib/cybersource_rest_client/models/acpv1tokens_authenticated_identities.rb +237 -0
  108. data/lib/cybersource_rest_client/models/acpv1tokens_authentication_context.rb +191 -0
  109. data/lib/cybersource_rest_client/models/acpv1tokens_bill_to.rb +400 -0
  110. data/lib/cybersource_rest_client/models/acpv1tokens_buyer_information.rb +229 -0
  111. data/lib/cybersource_rest_client/models/acpv1tokens_buyer_information_personal_identification.rb +212 -0
  112. data/lib/cybersource_rest_client/models/acpv1tokens_consent_data.rb +297 -0
  113. data/lib/cybersource_rest_client/models/{rbsv1subscriptions_client_reference_information.rb → acpv1tokens_consumer_identity.rb} +73 -61
  114. data/lib/cybersource_rest_client/models/acpv1tokens_device_information.rb +378 -0
  115. data/lib/cybersource_rest_client/models/acpv1tokens_device_information_device_data.rb +302 -0
  116. data/lib/cybersource_rest_client/models/acpv1tokens_enrollment_reference_data.rb +207 -0
  117. data/lib/cybersource_rest_client/models/acpv1tokens_payment_information.rb +215 -0
  118. data/lib/cybersource_rest_client/models/acpv1tokens_payment_information_customer.rb +197 -0
  119. data/lib/cybersource_rest_client/models/acpv1tokens_payment_information_instrument_identifier.rb +206 -0
  120. data/lib/cybersource_rest_client/models/acpv1tokens_payment_information_payment_instrument.rb +197 -0
  121. data/lib/cybersource_rest_client/models/agentic_cancel_purchase_intent_request.rb +257 -0
  122. data/lib/cybersource_rest_client/models/agentic_card_enrollment_bad_request_response400.rb +189 -0
  123. data/lib/cybersource_rest_client/models/agentic_card_enrollment_bad_request_response400_error.rb +238 -0
  124. data/lib/cybersource_rest_client/models/agentic_card_enrollment_bad_request_response400_error_detail.rb +224 -0
  125. data/lib/cybersource_rest_client/models/agentic_card_enrollment_request.rb +325 -0
  126. data/lib/cybersource_rest_client/models/agentic_card_enrollment_response200.rb +206 -0
  127. data/lib/cybersource_rest_client/models/agentic_card_enrollment_response202.rb +219 -0
  128. data/lib/cybersource_rest_client/models/agentic_confirm_transaction_events_request.rb +247 -0
  129. data/lib/cybersource_rest_client/models/agentic_confirm_transaction_events_response202.rb +195 -0
  130. data/lib/cybersource_rest_client/models/agentic_create_purchase_intent_request.rb +327 -0
  131. data/lib/cybersource_rest_client/models/agentic_create_purchase_intent_response200.rb +222 -0
  132. data/lib/cybersource_rest_client/models/agentic_pending_purchase_intent_response202.rb +241 -0
  133. data/lib/cybersource_rest_client/models/agentic_retrieve_payment_credentials_request.rb +247 -0
  134. data/lib/cybersource_rest_client/models/agentic_retrieve_payment_credentials_response200.rb +200 -0
  135. data/lib/cybersource_rest_client/models/{rbsv1plans_client_reference_information.rb → agentic_retrieve_payment_credentials_response200_transaction_response_complete.rb} +52 -47
  136. data/lib/cybersource_rest_client/models/agentic_retrieve_payment_credentials_response200_transaction_response_with_pending_events.rb +235 -0
  137. data/lib/cybersource_rest_client/models/agentic_update_purchase_intent_request.rb +315 -0
  138. data/lib/cybersource_rest_client/models/boardingv1registrations_organization_information_business_information.rb +36 -1
  139. data/lib/cybersource_rest_client/models/boardingv1registrations_organization_information_business_information_localized_names.rb +254 -0
  140. data/lib/cybersource_rest_client/models/create_plan_request.rb +1 -11
  141. data/lib/cybersource_rest_client/models/create_subscription_request.rb +1 -1
  142. data/lib/cybersource_rest_client/models/create_subscription_request_1.rb +1 -1
  143. data/lib/cybersource_rest_client/models/create_subscription_response.rb +15 -5
  144. data/lib/cybersource_rest_client/models/generate_unified_checkout_capture_context_request.rb +13 -2
  145. data/lib/cybersource_rest_client/models/get_all_subscriptions_response_client_reference_information.rb +196 -0
  146. data/lib/cybersource_rest_client/models/get_all_subscriptions_response_subscriptions.rb +11 -1
  147. data/lib/cybersource_rest_client/models/get_subscription_response.rb +11 -1
  148. data/lib/cybersource_rest_client/models/get_subscription_response_1_payment_instrument.rb +1 -1
  149. data/lib/cybersource_rest_client/models/get_subscription_response_1_payment_instrument_buyer_information.rb +1 -1
  150. data/lib/cybersource_rest_client/models/get_subscription_response_1_shipping_address.rb +1 -1
  151. data/lib/cybersource_rest_client/models/get_subscription_response_reactivation_information.rb +22 -22
  152. data/lib/cybersource_rest_client/models/inline_response_200.rb +9 -44
  153. data/lib/cybersource_rest_client/models/inline_response_200_1.rb +29 -31
  154. data/lib/cybersource_rest_client/models/inline_response_200_10.rb +33 -37
  155. data/lib/cybersource_rest_client/models/{inline_response_200_9_devices.rb → inline_response_200_10_devices.rb} +2 -2
  156. 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
  157. data/lib/cybersource_rest_client/models/inline_response_200_11.rb +47 -86
  158. data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded.rb → inline_response_200_11__embedded.rb} +2 -2
  159. data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded__links.rb → inline_response_200_11__embedded__links.rb} +2 -2
  160. data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded__links_reports.rb → inline_response_200_11__embedded__links_reports.rb} +1 -1
  161. data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded_batches.rb → inline_response_200_11__embedded_batches.rb} +3 -3
  162. data/lib/cybersource_rest_client/models/{inline_response_200_10__embedded_totals.rb → inline_response_200_11__embedded_totals.rb} +1 -1
  163. data/lib/cybersource_rest_client/models/inline_response_200_11__links.rb +16 -17
  164. data/lib/cybersource_rest_client/models/inline_response_200_12.rb +47 -49
  165. data/lib/cybersource_rest_client/models/inline_response_200_12__links.rb +201 -0
  166. data/lib/cybersource_rest_client/models/{inline_response_200_11__links_report.rb → inline_response_200_12__links_report.rb} +1 -1
  167. data/lib/cybersource_rest_client/models/{inline_response_200_11_billing.rb → inline_response_200_12_billing.rb} +1 -1
  168. data/lib/cybersource_rest_client/models/inline_response_200_13.rb +102 -31
  169. data/lib/cybersource_rest_client/models/{inline_response_200_12_records.rb → inline_response_200_13_records.rb} +3 -3
  170. data/lib/cybersource_rest_client/models/{inline_response_200_12_response_record.rb → inline_response_200_13_response_record.rb} +2 -2
  171. 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
  172. data/lib/cybersource_rest_client/models/{inline_response_200_12_source_record.rb → inline_response_200_13_source_record.rb} +1 -1
  173. data/lib/cybersource_rest_client/models/inline_response_200_14.rb +18 -84
  174. data/lib/cybersource_rest_client/models/inline_response_200_15.rb +287 -0
  175. data/lib/cybersource_rest_client/models/{inline_response_200_14_client_reference_information.rb → inline_response_200_15_client_reference_information.rb} +1 -1
  176. data/lib/cybersource_rest_client/models/{inline_response_200_content.rb → inline_response_200_1_content.rb} +1 -1
  177. data/lib/cybersource_rest_client/models/inline_response_200_2.rb +32 -103
  178. data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded.rb → inline_response_200_2__embedded.rb} +3 -3
  179. data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_capture.rb → inline_response_200_2__embedded_capture.rb} +2 -2
  180. data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_capture__links.rb → inline_response_200_2__embedded_capture__links.rb} +2 -2
  181. 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
  182. data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_reversal.rb → inline_response_200_2__embedded_reversal.rb} +2 -2
  183. data/lib/cybersource_rest_client/models/{inline_response_200_1__embedded_reversal__links.rb → inline_response_200_2__embedded_reversal__links.rb} +2 -2
  184. 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
  185. data/lib/cybersource_rest_client/models/inline_response_200_3.rb +100 -54
  186. data/lib/cybersource_rest_client/models/inline_response_200_4.rb +65 -25
  187. data/lib/cybersource_rest_client/models/{inline_response_200_3_integration_information.rb → inline_response_200_4_integration_information.rb} +2 -2
  188. 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
  189. data/lib/cybersource_rest_client/models/inline_response_200_5.rb +25 -126
  190. data/lib/cybersource_rest_client/models/inline_response_200_6.rb +1 -12
  191. data/lib/cybersource_rest_client/models/inline_response_200_7.rb +129 -51
  192. data/lib/cybersource_rest_client/models/inline_response_200_8.rb +55 -10
  193. data/lib/cybersource_rest_client/models/{inline_response_200_7_devices.rb → inline_response_200_8_devices.rb} +1 -1
  194. data/lib/cybersource_rest_client/models/inline_response_200_9.rb +10 -55
  195. data/lib/cybersource_rest_client/models/{inline_response_200_10__links.rb → inline_response_200_details.rb} +18 -17
  196. data/lib/cybersource_rest_client/models/inline_response_200_errors.rb +213 -0
  197. data/lib/cybersource_rest_client/models/inline_response_200_responses.rb +224 -0
  198. data/lib/cybersource_rest_client/models/inline_response_201_3_setups_payments.rb +15 -5
  199. data/lib/cybersource_rest_client/models/patch_customer_payment_instrument_request.rb +9 -9
  200. data/lib/cybersource_rest_client/models/patch_customer_request.rb +9 -9
  201. data/lib/cybersource_rest_client/models/patch_customer_shipping_address_request.rb +3 -3
  202. data/lib/cybersource_rest_client/models/patch_payment_instrument_request.rb +9 -9
  203. data/lib/cybersource_rest_client/models/payment_instrument_list_1__embedded_payment_instruments.rb +8 -8
  204. data/lib/cybersource_rest_client/models/payment_instrument_list__embedded.rb +1 -1
  205. data/lib/cybersource_rest_client/models/payments_products.rb +15 -5
  206. data/lib/cybersource_rest_client/models/post_customer_payment_instrument_request.rb +9 -9
  207. data/lib/cybersource_rest_client/models/post_customer_request.rb +9 -9
  208. data/lib/cybersource_rest_client/models/post_customer_shipping_address_request.rb +3 -3
  209. data/lib/cybersource_rest_client/models/post_issuer_life_cycle_simulation_request.rb +211 -0
  210. data/lib/cybersource_rest_client/models/post_payment_instrument_request.rb +9 -9
  211. data/lib/cybersource_rest_client/models/post_tokenize_request.rb +199 -0
  212. data/lib/cybersource_rest_client/models/ptsv2payments_aggregator_information.rb +22 -5
  213. data/lib/cybersource_rest_client/models/ptsv2payments_travel_information_transit_airline_ancillary_information.rb +22 -5
  214. data/lib/cybersource_rest_client/models/ptsv2payments_travel_information_transit_airline_ancillary_information_service.rb +39 -5
  215. data/lib/cybersource_rest_client/models/ptsv2paymentsidrefunds_travel_information.rb +246 -0
  216. data/lib/cybersource_rest_client/models/ptsv2paymentsidrefunds_travel_information_transit.rb +189 -0
  217. data/lib/cybersource_rest_client/models/ptsv2paymentsidrefunds_travel_information_transit_airline.rb +889 -0
  218. data/lib/cybersource_rest_client/models/ptsv2paymentsidrefunds_travel_information_transit_airline_ancillary_information.rb +259 -0
  219. data/lib/cybersource_rest_client/models/{rbsv1subscriptions_client_reference_information_partner.rb → ptsv2paymentsidrefunds_travel_information_transit_airline_ancillary_information_service.rb} +24 -24
  220. data/lib/cybersource_rest_client/models/refund_capture_request.rb +1 -1
  221. data/lib/cybersource_rest_client/models/refund_payment_request.rb +1 -1
  222. data/lib/cybersource_rest_client/models/shipping_address_list_for_customer__embedded.rb +1 -1
  223. data/lib/cybersource_rest_client/models/tms_issuerlifecycleeventsimulations_metadata_card_art_combined_asset.rb +190 -0
  224. data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_merchant_information.rb → tms_merchant_information.rb} +2 -2
  225. data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_merchant_information_merchant_descriptor.rb → tms_merchant_information_merchant_descriptor.rb} +1 -1
  226. 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
  227. 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
  228. 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
  229. data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument_instrument_identifier.rb → tmsv2tokenize_default_payment_instrument_instrument_identifier.rb} +1 -1
  230. data/lib/cybersource_rest_client/models/tmsv2tokenize_processing_information.rb +205 -0
  231. data/lib/cybersource_rest_client/models/tmsv2tokenize_token_information.rb +247 -0
  232. data/lib/cybersource_rest_client/models/tmsv2tokenize_token_information_customer.rb +289 -0
  233. data/lib/cybersource_rest_client/models/{tmsv2customers__embedded.rb → tmsv2tokenize_token_information_customer__embedded.rb} +3 -3
  234. data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_payment_instrument.rb → tmsv2tokenize_token_information_customer__embedded_default_payment_instrument.rb} +10 -10
  235. 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
  236. 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
  237. 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
  238. 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
  239. 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
  240. 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
  241. 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
  242. 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
  243. data/lib/cybersource_rest_client/models/{tmsv2customers__embedded_default_shipping_address.rb → tmsv2tokenize_token_information_customer__embedded_default_shipping_address.rb} +4 -4
  244. 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
  245. 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
  246. 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
  247. 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
  248. 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
  249. data/lib/cybersource_rest_client/models/{tmsv2customers__links.rb → tmsv2tokenize_token_information_customer__links.rb} +4 -4
  250. data/lib/cybersource_rest_client/models/{tmsv2customers__links_payment_instruments.rb → tmsv2tokenize_token_information_customer__links_payment_instruments.rb} +1 -1
  251. data/lib/cybersource_rest_client/models/{tmsv2customers__links_self.rb → tmsv2tokenize_token_information_customer__links_self.rb} +1 -1
  252. data/lib/cybersource_rest_client/models/{tmsv2customers__links_shipping_address.rb → tmsv2tokenize_token_information_customer__links_shipping_address.rb} +1 -1
  253. data/lib/cybersource_rest_client/models/{tmsv2customers_buyer_information.rb → tmsv2tokenize_token_information_customer_buyer_information.rb} +1 -1
  254. data/lib/cybersource_rest_client/models/{tmsv2customers_client_reference_information.rb → tmsv2tokenize_token_information_customer_client_reference_information.rb} +1 -1
  255. data/lib/cybersource_rest_client/models/{tmsv2customers_default_payment_instrument.rb → tmsv2tokenize_token_information_customer_default_payment_instrument.rb} +1 -1
  256. data/lib/cybersource_rest_client/models/{tmsv2customers_default_shipping_address.rb → tmsv2tokenize_token_information_customer_default_shipping_address.rb} +1 -1
  257. data/lib/cybersource_rest_client/models/{tmsv2customers_merchant_defined_information.rb → tmsv2tokenize_token_information_customer_merchant_defined_information.rb} +1 -1
  258. data/lib/cybersource_rest_client/models/{tmsv2customers_metadata.rb → tmsv2tokenize_token_information_customer_metadata.rb} +1 -1
  259. data/lib/cybersource_rest_client/models/{tmsv2customers_object_information.rb → tmsv2tokenize_token_information_customer_object_information.rb} +1 -1
  260. data/lib/cybersource_rest_client/models/tmsv2tokenizedcardstokenized_card_idissuerlifecycleeventsimulations_card.rb +230 -0
  261. data/lib/cybersource_rest_client/models/tmsv2tokenizedcardstokenized_card_idissuerlifecycleeventsimulations_metadata.rb +189 -0
  262. data/lib/cybersource_rest_client/models/tmsv2tokenizedcardstokenized_card_idissuerlifecycleeventsimulations_metadata_card_art.rb +189 -0
  263. data/lib/cybersource_rest_client/models/update_subscription.rb +1 -1
  264. data/lib/cybersource_rest_client/models/upv1capturecontexts_data.rb +28 -6
  265. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_buyer_information.rb +41 -5
  266. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_buyer_information_personal_identification.rb +1 -0
  267. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_client_reference_information_partner.rb +3 -3
  268. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_consumer_authentication_information.rb +24 -5
  269. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_device_information.rb +196 -0
  270. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_merchant_defined_information.rb +3 -2
  271. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_merchant_information_merchant_descriptor.rb +124 -5
  272. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information.rb +15 -5
  273. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_amount_details.rb +15 -5
  274. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_amount_details_tax_details.rb +213 -0
  275. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_invoice_details.rb +213 -0
  276. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_line_items.rb +30 -0
  277. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_line_items_passenger.rb +8 -0
  278. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_order_information_line_items_tax_details.rb +7 -0
  279. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_payment_information.rb +189 -0
  280. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_payment_information_card.rb +196 -0
  281. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_processing_information.rb +1 -0
  282. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_processing_information_authorization_options.rb +74 -5
  283. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_processing_information_authorization_options_initiator.rb +1 -0
  284. data/lib/cybersource_rest_client/models/upv1capturecontexts_data_recipient_information.rb +39 -5
  285. data/lib/cybersource_rest_client/models/upv1capturecontexts_order_information.rb +1 -0
  286. data/lib/cybersource_rest_client/utilities/capture_context/capture_context_parsing_utility.rb +113 -0
  287. data/lib/cybersource_rest_client/utilities/capture_context/public_key_fetcher.rb +131 -0
  288. data/lib/cybersource_rest_client/utilities/jwe_utility.rb +1 -1
  289. data/lib/cybersource_rest_client.rb +144 -62
  290. metadata +151 -65
  291. /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
- end
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.mapToControlMLEonAPI && operation_ids
23
+ if !merchant_config.internalMapToControlRequestMLEonAPI.nil? && !merchant_config.internalMapToControlRequestMLEonAPI.empty? && operation_ids
20
24
  operation_ids.each do |operation_id|
21
- if merchant_config.mapToControlMLEonAPI.key?(operation_id)
22
- is_mle_for_api = merchant_config.mapToControlMLEonAPI[operation_id]
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
- return nil if certificate.subject.to_s.empty? && certificate.issuer.to_s.empty?
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
- certificate.serial.nil? ? nil : certificate.serial.to_s
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