Skip to content

Commit

Permalink
[Orbital] Add support for 3DS (#3261)
Browse files Browse the repository at this point in the history
This adds values for 3DS transactions. You can validate that those xml keys are valid by looking at the xsd.
  • Loading branch information
Pierre Nespo authored and filipebarcos committed Aug 2, 2019
1 parent a2059bb commit 7aa0477
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 10 deletions.
70 changes: 60 additions & 10 deletions lib/active_merchant/billing/gateways/orbital.rb
Original file line number Diff line number Diff line change
Expand Up @@ -465,16 +465,62 @@ def add_creditcard(xml, creditcard, currency=nil)
end
end

def add_cdpt_eci_and_xid(xml, creditcard)
xml.tag! :AuthenticationECIInd, creditcard.eci
xml.tag! :XID, creditcard.transaction_id if creditcard.transaction_id
def add_eci(xml, creditcard, three_d_secure)
eci = if three_d_secure
three_d_secure[:eci]
elsif creditcard.is_a?(NetworkTokenizationCreditCard)
creditcard.eci
end

xml.tag!(:AuthenticationECIInd, eci) if eci
end

def add_xid(xml, creditcard, three_d_secure)
xid = if three_d_secure && creditcard.brand == 'visa'
three_d_secure[:xid]
elsif creditcard.is_a?(NetworkTokenizationCreditCard)
creditcard.transaction_id
end

xml.tag!(:XID, xid) if xid
end

def add_cavv(xml, creditcard, three_d_secure)
return unless three_d_secure && creditcard.brand == 'visa'

xml.tag!(:CAVV, three_d_secure[:cavv])
end

def add_aav(xml, creditcard, three_d_secure)
return unless three_d_secure && creditcard.brand == 'master'

xml.tag!(:AAV, three_d_secure[:cavv])
end

def add_cdpt_payment_cryptogram(xml, creditcard)
def add_dpanind(xml, creditcard)
return unless creditcard.is_a?(NetworkTokenizationCreditCard)

xml.tag! :DPANInd, 'Y'
end

def add_digital_token_cryptogram(xml, creditcard)
return unless creditcard.is_a?(NetworkTokenizationCreditCard)

xml.tag! :DigitalTokenCryptogram, creditcard.payment_cryptogram
end

def add_aevv(xml, creditcard, three_d_secure)
return unless three_d_secure && creditcard.brand == 'american_express'

xml.tag!(:AEVV, three_d_secure[:cavv])
end

def add_pymt_brand_program_code(xml, creditcard, three_d_secure)
return unless three_d_secure && creditcard.brand == 'american_express'

xml.tag!(:PymtBrandProgramCode, 'ASK')
end

def add_refund(xml, currency=nil)
xml.tag! :AccountNum, nil

Expand Down Expand Up @@ -633,9 +679,11 @@ def build_new_order_xml(action, money, creditcard, parameters = {})

yield xml if block_given?

if creditcard.is_a?(NetworkTokenizationCreditCard)
add_cdpt_eci_and_xid(xml, creditcard)
end
three_d_secure = parameters[:three_d_secure]

add_eci(xml, creditcard, three_d_secure)
add_cavv(xml, creditcard, three_d_secure)
add_xid(xml, creditcard, three_d_secure)

xml.tag! :OrderID, format_order_id(parameters[:order_id])
xml.tag! :Amount, amount(money)
Expand All @@ -644,11 +692,12 @@ def build_new_order_xml(action, money, creditcard, parameters = {})
add_level_2_tax(xml, parameters)
add_level_2_advice_addendum(xml, parameters)

add_aav(xml, creditcard, three_d_secure)
# CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here.

if creditcard.is_a?(NetworkTokenizationCreditCard)
add_cdpt_payment_cryptogram(xml, creditcard)
end
add_dpanind(xml, creditcard)
add_aevv(xml, creditcard, three_d_secure)
add_digital_token_cryptogram(xml, creditcard)

if parameters[:soft_descriptors].is_a?(OrbitalSoftDescriptors)
add_soft_descriptors(xml, parameters[:soft_descriptors])
Expand All @@ -666,6 +715,7 @@ def build_new_order_xml(action, money, creditcard, parameters = {})

add_level_2_purchase(xml, parameters)
add_stored_credentials(xml, parameters)
add_pymt_brand_program_code(xml, creditcard, three_d_secure)
end
end
xml.target!
Expand Down
97 changes: 97 additions & 0 deletions test/remote/gateways/remote_orbital_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,103 @@ def test_successful_purchase_with_discover_network_tokenization_credit_card
assert_false response.authorization.blank?
end

[
{
card: {
number: '4112344112344113',
verification_value: '411',
brand: 'visa',
},
three_d_secure: {
eci: '5',
cavv: 'AAABAIcJIoQDIzAgVAkiAAAAAAA=',
xid: 'AAABAIcJIoQDIzAgVAkiAAAAAAA=',
},
address: {
address1: '55 Forever Ave',
address2: '',
city: 'Concord',
state: 'NH',
zip: '03301',
country: 'US',
},
},
{
card: {
number: '5112345112345114',
verification_value: '823',
brand: 'master',
},
three_d_secure: {
eci: '6',
cavv: 'Asju1ljfl86bAAAAAACm9zU6aqY=',
xid: 'Asju1ljfl86bAAAAAACm9zU6aqY=',
},
address: {
address1: 'Byway Street',
address2: '',
city: 'Portsmouth',
state: 'MA',
zip: '',
country: 'US',
},
},
{
card: {
number: '371144371144376',
verification_value: '1234',
brand: 'american_express',
},
three_d_secure: {
eci: '5',
cavv: 'AAABBWcSNIdjeUZThmNHAAAAAAA=',
xid: 'AAABBWcSNIdjeUZThmNHAAAAAAA=',
},
address: {
address1: '4 Northeastern Blvd',
address2: '',
city: 'Salem',
state: 'NH',
zip: '03105',
country: 'US',
},
}
].each do |fixture|
define_method("test_successful_#{fixture[:card][:brand]}_authorization_with_3ds") do
cc = credit_card(fixture[:card][:number], {
verification_value: fixture[:card][:verification_value],
brand: fixture[:card][:brand]
})
assert response = @gateway.authorize(100, cc, @options.merge(
order_id: '2',
currency: 'USD',
three_d_secure: fixture[:three_d_secure],
address: fixture[:address]
))

assert_success response
assert_equal 'Approved', response.message
assert_false response.authorization.blank?
end

define_method("test_successful_#{fixture[:card][:brand]}_purchase_with_3ds") do
cc = credit_card(fixture[:card][:number], {
verification_value: fixture[:card][:verification_value],
brand: fixture[:card][:brand]
})
assert response = @gateway.purchase(100, cc, @options.merge(
order_id: '2',
currency: 'USD',
three_d_secure: fixture[:three_d_secure],
address: fixture[:address]
))

assert_success response
assert_equal 'Approved', response.message
assert_false response.authorization.blank?
end
end

def test_successful_purchase_with_mit_stored_credentials
mit_stored_credentials = {
mit_msg_type: 'MUSE',
Expand Down
65 changes: 65 additions & 0 deletions test/unit/gateways/orbital_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ def setup
initiator: 'customer'
}
}
@three_d_secure_options = {
three_d_secure: {
eci: '5',
xid: 'TESTXID',
cavv: 'TESTCAVV',
}
}
end

