Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade & Add 3ds2 redirect/native #192

Merged
merged 4 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public ResponseEntity<PaymentResponse> payments(@RequestHeader String host, @Req
var orderRef = UUID.randomUUID().toString();
var amount = new Amount()
.currency("EUR")
.value(10000L); // value is 10€ in minor units
.value(10000L); // value is 100€ in minor units

paymentRequest.setMerchantAccount(this.applicationProperty.getMerchantAccount()); // required
paymentRequest.setChannel(PaymentRequest.ChannelEnum.WEB);
Expand All @@ -89,16 +89,27 @@ public ResponseEntity<PaymentResponse> payments(@RequestHeader String host, @Req
new LineItem().quantity(1L).amountIncludingTax(5000L).description("Sunglasses"),
new LineItem().quantity(1L).amountIncludingTax(5000L).description("Headphones"))
);
// required for 3ds2 native flow
paymentRequest.setAdditionalData(Collections.singletonMap("allow3DS2", "true"));
// required for 3ds2 native flow
paymentRequest.setOrigin(request.getScheme() + "://" + host );

var authenticationData = new AuthenticationData();
authenticationData.setAttemptAuthentication(AuthenticationData.AttemptAuthenticationEnum.ALWAYS);
// add the following lines for Native 3DS2:
//var threeDSRequestData = new ThreeDSRequestData();
//threeDSRequestData.setNativeThreeDS(ThreeDSRequestData.NativeThreeDSEnum.PREFERRED);
//authenticationData.setThreeDSRequestData(threeDSRequestData);

paymentRequest.setAuthenticationData(authenticationData);

// required for 3ds2 redirect flow
paymentRequest.setOrigin(request.getScheme() + "://" + host);
// required for 3ds2
paymentRequest.setBrowserInfo(body.getBrowserInfo());
// required by some issuers for 3ds2
paymentRequest.setShopperIP(request.getRemoteAddr());
paymentRequest.setPaymentMethod(body.getPaymentMethod());

