From 651f34aa6f674681fe32358e7b82bb55f0a548b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20LELEU?= <jerome.leleu@teamdlab.com>
Date: Fri, 27 Mar 2020 10:41:39 +0100
Subject: [PATCH] login/pwd + authn delegation works (with or without service)

---
 .../fr/gouv/vitamui/cas/config/AppConfig.java |  8 +++-
 .../vitamui/cas/config/WebflowConfig.java     |  2 +-
 .../java/fr/gouv/vitamui/cas/util/Utils.java  | 23 ++++++------
 ...omDelegatedClientAuthenticationAction.java | 37 +++++++++++--------
 .../cas/webflow/actions/DispatcherAction.java | 14 +------
 .../webflow/actions/SelectRedirectAction.java |  8 ++--
 ...urrogateRestAuthenticationServiceTest.java |  2 +-
 .../UserAuthenticationHandlerTest.java        |  2 +-
 .../UserPrincipalResolverTest.java            |  2 +-
 .../IamRestPasswordManagementServiceTest.java |  2 +-
 .../cas/provider/ProvidersServiceTest.java    |  2 +-
 .../actions/BaseWebflowActionTest.java        |  2 +
 .../webflow/actions/DispatcherActionTest.java |  2 +-
 13 files changed, 54 insertions(+), 52 deletions(-)

