From 17859442bafc8cb8196fc702af77475b0600d5d5 Mon Sep 17 00:00:00 2001
From: Joze RIHTARSIC <Joze.RIHTARSIC@ext.ec.europa.eu>
Date: Wed, 15 Sep 2021 09:05:14 +0200
Subject: [PATCH] Set spring security programmatically and add session cookie
 parameters

---
 smp-parent-pom/pom.xml                        |   4 +-
 .../smp/data/ui/enums/SMPPropertyEnum.java    |   8 +-
 .../smp/services/ConfigurationService.java    |  14 ++
 .../ServiceMetadataIntegrationTest.java       |   7 +-
 smp-webapp/pom.xml                            |   2 +-
 .../smp/auth/SMPAuthenticationProvider.java   |   2 +
 .../smp/config/SMPTaskSchedulerConfig.java    |  28 ++++
 .../edelivery/smp/config/SmpWebAppConfig.java |   3 +
 .../smp/config/SpringSecurityConfig.java      | 127 +++++++++++++++++-
 .../error/SpringSecurityExceptionHandler.java |   9 +-
 .../smp/ui/AuthenticationResource.java        |  36 ++++-
 .../ec/edelivery/smp/ui/SMPCookieWriter.java  |  80 +++++++++++
 .../SecurityConfigurationClientCertTest.java  |   5 +-
 .../security/SecurityConfigurationTest.java   |  16 ++-
 .../security/SignatureValidatorTest.java      |   6 +-
 .../ServiceGroupControllerTest.java           |   2 +-
 16 files changed, 317 insertions(+), 32 deletions(-)
 create mode 100644 smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SMPTaskSchedulerConfig.java
 create mode 100644 smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SMPCookieWriter.java