// we strongly recommend that you the billingAddress in your request
// card schemes require this for channel web, iOS, and Android implementations
//paymentRequest.setBillingAddress(new Address());
log.info("REST request to make Adyen payment {}", paymentRequest);
var response = paymentsApi.payments(paymentRequest);
return ResponseEntity.ok()
Expand Down Expand Up @@ -133,6 +144,9 @@ public RedirectView redirect(@RequestParam(required = false) String payload, @Re

PaymentCompletionDetails details = new PaymentCompletionDetails();
if (redirectResult != null && !redirectResult.isEmpty()) {
// for redirect, you are redirected to an Adyen domain to complete the 3DS2 challenge
// after completing the 3DS2 challenge, you get the redirect result from Adyen in the returnUrl
// we then pass on the redirectResult
details.redirectResult(redirectResult);
} else if (payload != null && !payload.isEmpty()) {
details.payload(payload);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ async function initCheckout() {
holderNameRequired: true,
name: "Credit or debit card",
amount: {
value: 1000,
value: 10000,
currency: "EUR",
},
},
paypal: {
amount: {
value: 1000,
value: 10000,
currency: "USD",
},
environment: "test", // Change this to "live" when you're ready to accept live PayPal payments
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@
/>

<!-- Adyen JS from TEST environment (change to live for production)-->
<script src="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/5.40.0/adyen.js"
integrity="sha384-ds1t0hgFCe636DXFRL6ciadL2Wb4Yihh27R4JO7d9CF7sFY3NJE4aPCK0EpzaYXD"
<script src="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/5.53.2/adyen.js"
integrity="sha384-ng3HLoZIlQ3BLgyGyGNiwWSx6LEPIlmxVuGRw72skZFt9mL8OweRjp7vcPzSqxTj"
crossorigin="anonymous"></script>

<!-- Adyen CSS from TEST environment (change to live for production)-->
<link rel="stylesheet"
href="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/5.40.0/adyen.css"
integrity="sha384-BRZCzbS8n6hZVj8BESE6thGk0zSkUZfUWxL/vhocKu12k3NZ7xpNsIK39O2aWuni"
crossorigin="anonymous">
href="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/5.53.2/adyen.css"
integrity="sha384-9EdBqZRrjozkt+Be5ycjHBTi+4DYrafpC1KyPnNyTBfjBIZ5+oMp8BbgvPLGgsE0"
crossorigin="anonymous"/>

<link rel="stylesheet" href="/css/application.css" />
</head>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ <h2>Cart</h2>
</ul>
</div>
<div class="cart-footer"><span class="cart-footer-label">Total:</span><span
class="cart-footer-amount">10.00</span>
class="cart-footer-amount">100.00</span>
<a th:href="@{/checkout(type=${type})}">
<p class="button">Continue to checkout</p>
</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import com.adyen.Client;
import com.adyen.giving.ApplicationProperty;
import com.adyen.enums.Environment;
import com.adyen.giving.service.DonationService;
import com.adyen.model.checkout.*;
import com.adyen.service.checkout.PaymentsApi;
import com.adyen.service.exception.ApiException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.view.RedirectView;
Expand All @@ -31,6 +33,8 @@ public class CheckoutResource {

private final PaymentsApi paymentsApi;

@Autowired
private DonationService donationService;
private static final String DONATION_TOKEN = "DonationToken";

private static final String PAYMENT_ORIGINAL_PSPREFERENCE = "PaymentOriginalPspReference";
Expand Down Expand Up @@ -59,23 +63,13 @@ public CheckoutResource(ApplicationProperty applicationProperty) {
@PostMapping("/donations")
public ResponseEntity<DonationPaymentResponse> donations(@RequestBody Amount body, @RequestHeader String host, HttpServletRequest request) throws IOException, ApiException {
DonationPaymentRequest donationRequest = new DonationPaymentRequest();
HttpSession session = request.getSession();
var pspReference = session.getAttribute(PAYMENT_ORIGINAL_PSPREFERENCE);
var donationToken = session.getAttribute(DONATION_TOKEN);

if (pspReference == null) {
log.info("Could not find the PspReference in the stored session.");
return ResponseEntity.badRequest().build();
}

if (donationToken == null) {
log.info("Could not find the DonationToken in the stored session.");
return ResponseEntity.badRequest().build();
}
var pspReference = donationService.getPaymentOriginalPspReference();
var donationToken = donationService.getDonationToken();

donationRequest.amount(body);
donationRequest.reference(UUID.randomUUID().toString());
donationRequest.setPaymentMethod(new CheckoutPaymentMethod(new CardDetails()));
donationRequest.setPaymentMethod(new DonationPaymentMethod(new CardDetails()));
donationRequest.setDonationToken(donationToken.toString());
donationRequest.donationOriginalPspReference(pspReference.toString());
donationRequest.setDonationAccount(this.applicationProperty.getDonationMerchantAccount());
Expand Down Expand Up @@ -148,14 +142,8 @@ public ResponseEntity<PaymentResponse> payments(@RequestHeader String host, @Req
log.info("REST request to make Adyen payment {}", paymentRequest);
var response = paymentsApi.payments(paymentRequest);

var session = request.getSession();
if (response.getDonationToken() == null) {
log.error("The payments endpoint did not return a donationToken, please enable this in your Customer Area. See README.");
}
else {
session.setAttribute(PAYMENT_ORIGINAL_PSPREFERENCE, response.getPspReference());
session.setAttribute(DONATION_TOKEN, response.getDonationToken());
}
donationService.setDonationTokenAndOriginalPspReference(response.getDonationToken(), response.getPspReference());

return ResponseEntity.ok()
.body(response);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.adyen.giving.service;

import jakarta.servlet.http.HttpSession;
import jakarta.ws.rs.NotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DonationService {
@Autowired
protected HttpSession session;
Kwok-he-Chu marked this conversation as resolved.
Show resolved Hide resolved

private static final String DONATION_TOKEN = "DonationToken";

private static final String PAYMENT_ORIGINAL_PSPREFERENCE = "PaymentOriginalPspReference";

public void setDonationTokenAndOriginalPspReference(String donationToken, String originalPspReference) throws NullPointerException {
if (donationToken == null) {
throw new NullPointerException("No donationToken is found. The payments endpoint did not return a donationToken, please enable this in your Customer Area. See README.");
}

session.setAttribute(PAYMENT_ORIGINAL_PSPREFERENCE, originalPspReference);
session.setAttribute(DONATION_TOKEN, donationToken);
}

public String getDonationToken() throws NotFoundException {
var donationToken = session.getAttribute(DONATION_TOKEN);
if (donationToken == null) {
throw new NotFoundException("Could not find donationToken in the sessions");
}
return (String) donationToken;
}

public String getPaymentOriginalPspReference() throws NotFoundException {
var pspReference = session.getAttribute(PAYMENT_ORIGINAL_PSPREFERENCE);
if (pspReference == null) {
throw new NotFoundException("Could not find originalPspReference in the sessions");
}
return (String) pspReference;
}
}
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
adyenVersion="21.4.0"
adyenVersion="22.1.0"
springVersion="3.1.4"
springDependendyManagementVersion="1.1.3"

Expand Down
Loading