def test_successful_purchase
Expand Down Expand Up @@ -92,6 +99,64 @@ def test_network_tokenization_credit_card_data
end.respond_with(successful_purchase_response)
end

def test_three_d_secure_data_on_visa_purchase
stub_comms do
@gateway.purchase(50, credit_card, @options.merge(@three_d_secure_options))
end.check_request do |endpoint, data, headers|
assert_match %{<AuthenticationECIInd>5</AuthenticationECIInd>}, data
assert_match %{<CAVV>TESTCAVV</CAVV>}, data
assert_match %{<XID>TESTXID</XID>}, data
end.respond_with(successful_purchase_response)
end

def test_three_d_secure_data_on_visa_authorization
stub_comms do
@gateway.authorize(50, credit_card, @options.merge(@three_d_secure_options))
end.check_request do |endpoint, data, headers|
assert_match %{<AuthenticationECIInd>5</AuthenticationECIInd>}, data
assert_match %{<CAVV>TESTCAVV</CAVV>}, data
assert_match %{<XID>TESTXID</XID>}, data
end.respond_with(successful_purchase_response)
end

def test_three_d_secure_data_on_master_purchase
stub_comms do
@gateway.purchase(50, credit_card(nil, brand: 'master'), @options.merge(@three_d_secure_options))
end.check_request do |endpoint, data, headers|
assert_match %{<AuthenticationECIInd>5</AuthenticationECIInd>}, data
assert_match %{<AAV>TESTCAVV</AAV>}, data
end.respond_with(successful_purchase_response)
end

def test_three_d_secure_data_on_master_authorization
stub_comms do
@gateway.authorize(50, credit_card(nil, brand: 'master'), @options.merge(@three_d_secure_options))
end.check_request do |endpoint, data, headers|
assert_match %{<AuthenticationECIInd>5</AuthenticationECIInd>}, data
assert_match %{<AAV>TESTCAVV</AAV>}, data
end.respond_with(successful_purchase_response)
end

def test_three_d_secure_data_on_american_express_purchase
stub_comms do
@gateway.purchase(50, credit_card(nil, brand: 'american_express'), @options.merge(@three_d_secure_options))
end.check_request do |endpoint, data, headers|
assert_match %{<AuthenticationECIInd>5</AuthenticationECIInd>}, data
assert_match %{<AEVV>TESTCAVV</AEVV>}, data
assert_match %{<PymtBrandProgramCode>ASK</PymtBrandProgramCode>}, data
end.respond_with(successful_purchase_response)
end

def test_three_d_secure_data_on_american_express_authorization
stub_comms do
@gateway.authorize(50, credit_card(nil, brand: 'american_express'), @options.merge(@three_d_secure_options))
end.check_request do |endpoint, data, headers|
assert_match %{<AuthenticationECIInd>5</AuthenticationECIInd>}, data
assert_match %{<AEVV>TESTCAVV</AEVV>}, data
assert_match %{<PymtBrandProgramCode>ASK</PymtBrandProgramCode>}, data
end.respond_with(successful_purchase_response)
end

def test_currency_exponents
stub_comms do
@gateway.purchase(50, credit_card, :order_id => '1')
Expand Down

0 comments on commit 7aa0477

Please sign in to comment.