diff --git a/smp-parent-pom/pom.xml b/smp-parent-pom/pom.xml
index 84dbbc316..0124d36ea 100644
--- a/smp-parent-pom/pom.xml
+++ b/smp-parent-pom/pom.xml
@@ -50,8 +50,8 @@
 
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <slf4j.version>1.7.26</slf4j.version>
-        <spring.version>5.1.9.RELEASE</spring.version>
-        <spring.security.version>5.1.6.RELEASE</spring.security.version>
+        <spring.version>5.3.9</spring.version>
+        <spring.security.version>5.5.2</spring.security.version>
         <spring.boot.version>2.1.8.RELEASE</spring.boot.version>
         <!-- bdmsl.client.version>3.0.0</bdmsl.client.version -->
         <bdmsl.api.version>4.0.0</bdmsl.api.version>
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/SMPPropertyEnum.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/SMPPropertyEnum.java
index e827e0dd8..a99e7e32f 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/SMPPropertyEnum.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/enums/SMPPropertyEnum.java
@@ -56,7 +56,13 @@ public enum SMPPropertyEnum {
     SML_PROXY_PORT("bdmsl.integration.proxy.port","","Deprecated", false, false , SMPPropertyTypeEnum.INTEGER),
     SML_PROXY_USER("bdmsl.integration.proxy.user","","Deprecated", false, false , SMPPropertyTypeEnum.STRING),
     SML_PROXY_PASSWORD("bdmsl.integration.proxy.password","","Deprecated", false, false , SMPPropertyTypeEnum.STRING),
-    SMP_PROPERTY_REFRESH_CRON("smp.property.refresh.cronJobExpression","0 48 */1 * * *","Property refresh cron expression (def 12 minutes to each hour). Property change is refreshed at restart!", false, false , SMPPropertyTypeEnum.STRING);
+    SMP_PROPERTY_REFRESH_CRON("smp.property.refresh.cronJobExpression","0 48 */1 * * *","Property refresh cron expression (def 12 minutes to each hour). Property change is refreshed at restart!", false, false , SMPPropertyTypeEnum.STRING),
+
+    UI_COOKIE_SESSION_SECURE("smp.ui.session.secure","false","Cookie is only sent to the server when a request is made with the https: scheme (except on localhost), and therefore is more resistent to man-in-the-middle attacks.", false, false , SMPPropertyTypeEnum.BOOLEAN),
+    UI_COOKIE_SESSION_MAX_AGE("smp.ui.session.max-age","","Number of seconds until the cookie expires. A zero or negative number will expire the cookie immediately. Empty value will not set parameter", false, false , SMPPropertyTypeEnum.INTEGER),
+    UI_COOKIE_SESSION_SITE("smp.ui.session.strict","None","Controls whether a cookie is sent with cross-origin requests, providing some protection against cross-site request forgery attacks. Possible values are: Strict, None, Lax", false, false , SMPPropertyTypeEnum.STRING),
+    UI_COOKIE_SESSION_PATH("smp.ui.session.path","","A path that must exist in the requested URL, or the browser won't send the Cookie header.  Null/Empty value sets the authentication requests context by default.  The forward slash (/) character is interpreted as a directory separator, and subdirectories will be matched as well: for Path=/docs, /docs, /docs/Web/, and /docs/Web/HTTP will all match", false, false , SMPPropertyTypeEnum.STRING),
+    ;
 
 
     String property;
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java
index 970c4f31c..b526bb674 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ConfigurationService.java
@@ -170,4 +170,18 @@ public class ConfigurationService {
     }
 
 
+    public boolean getSessionCookieSecure() {
+        Boolean value = (Boolean) configurationDAO.getCachedPropertyValue(UI_COOKIE_SESSION_SECURE);
+        return value != null && value;
+    }
+    public Integer getSessionCookieMaxAge() {
+        return (Integer) configurationDAO.getCachedPropertyValue(UI_COOKIE_SESSION_MAX_AGE);
+    }
+    public String getSessionCookieSameSite() {
+        return (String) configurationDAO.getCachedPropertyValue(UI_COOKIE_SESSION_SITE);
+    }
+    public String getSessionCookiePath() {
+        return (String) configurationDAO.getCachedPropertyValue(UI_COOKIE_SESSION_PATH);
+    }
+
 }
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataIntegrationTest.java
index 576857da9..ae2fffc25 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataIntegrationTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataIntegrationTest.java
@@ -50,8 +50,7 @@ import static eu.europa.ec.edelivery.smp.conversion.ServiceMetadataConverter.unm
 import static eu.europa.ec.edelivery.smp.testutil.TestConstants.*;
 import static eu.europa.ec.edelivery.smp.testutil.XmlTestUtils.loadDocumentAsByteArray;
 import static eu.europa.ec.edelivery.smp.testutil.XmlTestUtils.marshallToByteArray;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 /**
  * Created by gutowpa on 15/11/2017.
@@ -114,8 +113,6 @@ public class ServiceMetadataIntegrationTest extends AbstractServiceIntegrationTe
 
     @Test
     public void saveAndReadPositiveScenario() throws IOException, TransformerException, JAXBException {
-
-
         //given
         byte[]  inServiceMetadataXml = loadDocumentAsByteArray(SERVICE_METADATA_XML_PATH);
         byte[] expectedSignedServiceMetadataXml = loadDocumentAsByteArray(SIGNED_SERVICE_METADATA_XML_PATH);
@@ -131,7 +128,7 @@ public class ServiceMetadataIntegrationTest extends AbstractServiceIntegrationTe
         assertEquals(1, docIdsAfter.size());
         assertEquals(DOC_ID.getValue().toLowerCase(), docIdsAfter.get(0).getValue()); // normalized
         assertEquals(DOC_ID.getScheme().toLowerCase(), docIdsAfter.get(0).getScheme()); // normalized
-        assertTrue(Arrays.equals(expectedSignedServiceMetadataXml, ServiceMetadataConverter.toByteArray(outServiceMetadataDoc) ));
+        assertArrayEquals(expectedSignedServiceMetadataXml, ServiceMetadataConverter.toByteArray(outServiceMetadataDoc));
     }
 
     @Test
diff --git a/smp-webapp/pom.xml b/smp-webapp/pom.xml
index 377f0e545..a2681a7d8 100644
--- a/smp-webapp/pom.xml
+++ b/smp-webapp/pom.xml
@@ -15,7 +15,7 @@
     <properties>
         <maven.deploy.skip>false</maven.deploy.skip>
         <buildtimestamp>${maven.build.timestamp}</buildtimestamp>
-        <maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
+        <maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss'Z'</maven.build.timestamp.format>
 
         <ftp.host>wltdgt02.cc.cec.eu.int</ftp.host>
         <ftp.port>2059</ftp.port>
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java
index db303baa7..6ee66b53a 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/auth/SMPAuthenticationProvider.java
@@ -20,6 +20,7 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.crypto.bcrypt.BCrypt;
 import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
+import org.springframework.stereotype.Component;
 
 import java.security.cert.CertificateRevokedException;
 import java.text.DateFormat;
@@ -33,6 +34,7 @@ import static java.util.Locale.US;
 
 
 @Import({SmpAppConfig.class})
+@Component
 public class SMPAuthenticationProvider implements AuthenticationProvider {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(AuthenticationProvider.class);
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SMPTaskSchedulerConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SMPTaskSchedulerConfig.java
new file mode 100644
index 000000000..27102a76c
--- /dev/null
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SMPTaskSchedulerConfig.java
@@ -0,0 +1,28 @@
+package eu.europa.ec.edelivery.smp.config;
+
+
+import eu.europa.ec.edelivery.smp.data.dao.ConfigurationDao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+@Configuration
+@EnableScheduling
+@ComponentScan(
+        basePackages = "eu.europa.ec.edelivery.smp")
+public class SMPTaskSchedulerConfig {
+
+    ConfigurationDao configurationDao;
+
+    @Autowired
+    public SMPTaskSchedulerConfig(ConfigurationDao configurationDao) {
+        this.configurationDao = configurationDao;
+    }
+
+    @Scheduled(cron = "${smp.property.refresh.cronJobExpression:0 48 */1 * * *}")
+    public void refreshProperties() {
+        configurationDao.refreshProperties();
+    }
+}
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
index f9d350666..f6e6887ff 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
@@ -14,6 +14,8 @@
 package eu.europa.ec.edelivery.smp.config;
 
 import eu.europa.ec.edelivery.smp.error.ErrorMappingControllerAdvice;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