diff --git a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/config/AppConfig.java b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/config/AppConfig.java
index da2a71cf..f20fec94 100644
--- a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/config/AppConfig.java
+++ b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/config/AppConfig.java
@@ -162,6 +162,12 @@ public class AppConfig extends BaseTicketCatalogConfigurer {
     @Value("${ip.header}")
     private String ipHeaderName;
 
+    @Value("${vitamui.cas.tenant.identifier}")
+    private Integer casTenantIdentifier;
+
+    @Value("${vitamui.cas.identity}")
+    private String casIdentity;
+
     @Bean
     public UserAuthenticationHandler userAuthenticationHandler() {
         return new UserAuthenticationHandler(servicesManager, principalFactory, casRestClient(), utils(), ipHeaderName);
@@ -234,7 +240,7 @@ public class AppConfig extends BaseTicketCatalogConfigurer {
 
     @Bean
     public Utils utils() {
-        return new Utils(casRestClient(), tokenApiCas);
+        return new Utils(casRestClient(), tokenApiCas, casTenantIdentifier, casIdentity);
     }
 
     @Bean
diff --git a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/config/WebflowConfig.java b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/config/WebflowConfig.java
index 83a249ec..65a538a0 100644
--- a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/config/WebflowConfig.java
+++ b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/config/WebflowConfig.java
@@ -207,7 +207,7 @@ public class WebflowConfig {
 
     @Bean
     public SelectRedirectAction selectRedirectAction() {
-        return new SelectRedirectAction();
+        return new SelectRedirectAction(centralAuthenticationService.getObject());
     }
 
     @Bean
diff --git a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/util/Utils.java b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/util/Utils.java
index ca84f9ef..02551461 100644
--- a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/util/Utils.java
+++ b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/util/Utils.java
@@ -44,7 +44,9 @@ import java.util.Optional;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletResponse;
 
+import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang.StringUtils;
+import org.apereo.cas.CasProtocolConstants;
 import org.apereo.cas.authentication.Authentication;
 import org.apereo.cas.authentication.principal.Principal;
 import org.apereo.cas.authentication.surrogate.SurrogateAuthenticationService;
@@ -54,7 +56,6 @@ import org.apereo.cas.web.support.WebUtils;
 import org.pac4j.core.util.CommonHelper;
 import org.pac4j.core.context.Pac4jConstants;
 import org.pac4j.saml.client.SAML2Client;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.webflow.context.ExternalContext;
 import org.springframework.webflow.execution.Action;
 import org.springframework.webflow.execution.Event;
@@ -67,11 +68,14 @@ import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
 import fr.gouv.vitamui.commons.rest.client.ExternalHttpContext;
 import fr.gouv.vitamui.iam.external.client.CasExternalRestClient;
 
+import lombok.val;
+
 /**
  * Helper class.
  *
  *
  */
+@RequiredArgsConstructor
 public class Utils {
 
     private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(Utils.class);
@@ -82,16 +86,9 @@ public class Utils {
 
     private final String casToken;
 
-    @Value("${vitamui.cas.tenant.identifier}")
-    private Integer casTenantIdentifier;
-
-    @Value("${vitamui.cas.identity}")
-    private String casIdentity;
+    private final Integer casTenantIdentifier;
 
-    public Utils(final CasExternalRestClient casExternalRestClient, final String casToken) {
-        this.casExternalRestClient = casExternalRestClient;
-        this.casToken = casToken;
-    }
+    private final String casIdentity;
 
     public ExternalHttpContext buildContext(final String username) {
         return new ExternalHttpContext(casTenantIdentifier, casToken, "cas+" + username, casIdentity);
@@ -99,8 +96,12 @@ public class Utils {
 
     public Event performClientRedirection(final Action action, final SAML2Client client, final RequestContext requestContext) throws IOException {
         final HttpServletResponse response = WebUtils.getHttpServletResponseFromExternalWebflowContext(requestContext);
+        val service = WebUtils.getService(requestContext);
 
-        final String url = CommonHelper.addParameter("clientredirect", Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER, client.getName());
+        String url = CommonHelper.addParameter("clientredirect", Pac4jConstants.DEFAULT_CLIENT_NAME_PARAMETER, client.getName());
+        if (service != null) {
+            url = CommonHelper.addParameter(url, CasProtocolConstants.PARAMETER_SERVICE, service.getOriginalUrl());
+        }
         response.sendRedirect(url);
 
         final ExternalContext externalContext = requestContext.getExternalContext();
diff --git a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/CustomDelegatedClientAuthenticationAction.java b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/CustomDelegatedClientAuthenticationAction.java
index da43deda..c90475a1 100644
--- a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/CustomDelegatedClientAuthenticationAction.java
+++ b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/CustomDelegatedClientAuthenticationAction.java
@@ -81,7 +81,8 @@ import java.util.Optional;
 /**
  * Custom authentication delegation:
  * - automatic delegation given the provided IdP
- * - extraction of the username/surrogate passed as a request parameter.
+ * - extraction of the username/surrogate passed as a request parameter
+ * - save the portalUrl in the webflow.
  *
  *
  */
@@ -139,12 +140,14 @@ public class CustomDelegatedClientAuthenticationAction extends DelegatedClientAu
     @Override
     public Event doExecute(final RequestContext context) {
 
+        // save a label in the webflow
+        final MutableAttributeMap<Object> flowScope = context.getFlowScope();
+        flowScope.put(Constants.PORTAL_URL, vitamuiPortalUrl);
+
         final Event event = super.doExecute(context);
         if ("error".equals(event.getId())) {
 
-            final MutableAttributeMap<Object> flowScope = context.getFlowScope();
-            flowScope.put(Constants.PORTAL_URL, vitamuiPortalUrl);
-
+            // extract and parse the request username if provided
             String username = context.getRequestParameters().get(Constants.USERNAME);
             if (username != null) {
 
@@ -163,23 +166,25 @@ public class CustomDelegatedClientAuthenticationAction extends DelegatedClientAu
                 }
             }
 
+            // get the idp if it exists
+            final HttpServletRequest request = WebUtils.getHttpServletRequestFromExternalWebflowContext(context);
+            final String idp = getIdpValue(request);
+            LOGGER.debug("Provided idp: {}", idp);
+            if (StringUtils.isNotBlank(idp)) {
 
-            TicketGrantingTicket tgt = null;
-            final String tgtId = WebUtils.getTicketGrantingTicketId(context);
-            if (tgtId != null) {
-                tgt = ticketRegistry.getTicket(tgtId, TicketGrantingTicket.class);
-            }
+                TicketGrantingTicket tgt = null;
+                final String tgtId = WebUtils.getTicketGrantingTicketId(context);
+                if (tgtId != null) {
+                    tgt = ticketRegistry.getTicket(tgtId, TicketGrantingTicket.class);
+                }
 
-            if (tgt == null || tgt.isExpired()) {
-                final HttpServletRequest request = WebUtils.getHttpServletRequestFromExternalWebflowContext(context);
-                final HttpServletResponse response = WebUtils.getHttpServletResponseFromExternalWebflowContext(context);
+                // if no authentication
+                if (tgt == null || tgt.isExpired()) {
 
-                // get the idp and redirect if it exists
-                final String idp = getIdpValue(request);
-                LOGGER.debug("Provided idp: {}", idp);
-                if (StringUtils.isNotBlank(idp)) {
+                    // if it matches an existing IdP, save it and redirect
                     final Optional<IdentityProviderDto> optProvider = identityProviderHelper.findByTechnicalName(providersService.getProviders(), idp);
                     if (optProvider.isPresent()) {
+                        final HttpServletResponse response = WebUtils.getHttpServletResponseFromExternalWebflowContext(context);
                         response.addCookie(utils.buildIdpCookie(idp, casProperties.getTgc()));
                         final SAML2Client client = ((SamlIdentityProviderDto) optProvider.get()).getSaml2Client();
                         LOGGER.debug("Force redirect to the SAML IdP: {}", client.getName());
diff --git a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/DispatcherAction.java b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/DispatcherAction.java
index e7bb07be..fcbc2150 100644
--- a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/DispatcherAction.java
+++ b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/DispatcherAction.java
@@ -48,6 +48,7 @@ import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
 import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
 import fr.gouv.vitamui.iam.common.utils.IdentityProviderHelper;
 import fr.gouv.vitamui.iam.external.client.CasExternalRestClient;
+import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang.StringUtils;
 import org.apereo.cas.authentication.credential.UsernamePasswordCredential;
 import org.apereo.cas.web.support.WebUtils;
@@ -68,6 +69,7 @@ import java.util.Optional;
  *
  *
  */
+@RequiredArgsConstructor
 public class DispatcherAction extends AbstractAction {
 
     public static final String DISABLED = "disabled";
@@ -85,18 +87,6 @@ public class DispatcherAction extends AbstractAction {
 
     private final Utils utils;
 
-    public DispatcherAction(final ProvidersService providersService,
-                            final IdentityProviderHelper identityProviderHelper,
-                            final CasExternalRestClient casExternalRestClient,
-                            final String surrogationSeparator,
-                            final Utils utils) {
-        this.providersService = providersService;
-        this.identityProviderHelper = identityProviderHelper;
-        this.casExternalRestClient = casExternalRestClient;
-        this.surrogationSeparator = surrogationSeparator;
-        this.utils = utils;
-    }
-
     @Override
     protected Event doExecute(final RequestContext requestContext) throws IOException {
 
diff --git a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/SelectRedirectAction.java b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/SelectRedirectAction.java
index c080f62f..3564f0c2 100644
--- a/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/SelectRedirectAction.java
+++ b/cas/cas-server/src/main/java/fr/gouv/vitamui/cas/webflow/actions/SelectRedirectAction.java
@@ -39,11 +39,10 @@ package fr.gouv.vitamui.cas.webflow.actions;
 import fr.gouv.vitamui.cas.webflow.CustomLoginWebflowConfigurer;
 import fr.gouv.vitamui.commons.api.logger.VitamUILogger;
 import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory;
+import lombok.RequiredArgsConstructor;
 import org.apereo.cas.CentralAuthenticationService;
 import org.apereo.cas.ticket.ServiceTicket;
 import org.apereo.cas.web.support.WebUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.webflow.action.AbstractAction;
 import org.springframework.webflow.execution.Event;
 import org.springframework.webflow.execution.RequestContext;
@@ -53,13 +52,12 @@ import org.springframework.webflow.execution.RequestContext;
  *
  *
  */
+@RequiredArgsConstructor
 public class SelectRedirectAction extends AbstractAction {
 
     private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(SelectRedirectAction.class);
 
-    @Autowired
-    @Qualifier("centralAuthenticationService")
-    private CentralAuthenticationService centralAuthenticationService;
+    private final CentralAuthenticationService centralAuthenticationService;
 
     @Override
     protected Event doExecute(final RequestContext requestContext) {
diff --git a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/IamSurrogateRestAuthenticationServiceTest.java b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/IamSurrogateRestAuthenticationServiceTest.java
index 97b0ca50..d3e227c8 100644
--- a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/IamSurrogateRestAuthenticationServiceTest.java
+++ b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/IamSurrogateRestAuthenticationServiceTest.java
@@ -42,7 +42,7 @@ public final class IamSurrogateRestAuthenticationServiceTest {
     public void setUp() {
         casExternalRestClient = mock(CasExternalRestClient.class);
 
-        final Utils utils = new Utils(casExternalRestClient, null);
+        final Utils utils = new Utils(casExternalRestClient, null, 0, null);
         service = new IamSurrogateRestAuthenticationService(casExternalRestClient, mock(ServicesManager.class), utils);
     }
 
diff --git a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/UserAuthenticationHandlerTest.java b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/UserAuthenticationHandlerTest.java
index bd685858..853db4ea 100644
--- a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/UserAuthenticationHandlerTest.java
+++ b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/UserAuthenticationHandlerTest.java
@@ -61,7 +61,7 @@ public final class UserAuthenticationHandlerTest {
     @Before
     public void setUp() {
         casExternalRestClient = mock(CasExternalRestClient.class);
-        final Utils utils = new Utils(casExternalRestClient, null);
+        final Utils utils = new Utils(casExternalRestClient, null, 0, null);
         handler = new UserAuthenticationHandler(null, new DefaultPrincipalFactory(), casExternalRestClient, utils, null);
         credential = new UsernamePasswordCredential(USERNAME, PASSWORD);
     }
diff --git a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/UserPrincipalResolverTest.java b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/UserPrincipalResolverTest.java
index b130c464..7267736e 100644
--- a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/UserPrincipalResolverTest.java
+++ b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/authentication/UserPrincipalResolverTest.java
@@ -57,7 +57,7 @@ public final class UserPrincipalResolverTest {
     @Before
     public void setUp() {
         casExternalRestClient = mock(CasExternalRestClient.class);
-        final Utils utils = new Utils(casExternalRestClient, null);
+        final Utils utils = new Utils(casExternalRestClient, null, 0, null);
         resolver = new UserPrincipalResolver(false, new DefaultPrincipalFactory(), casExternalRestClient, utils);
         final RequestContext context = mock(RequestContext.class);
         RequestContextHolder.setRequestContext(context);
diff --git a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/pm/IamRestPasswordManagementServiceTest.java b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/pm/IamRestPasswordManagementServiceTest.java
index a6dc3e04..8e73e8ea 100644
--- a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/pm/IamRestPasswordManagementServiceTest.java
+++ b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/pm/IamRestPasswordManagementServiceTest.java
@@ -76,7 +76,7 @@ public final class IamRestPasswordManagementServiceTest {
         identityProviderDto.setInternal(true);
         when(identityProviderHelper.findByUserIdentifier(any(List.class), eq(EMAIL))).thenReturn(Optional.of(identityProviderDto));
         service = new IamRestPasswordManagementService(casExternalRestClient, null, providersService, identityProviderHelper);
-        final Utils utils = new Utils(casExternalRestClient, null);
+        final Utils utils = new Utils(casExternalRestClient, null, 0, null);
         service.setUtils(utils);
         final RequestContext context = mock(RequestContext.class);
         RequestContextHolder.setRequestContext(context);
diff --git a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/provider/ProvidersServiceTest.java b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/provider/ProvidersServiceTest.java
index b5c1c5c4..c57b6467 100644
--- a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/provider/ProvidersServiceTest.java
+++ b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/provider/ProvidersServiceTest.java
@@ -57,7 +57,7 @@ public final class ProvidersServiceTest {
         restClient = mock(IdentityProviderExternalRestClient.class);
         service.setIdentityProviderExternalRestClient(restClient);
         final CasExternalRestClient casExternalRestClient = mock(CasExternalRestClient.class);
-        final Utils utils = new Utils(casExternalRestClient, null);
+        final Utils utils = new Utils(casExternalRestClient, null, 0, null);
         service.setUtils(utils);
 
         provider = new IdentityProviderDto();
diff --git a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/webflow/actions/BaseWebflowActionTest.java b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/webflow/actions/BaseWebflowActionTest.java
index 109049e4..ae75f1e3 100644
--- a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/webflow/actions/BaseWebflowActionTest.java
+++ b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/webflow/actions/BaseWebflowActionTest.java
@@ -1,6 +1,7 @@
 package fr.gouv.vitamui.cas.webflow.actions;
 
 import fr.gouv.vitamui.commons.api.identity.ServerIdentityAutoConfiguration;
+import org.apereo.cas.authentication.principal.WebApplicationService;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 import org.springframework.test.context.ContextConfiguration;
@@ -56,6 +57,7 @@ public abstract class BaseWebflowActionTest {
 
         flowParameters = new LocalAttributeMap<>();
         when(context.getFlowScope()).thenReturn(flowParameters);
+        flowParameters.put("service", mock(WebApplicationService.class));
 
         val flow = mock(Flow.class);
         when(flow.getVariable("credential")).thenReturn(mock(FlowVariable.class));
diff --git a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/webflow/actions/DispatcherActionTest.java b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/webflow/actions/DispatcherActionTest.java
index b03f19bf..c6e8dbbe 100644
--- a/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/webflow/actions/DispatcherActionTest.java
+++ b/cas/cas-server/src/test/java/fr/gouv/vitamui/cas/webflow/actions/DispatcherActionTest.java
@@ -64,7 +64,7 @@ public final class DispatcherActionTest extends BaseWebflowActionTest {
         identityProviderHelper = mock(IdentityProviderHelper.class);
         casExternalRestClient = mock(CasExternalRestClient.class);
 
-        final Utils utils = new Utils(casExternalRestClient, null);
+        final Utils utils = new Utils(casExternalRestClient, null, 0, null);
         action = new DispatcherAction(providersService, identityProviderHelper, casExternalRestClient, ",", utils);
 
         final SAML2Client client = new SAML2Client();
-- 
GitLab