Skip to content

Commit

Permalink
Merge pull request #435 from Adyen/feature/AD-294
Browse files Browse the repository at this point in the history
AD-294 Implement Multiple Small Improvements in v12 Adyen Integration…
  • Loading branch information
kpieloch authored Sep 3, 2024
2 parents 1d65005 + d44c503 commit 85dbf71
Show file tree
Hide file tree
Showing 12 changed files with 379 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Hybris Extension
*
* Copyright (c) 2020 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/

package com.adyen.commerce.filters;

import com.adyen.commerce.utils.SameSiteCookieAttributeAppenderUtils;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
* This class uses code written by Igor Zarvanskyi and published on https://clutcher.github.io/post/hybris/same_site_login_issue/
*/
public class SameSiteCookiePostProcessFilter extends GenericFilterBean {

private SameSiteCookieAttributeAppenderUtils sameSiteCookieAttributeAppenderUtils;

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
getSameSiteCookieAttributeAppenderUtils().addSameSiteAttribute((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
filterChain.doFilter(servletRequest, servletResponse);
}

protected SameSiteCookieAttributeAppenderUtils getSameSiteCookieAttributeAppenderUtils() {
return sameSiteCookieAttributeAppenderUtils;
}

public void setSameSiteCookieAttributeAppenderUtils(SameSiteCookieAttributeAppenderUtils sameSiteCookieAttributeAppenderUtils) {
this.sameSiteCookieAttributeAppenderUtils = sameSiteCookieAttributeAppenderUtils;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Hybris Extension
*
* Copyright (c) 2020 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/

package com.adyen.commerce.interceptors;

import com.adyen.commerce.utils.SameSiteCookieAttributeAppenderUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/*
* This class uses code written by Igor Zarvanskyi and published on https://clutcher.github.io/post/hybris/same_site_login_issue/
*/
public class SameSiteCookieHandlerInterceptorAdapter extends HandlerInterceptorAdapter {

private SameSiteCookieAttributeAppenderUtils sameSiteCookieAttributeAppenderUtils;

@Override
public void postHandle(HttpServletRequest servletRequest, HttpServletResponse servletResponse, Object handler, ModelAndView modelAndView) {
getSameSiteCookieAttributeAppenderUtils().addSameSiteAttribute(servletRequest, servletResponse);
}

protected SameSiteCookieAttributeAppenderUtils getSameSiteCookieAttributeAppenderUtils() {
return sameSiteCookieAttributeAppenderUtils;
}

public void setSameSiteCookieAttributeAppenderUtils(SameSiteCookieAttributeAppenderUtils sameSiteCookieAttributeAppenderUtils) {
this.sameSiteCookieAttributeAppenderUtils = sameSiteCookieAttributeAppenderUtils;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Hybris Extension
*
* Copyright (c) 2020 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/

package com.adyen.commerce.security;

import com.adyen.commerce.utils.SameSiteCookieAttributeAppenderUtils;
import de.hybris.platform.acceleratorstorefrontcommons.security.GUIDCookieStrategy;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/*
* This class uses code written by Igor Zarvanskyi and published on https://clutcher.github.io/post/hybris/same_site_login_issue/
*/
public class AdyenGUIDAuthenticationSuccessHandler implements AuthenticationSuccessHandler
{
private GUIDCookieStrategy guidCookieStrategy;
private AuthenticationSuccessHandler authenticationSuccessHandler;
private SameSiteCookieAttributeAppenderUtils sameSiteCookieAttributeAppenderUtils;

@Override
public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response,
final Authentication authentication) throws IOException, ServletException
{
getGuidCookieStrategy().setCookie(request, response);

// onAuthenticationSuccess will commit response, so we won't be able to change it, that's why we should execute filter before it.
getSameSiteCookieAttributeAppenderUtils().addSameSiteAttribute(request, response);

getAuthenticationSuccessHandler().onAuthenticationSuccess(request, response, authentication);
}

protected GUIDCookieStrategy getGuidCookieStrategy()
{
return guidCookieStrategy;
}

/**
* @param guidCookieStrategy the guidCookieStrategy to set
*/
@Required
public void setGuidCookieStrategy(final GUIDCookieStrategy guidCookieStrategy)
{
this.guidCookieStrategy = guidCookieStrategy;
}

protected AuthenticationSuccessHandler getAuthenticationSuccessHandler()
{
return authenticationSuccessHandler;
}

/**
* @param authenticationSuccessHandler the authenticationSuccessHandler to set
*/
@Required
public void setAuthenticationSuccessHandler(final AuthenticationSuccessHandler authenticationSuccessHandler)
{
this.authenticationSuccessHandler = authenticationSuccessHandler;
}

protected SameSiteCookieAttributeAppenderUtils getSameSiteCookieAttributeAppenderUtils() {
return sameSiteCookieAttributeAppenderUtils;
}

public void setSameSiteCookieAttributeAppenderUtils(SameSiteCookieAttributeAppenderUtils sameSiteCookieAttributeAppenderUtils) {
this.sameSiteCookieAttributeAppenderUtils = sameSiteCookieAttributeAppenderUtils;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Hybris Extension
*
* Copyright (c) 2020 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*/

package com.adyen.commerce.utils;

import com.google.common.net.HttpHeaders;
import de.hybris.platform.servicelayer.config.ConfigurationService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.configuration.Configuration;
import org.apache.log4j.Logger;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
* This class uses code written by Igor Zarvanskyi and published on https://clutcher.github.io/post/hybris/same_site_login_issue/
*/
public class SameSiteCookieAttributeAppenderUtils {

private static final Logger LOG = Logger.getLogger(SameSiteCookieAttributeAppenderUtils.class);

private ConfigurationService configurationService;

private static final String PLATFORM_VERSION_PROPERTY = "build.version.api";
private static final String SAMESITE_COOKIE_HANDLER_ENABLED_PROPERTY = "adyen.samesitecookie.handler.enabled";
private static final int SAP_VERSION_WITH_SAMESITE_FIX = 2005;
private static final List<String> COOKIES_WITH_FORCE_SAME_SITE_NONE = Arrays.asList("JSESSIONID", "acceleratorSecureGUID", "yacceleratorstorefrontRememberMe");
private static final Pattern CHROME_VERSION = Pattern.compile("Chrom[^ \\/]+\\/(\\d+)[\\.\\d]*");

public void addSameSiteAttribute(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
// Do not modify cookies for SAP versions which already have SameSite cookies handler available
if(isPlatformVersionWithSameSiteFix()) {
return;
}

if (isSameSiteCookieHandlingEnabled() && isNotCommittedResponse(servletResponse)) {
Collection<String> headers = servletResponse.getHeaders(HttpHeaders.SET_COOKIE);
if (CollectionUtils.isNotEmpty(headers)) {
String userAgent = servletRequest.getHeader(HttpHeaders.USER_AGENT);
for (String sameSiteCookie : COOKIES_WITH_FORCE_SAME_SITE_NONE) {
addSameSiteNone(sameSiteCookie, servletResponse, userAgent);
}
}
}
}

private void addSameSiteNone(String sameSiteCookie, HttpServletResponse servletResponse, String userAgent) {
Collection<String> headers = servletResponse.getHeaders(HttpHeaders.SET_COOKIE);

// Check if exists session set cookie header
Optional<String> sessionCookieWithoutSameSite = headers.stream()
.filter(cookie -> cookie.startsWith(sameSiteCookie) && !cookie.contains("SameSite"))
.findAny();

if (sessionCookieWithoutSameSite.isPresent() && shouldSendSameSiteNone(userAgent)) {
// Replace all set cookie headers with 1 new session + sameSite header
servletResponse.setHeader(HttpHeaders.SET_COOKIE, sessionCookieWithoutSameSite.get() + ";Secure ;SameSite=None");

// Re-add all other set cookie headers
headers.stream()
.filter(cookie -> !cookie.startsWith(sameSiteCookie))
.forEach(cookie -> servletResponse.addHeader(HttpHeaders.SET_COOKIE, cookie));
}
}

private boolean isNotCommittedResponse(ServletResponse servletResponse) {
return !servletResponse.isCommitted();
}

private boolean isSameSiteCookieHandlingEnabled() {
Configuration configuration = getConfigurationService().getConfiguration();
boolean isSameSiteCookieHandlingEnabled = false;
if (configuration.containsKey(SAMESITE_COOKIE_HANDLER_ENABLED_PROPERTY)) {
isSameSiteCookieHandlingEnabled = configuration.getBoolean(SAMESITE_COOKIE_HANDLER_ENABLED_PROPERTY);
}
return isSameSiteCookieHandlingEnabled;
}

private boolean isPlatformVersionWithSameSiteFix() {
try {
String platformVersion = getConfigurationService().getConfiguration().getString(PLATFORM_VERSION_PROPERTY);
if(platformVersion != null) {
String[] platformVersionSplit = platformVersion.split("\\.");
//compare major version
int majorVersion = Integer.parseInt(platformVersionSplit[0]);
return majorVersion >= SAP_VERSION_WITH_SAMESITE_FIX;
}
} catch (Exception e) {
LOG.debug(e);
}

LOG.debug("Could not parse platform version, SameSite cookie handling will be skipped");
return true;
}

public static boolean shouldSendSameSiteNone(String useragent) {
return isChromiumBased(useragent) && isChromiumVersionAtLeast(80, useragent);
}

private static boolean isChromiumBased(String useragent) {
return useragent.contains("Chrome") || useragent.contains("Chromium");
}

private static boolean isChromiumVersionAtLeast(int major, String useragent) {
Matcher matcher = CHROME_VERSION.matcher(useragent);
if (matcher.find()) {
try {
String chromeVersion = matcher.group(1);
return Integer.parseInt(chromeVersion) >= major;
} catch (Exception e) {
LOG.debug(e);
}
}

LOG.debug("Could not parse Chrome browser version, SameSite cookie handling will be skipped");
return false;
}

public ConfigurationService getConfigurationService() {
return configurationService;
}

public void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,4 @@
</bean>


<!-- To support getCheckoutCart for non credit cards (CreditCardPaymentInfoModel) -->
<alias name="adyenCheckoutFlowFacade" alias="checkoutFlowFacade"/>
<bean id="adyenCheckoutFlowFacade" class="com.adyen.v6.acceleratorfacades.flow.impl.AdyenCheckoutFlowFacade" parent="defaultCheckoutFlowFacade" />

</beans>
5 changes: 5 additions & 0 deletions adyenv6core/external-dependencies.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,10 @@
<artifactId>json</artifactId>
<version>20220924</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.3</version>
</dependency>
</dependencies>
</project>
4 changes: 4 additions & 0 deletions adyenv6core/resources/adyenv6core-spring.xml
Original file line number Diff line number Diff line change
Expand Up @@ -432,4 +432,8 @@
<bean id="defaultAdyenMerchantStrategy" class="com.adyen.v6.strategy.impl.DefaultAdyenMerchantAccountStrategy">
<property name="baseStoreService" ref="baseStoreService"/>
</bean>

<!-- To support getCheckoutCart for non credit cards (CreditCardPaymentInfoModel) -->
<alias name="adyenCheckoutFlowFacade" alias="checkoutFlowFacade"/>
<bean id="adyenCheckoutFlowFacade" class="com.adyen.v6.acceleratorfacades.flow.impl.AdyenCheckoutFlowFacade" parent="defaultCheckoutFlowFacade" />
</beans>
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ public AdyenPaymentServiceFactory(final AdyenRequestFactory adyenRequestFactory,
}

public AdyenCheckoutApiService createAdyenCheckoutApiService(final BaseStoreModel baseStoreModel) {
String webMerchantAccount = adyenMerchantAccountStrategy.getWebMerchantAccount();
String webMerchantAccount = adyenMerchantAccountStrategy.getWebMerchantAccount(baseStoreModel);
DefaultAdyenCheckoutApiService defaultAdyenCheckoutApiService = new DefaultAdyenCheckoutApiService(baseStoreModel, webMerchantAccount);
defaultAdyenCheckoutApiService.setAdyenRequestFactory(adyenRequestFactory);
return defaultAdyenCheckoutApiService;
}

public AdyenModificationsApiService createAdyenModificationsApiService(final BaseStoreModel baseStoreModel) {
String webMerchantAccount = adyenMerchantAccountStrategy.getWebMerchantAccount();
String webMerchantAccount = adyenMerchantAccountStrategy.getWebMerchantAccount(baseStoreModel);
DefaultAdyenModificationsApiService adyenModificationsApiService = new DefaultAdyenModificationsApiService(baseStoreModel, webMerchantAccount);
adyenModificationsApiService.setAdyenRequestFactory(adyenRequestFactory);
return adyenModificationsApiService;
Expand Down
Loading

0 comments on commit 85dbf71

Please sign in to comment.