@@ -38,6 +40,7 @@ import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
         "eu.europa.ec.edelivery.smp.ui"})
 @Import({GlobalMethodSecurityConfig.class, ErrorMappingControllerAdvice.class})
 public class SmpWebAppConfig implements WebMvcConfigurer {
+    private static final Logger LOG = LoggerFactory.getLogger(SmpWebAppConfig.class);
 
     @Override
     public void addResourceHandlers(ResourceHandlerRegistry registry) {
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SpringSecurityConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SpringSecurityConfig.java
index 8a964e03c..569bf7e2a 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SpringSecurityConfig.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SpringSecurityConfig.java
@@ -15,23 +15,142 @@ package eu.europa.ec.edelivery.smp.config;
 
 import eu.europa.ec.edelivery.security.BlueCoatAuthenticationFilter;
 import eu.europa.ec.edelivery.security.EDeliveryX509AuthenticationFilter;
+import eu.europa.ec.edelivery.smp.auth.SMPAuthenticationProvider;
+import eu.europa.ec.edelivery.smp.auth.SMPAuthority;
+import eu.europa.ec.edelivery.smp.error.SpringSecurityExceptionHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.ImportResource;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.BeanIds;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.firewall.DefaultHttpFirewall;
+import org.springframework.security.web.firewall.HttpFirewall;
 
 /**
  * Created by gutowpa on 12/07/2017.
  */
 
 @EnableWebSecurity
-@ImportResource("classpath:spring-security.xml")
+@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
+//@ImportResource("classpath:spring-security.xml")
 @ComponentScan("eu.europa.ec.edelivery.smp.auth")
-public class SpringSecurityConfig {
+public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
+    private static final Logger LOG = LoggerFactory.getLogger(SpringSecurityConfig.class);
 
+    SMPAuthenticationProvider smpAuthenticationProvider;
+    BlueCoatAuthenticationFilter blueCoatAuthenticationFilter;
+    EDeliveryX509AuthenticationFilter x509AuthenticationFilter;
 
+    @Value("${authentication.blueCoat.enabled:false}")
+    boolean clientCertEnabled;
+    @Value("${encodedSlashesAllowedInUrl:true}")
+    boolean encodedSlashesAllowedInUrl;
+
+    /**
+     * Initialize beans. Use lazy initialization for filter to avoid circular dependencies
+     *
+     * @param smpAuthenticationProvider
+     * @param blueCoatAuthenticationFilter
+     * @param x509AuthenticationFilter
+     */
+    @Autowired
+    public SpringSecurityConfig(SMPAuthenticationProvider smpAuthenticationProvider,
+                                @Lazy BlueCoatAuthenticationFilter blueCoatAuthenticationFilter,
+                                @Lazy EDeliveryX509AuthenticationFilter x509AuthenticationFilter) {
+        super(false);
+        this.smpAuthenticationProvider = smpAuthenticationProvider;
+        this.blueCoatAuthenticationFilter = blueCoatAuthenticationFilter;
+        this.x509AuthenticationFilter = x509AuthenticationFilter;
+    }
+
+    @Override
+    protected void configure(HttpSecurity httpSecurity) throws Exception {
+
+        // prepare filters
+        blueCoatAuthenticationFilter.setBlueCoatEnabled(clientCertEnabled);
+
+        httpSecurity.csrf().disable()
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS).and()
+                .exceptionHandling().authenticationEntryPoint(new SpringSecurityExceptionHandler()).and()
+                .headers().frameOptions().deny().contentTypeOptions().and().xssProtection().xssProtectionEnabled(true).and().and()
+
+                .addFilter(blueCoatAuthenticationFilter)
+                .addFilter(x509AuthenticationFilter)
+                .httpBasic()
+                .and() // username
+                .anonymous().authorities(SMPAuthority.S_AUTHORITY_ANONYMOUS.getAuthority()).and()
+                .authorizeRequests().antMatchers(HttpMethod.DELETE, "/ui/rest/security/authentication").permitAll()
+                .antMatchers(HttpMethod.POST, "/ui/rest/security/authentication").permitAll()
+                .and()
+                .authorizeRequests()
+                .antMatchers(HttpMethod.DELETE).hasAnyAuthority(
+                SMPAuthority.S_AUTHORITY_SMP_ADMIN.getAuthority(),
+                SMPAuthority.S_AUTHORITY_SERVICE_GROUP.getAuthority(),
+                SMPAuthority.S_AUTHORITY_SYSTEM_ADMIN.getAuthority())
+                .antMatchers(HttpMethod.PUT).hasAnyAuthority(
+                SMPAuthority.S_AUTHORITY_SMP_ADMIN.getAuthority(),
+                SMPAuthority.S_AUTHORITY_SERVICE_GROUP.getAuthority(),
+                SMPAuthority.S_AUTHORITY_SYSTEM_ADMIN.getAuthority())
+                .antMatchers(HttpMethod.GET).permitAll().and()
+                .authorizeRequests().antMatchers(HttpMethod.GET, "/ui/").hasAnyAuthority(
+                SMPAuthority.S_AUTHORITY_SMP_ADMIN.getAuthority(),
+                SMPAuthority.S_AUTHORITY_SERVICE_GROUP.getAuthority(),
+                SMPAuthority.S_AUTHORITY_SYSTEM_ADMIN.getAuthority()).and()
+        ;
+
+
+    }
+
+    @Override
+    public void configure(WebSecurity web) throws Exception {
+        super.configure(web);
+        web.httpFirewall(smpHttpFirewall());
+    }
+
+
+    @Bean
+    public HttpFirewall smpHttpFirewall() {
+        DefaultHttpFirewall firewall = new DefaultHttpFirewall();
+        firewall.setAllowUrlEncodedSlash(encodedSlashesAllowedInUrl);
+        return firewall;
+    }
+
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) {
+        LOG.info("configureAuthenticationManagerBuilder, set SMP provider ");
+        auth.authenticationProvider(smpAuthenticationProvider);
+    }
+
+    @Override
+    @Bean(name = {BeanIds.AUTHENTICATION_MANAGER, "smpAuthenticationManager"})
+    public AuthenticationManager authenticationManagerBean() throws Exception {
+        return super.authenticationManagerBean();
+    }
+
+    @Bean
+    public BlueCoatAuthenticationFilter getClientCertAuthenticationFilter(@Qualifier("smpAuthenticationManager") AuthenticationManager authenticationManager) {
+        BlueCoatAuthenticationFilter blueCoatAuthenticationFilter = new BlueCoatAuthenticationFilter();
+        blueCoatAuthenticationFilter.setAuthenticationManager(authenticationManager);
+        return blueCoatAuthenticationFilter;
+    }
+
+    @Bean
+    public EDeliveryX509AuthenticationFilter getEDeliveryX509AuthenticationFilter(@Qualifier("smpAuthenticationManager") AuthenticationManager authenticationManager) {
+        EDeliveryX509AuthenticationFilter x509AuthenticationFilter = new EDeliveryX509AuthenticationFilter();
+        x509AuthenticationFilter.setAuthenticationManager(authenticationManager);
+        return x509AuthenticationFilter;
+    }
 }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/SpringSecurityExceptionHandler.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/SpringSecurityExceptionHandler.java
index 7d8418e8c..fb3fb8c41 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/SpringSecurityExceptionHandler.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/error/SpringSecurityExceptionHandler.java
@@ -24,7 +24,6 @@ import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.access.AccessDeniedHandler;
 import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
 
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.xml.bind.JAXBContext;
@@ -51,20 +50,20 @@ public class SpringSecurityExceptionHandler extends BasicAuthenticationEntryPoin
 
     @Override
     public void commence(HttpServletRequest request, HttpServletResponse response,
-                         AuthenticationException authException) throws IOException, ServletException {
+                         AuthenticationException authException) throws IOException {
         String errorMsg = authException.getMessage();
-        if(authException instanceof BadCredentialsException){
+        if (authException instanceof BadCredentialsException) {
             errorMsg += " - Provided username/password or client certificate are invalid";
         }
         handle(response, authException, errorMsg);
     }
 
     @Override
-    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
+    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
         handle(response, accessDeniedException, accessDeniedException.getMessage());
     }
 
-    private void handle(HttpServletResponse response, RuntimeException exception, String errorMsg) throws IOException, ServletException {
+    private void handle(HttpServletResponse response, RuntimeException exception, String errorMsg) throws IOException {
         ResponseEntity respEntity = buildAndWarn(exception, errorMsg);
         String errorBody = marshall((ErrorResponse) respEntity.getBody());
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResource.java
index 2ae1ded9b..aaf581ed2 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/AuthenticationResource.java
@@ -10,6 +10,7 @@ import eu.europa.ec.edelivery.smp.data.ui.LoginRO;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.edelivery.smp.services.ConfigurationService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.convert.ConversionService;
 import org.springframework.http.HttpStatus;
@@ -34,6 +35,9 @@ import javax.servlet.http.HttpServletResponse;
 @RequestMapping(value = "/ui/rest/security")
 public class AuthenticationResource {
 
+    public static final String CSRF_COOKIE_NAME = "XSRF-TOKEN";
+    public static final String SESSION_COOKIE_NAME = "JSESSIONID";
+
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(AuthenticationResource.class);
 
     @Autowired
@@ -45,6 +49,12 @@ public class AuthenticationResource {
     @Autowired
     private ConversionService conversionService;
 
+    @Autowired
+    private ConfigurationService configurationService;
+
+    SMPCookieWriter smpCookieWriter = new SMPCookieWriter();
+
+
     @ResponseStatus(value = HttpStatus.FORBIDDEN)
     @ExceptionHandler({AuthenticationException.class})
     public ErrorRO handleException(Exception ex) {
@@ -54,8 +64,12 @@ public class AuthenticationResource {
 
     @RequestMapping(value = "authentication", method = RequestMethod.POST)
     @Transactional(noRollbackFor = BadCredentialsException.class)
-    public UserRO authenticate(@RequestBody LoginRO loginRO, HttpServletResponse response) {
+    public UserRO authenticate(@RequestBody LoginRO loginRO, HttpServletRequest request, HttpServletResponse response) {
         LOG.debug("Authenticating user [{}]", loginRO.getUsername());
+        // reset session id with login
+
+        recreatedSessionCookie(request, response);
+
         SMPAuthenticationToken authentication = (SMPAuthenticationToken) authenticationService.authenticate(loginRO.getUsername(), loginRO.getPassword());
         UserRO userRO = conversionService.convert(authentication.getUser(), UserRO.class);
         return authorizationService.sanitize(userRO);
@@ -70,7 +84,7 @@ public class AuthenticationResource {
         }
 
         LOG.info("Logging out user [{}]", auth.getName());
-        new CookieClearingLogoutHandler("JSESSIONID", "XSRF-TOKEN").logout(request, response, null);
+        new CookieClearingLogoutHandler(SESSION_COOKIE_NAME, CSRF_COOKIE_NAME).logout(request, response, null);
         LOG.info("Cleared cookies");
         new SecurityContextLogoutHandler().logout(request, response, auth);
         LOG.info("Logged out");
@@ -88,4 +102,22 @@ public class AuthenticationResource {
         return user;
     }
 
+    /**
+     * set cookie parameters https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
+     *
+     * @param request
+     * @param response
+     */
+    public void recreatedSessionCookie(HttpServletRequest request, HttpServletResponse response) {
+        String sessionId = request.changeSessionId();
+        smpCookieWriter.writeCookieToResponse(SESSION_COOKIE_NAME,
+                sessionId,
+                configurationService.getSessionCookieSecure(), configurationService.getSessionCookieMaxAge(),
+                configurationService.getSessionCookiePath(),
+                configurationService.getSessionCookieSameSite(),
+                null,
+                request, response
+        );
+    }
+
 }
\ No newline at end of file
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SMPCookieWriter.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SMPCookieWriter.java
new file mode 100644
index 000000000..42eb976ef
--- /dev/null
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SMPCookieWriter.java
@@ -0,0 +1,80 @@
+package eu.europa.ec.edelivery.smp.ui;
+
+import eu.europa.ec.edelivery.smp.logging.SMPLogger;
+import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.edelivery.smp.services.ConfigurationService;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.HttpHeaders;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class SMPCookieWriter {
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(SMPCookieWriter.class);
+    private static final String COOKIE_PARAM_DELIMITER = "; ";
+    private static final String COOKIE_PARAM_SECURE = "secure";
+    private static final String COOKIE_PARAM_MAX_AGE = "Max-Age";
+    private static final String COOKIE_PARAM_EXPIRES = "Expires";
+
+    private static final String COOKIE_PARAM_PATH = "Path";
+    private static final String COOKIE_PARAM_HTTP_ONLY = "HttpOnly";
+    private static final String COOKIE_PARAM_SAME_SITE = "SameSite";
+
+    /**
+     * set cookie parameters https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
+     */
+    public void writeCookieToResponse(String cookieName, String cookieValue, boolean isSecure, Integer maxAge, String path, String sameSite, String domain, HttpServletRequest request, HttpServletResponse response) {
+
+
+        StringBuilder sb = new StringBuilder();
+        sb.append(cookieName)
+                .append('=')
+                .append(cookieValue);
+        // set secure\
+        if (isSecure) {
+            sb.append(COOKIE_PARAM_DELIMITER)
+                    .append(COOKIE_PARAM_SECURE);
+        }
+
+        sb.append(COOKIE_PARAM_DELIMITER)
+                .append(COOKIE_PARAM_HTTP_ONLY);
+
+        if (maxAge != null && maxAge > -1) {
+            sb.append(COOKIE_PARAM_DELIMITER)
+                    .append(COOKIE_PARAM_MAX_AGE)
+                    .append('=')
+                    .append(maxAge.intValue());
+
+            ZonedDateTime expires = (maxAge != 0) ? ZonedDateTime.now().plusSeconds(maxAge)
+                    : Instant.EPOCH.atZone(ZoneOffset.UTC);
+            sb.append(COOKIE_PARAM_DELIMITER).append(COOKIE_PARAM_EXPIRES)
+                    .append('=').append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME));
+        }
+
+
+        if (StringUtils.isBlank(path)) {
+            path = request.getContextPath();
+            path = StringUtils.isNotBlank(path)
+                    ? path  : "/";
+        }
+        if (StringUtils.isNotBlank(path)) {
+            sb.append(COOKIE_PARAM_DELIMITER)
+                    .append(COOKIE_PARAM_PATH)
+                    .append('=')
+                    .append(path);
+        }
+        if (StringUtils.isNotBlank(sameSite)) {
+            sb.append(COOKIE_PARAM_DELIMITER)
+                    .append(COOKIE_PARAM_SAME_SITE)
+                    .append('=')
+                    .append(sameSite);
+        }
+
+        LOG.info("Set cookie [{}]",sb.toString());
+        response.setHeader(HttpHeaders.SET_COOKIE, sb.toString());
+    }
+}
diff --git a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationClientCertTest.java b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationClientCertTest.java
index 9bc1d1ce5..ce8450803 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationClientCertTest.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationClientCertTest.java
@@ -52,7 +52,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
         SmpWebAppConfig.class,
         DatabaseConfig.class,
         SpringSecurityConfig.class,
-        SpringSecurityTestConfig.class,
+        SpringSecurityTestConfig.class
 })
 @WebAppConfiguration
 @Sql(scripts = {"classpath:/cleanup-database.sql",
@@ -123,7 +123,6 @@ public class SecurityConfigurationClientCertTest {
                 },
 
 
-
                 {
                         "Issue test one",
                         "CN=ncp.fi.ehealth.testa.eu,O=Kansanelakelaitos,C=FI:f71ee8b11cb3b787",
@@ -177,7 +176,7 @@ public class SecurityConfigurationClientCertTest {
 
     @Test
     public void validBlueCoatHeaderAuthorizedForPutTest() throws Exception {
-        System.out.println("Test: "+ testName);
+        System.out.println("Test: " + testName);
         String clientCert = buildClientCert(serialNumber, certificateDn);
         System.out.println("Client-Cert: " + clientCert);
 
diff --git a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationTest.java b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationTest.java
index df9a1b9af..27877ddfd 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationTest.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SecurityConfigurationTest.java
@@ -63,14 +63,11 @@ public class SecurityConfigurationTest {
     public static final String BLUE_COAT_VALID_HEADER_DB_UPPER_SN = "sno=BB66&subject=CN=common name UPPER database SN,O=org,C=BE&validfrom=Dec 6 17:41:42 2016 GMT&validto=Jul 9 23:59:00 2050 GMT&issuer=C=x,O=y,CN=z";
     public static final String TEST_USERNAME_BLUE_COAT__DB_UPPER_SN = "CN=common name UPPER database SN,O=org,C=BE:000000000000bb66";
 
+    public static final String BLUE_COAT_NOT_AUTHORIZED_HEADER = "sno=bb61&subject=C=BE,O=org,CN=common name not exists&validfrom=Dec 6 17:41:42 2016 GMT&validto=Jul 9 23:59:00 2050 GMT&issuer=C=x,O=y,CN=z";
+
     @Autowired
     private WebApplicationContext context;
 
-    /*
-    @PersistenceContext
-    private EntityManager em;
-    */
-
     MockMvc mvc;
 
     @Before
@@ -151,6 +148,15 @@ public class SecurityConfigurationTest {
                 .andExpect(content().string(TEST_USERNAME_BLUE_COAT))
                 .andReturn().getResponse().getContentAsString();
     }
+    @Test
+    public void blueCoatHeaderNotAuthorizedForPutTest() throws Exception {
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("Client-Cert", BLUE_COAT_NOT_AUTHORIZED_HEADER);
+
+        mvc.perform(MockMvcRequestBuilders.put(RETURN_LOGGED_USER_PATH)
+                .headers(headers))
+                .andExpect(status().isUnauthorized());
+    }
 
     @Test
     public void validBlueCoatHeaderAuthorizedBeforeValidBasicAuthTest() throws Exception {
diff --git a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SignatureValidatorTest.java b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SignatureValidatorTest.java
index 7523b93aa..5400c747f 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SignatureValidatorTest.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/cipa/smp/server/security/SignatureValidatorTest.java
@@ -125,7 +125,7 @@ public class SignatureValidatorTest {
     }
 
     @Test
-    public void validateLinarizedSignature() throws Throwable {
+    public void validateLinearizedSignature() throws Throwable {
         String serviceGroupId = "ehealth-actorid-qns::urn:brazil:ncpb";
         Principal principal = new PreAuthenticatedCertificatePrincipal("C=BE, O=European Commission,OU=CEF_eDelivery.europa.eu,OU=eHealth,OU=SMP_TEST,CN=EHEALTH_SMP_EC", "C=DE, O=T-Systems International GmbH, OU=T-Systems Trust Center, ST=Nordrhein Westfalen/postalCode=57250, L=Netphen/street=Untere Industriestr. 20, CN=Shared Business CA 4", "f7:1e:e8:b1:1c:b3:b7:87");
         String filePathToLoad = "/input/ServiceMetadata_linarized.xml";
@@ -181,8 +181,8 @@ public class SignatureValidatorTest {
         //Default signature validation
         Element smpSigPointer = SignatureUtil.findSignatureByParentNode(response.getDocumentElement());
         SignatureUtil.validateSignature(smpSigPointer);
-        Assert.assertEquals(signedByCustomizedSignature, SignatureUtil.loadDocumentAsString(signedByCustomizedSignatureFilePath));
-        Assert.assertEquals(SignatureUtil.marshall(response), SignatureUtil.loadDocumentAsString(defaultSignatureFilePath));
+        Assert.assertEquals(SignatureUtil.loadDocumentAsString(signedByCustomizedSignatureFilePath), signedByCustomizedSignature);
+        Assert.assertEquals(SignatureUtil.loadDocumentAsString(defaultSignatureFilePath), SignatureUtil.marshall(response) );
     }
 
     public static Document parse(String serviceMetadataXml) throws SAXException, IOException, ParserConfigurationException {
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerTest.java
index eabf3ba08..3585e368a 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerTest.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupControllerTest.java
@@ -203,7 +203,7 @@ public class ServiceGroupControllerTest {
     }
 
     @Test
-    public void getExistingServiceMetadatWithReverseNoProxyHost() throws Exception {
+    public void getExistingServiceMetadataWithReverseNoProxyHost() throws Exception {
         //given
         prepareForGet();
 
-- 
GitLab