diff --git a/docker-test/src/main/resources/share/share-config-custom.xml b/docker-test/src/main/resources/share/share-config-custom.xml index 7662bba..b37e2fb 100644 --- a/docker-test/src/main/resources/share/share-config-custom.xml +++ b/docker-test/src/main/resources/share/share-config-custom.xml @@ -33,6 +33,15 @@ de.acosix.alfresco.keycloak.share.remote.AccessTokenAwareAlfrescoAuthenticator + + alfresco-noauth + Alfresco - unauthenticated access + Access to Alfresco Repository WebScripts that do not require authentication + alfresco + http://repository:8080/alfresco/s + none + + alfresco Alfresco - user access @@ -71,7 +80,7 @@ true true - false + true true @@ -88,4 +97,61 @@ + + + + false + 1000 + 7000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://repository:8080/alfresco + + false + + application/vnd.openxmlformats-officedocument.wordprocessingml.document + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + application/vnd.ms-powerpoint + + + + false + + \ No newline at end of file diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java index caf6b73..ae0481a 100644 --- a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java +++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java @@ -179,6 +179,9 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I private static final String PAGE_TYPE_PARAMETER_NAME = "pt"; + // used on some login page redirects - see PageView ALF_REDIRECT_URL constant + private static final String ALF_REDIRECT_URL = "alfRedirectUrl"; + private static final String LOGIN_PATH_INFORMATION = "/dologin"; private static final String LOGOUT_PATH_INFORMATION = "/dologout"; @@ -527,13 +530,20 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I this.keycloakDeployment = KeycloakDeploymentBuilder.build(adapterConfiguration); // we need to recreate the HttpClient to configure the forced route URL - this.keycloakDeployment.setClient(new Callable() { + this.keycloakDeployment.setClient(new Callable() + { + private HttpClient client; + @Override - public HttpClient call() throws Exception { - if (this.client == null) { - synchronized (this) { - if (this.client == null) { + public HttpClient call() throws Exception + { + if (this.client == null) + { + synchronized (this) + { + if (this.client == null) + { this.client = new HttpClientBuilder() .routePlanner(KeycloakAuthenticationFilter.this.createForcedRoutePlanner(adapterConfiguration)) .build(adapterConfiguration); @@ -845,11 +855,7 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I return cookie; }).forEach(res::addCookie); - final List redirects = captureFacade.getHeaders().get("Location"); - if (redirects != null && !redirects.isEmpty()) - { - LOGIN_REDIRECT_URL.set(redirects.get(0)); - } + setRedirectFromCaptureFacade(req, captureFacade); } /** @@ -881,6 +887,14 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I { // no query parameters, so no code= and no error= // this will cause login redirect challenge to be generated + + // but use the alfRedirectUrl if present in request + final String alfRedirectUrl = req.getParameter(ALF_REDIRECT_URL); + if (alfRedirectUrl != null && !alfRedirectUrl.isBlank()) + { + LOGGER.debug("Found {} query parameter with value {}", ALF_REDIRECT_URL, alfRedirectUrl); + return ALF_REDIRECT_URL + "=" + alfRedirectUrl; + } return ""; } @@ -915,10 +929,17 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I return cookie; }).forEach(res::addCookie); + setRedirectFromCaptureFacade(req, captureFacade); + } + + private static void setRedirectFromCaptureFacade(final HttpServletRequest req, + final ResponseHeaderCookieCaptureServletHttpFacade captureFacade) + { final List redirects = captureFacade.getHeaders().get("Location"); if (redirects != null && !redirects.isEmpty()) { - LOGIN_REDIRECT_URL.set(redirects.get(0)); + final String redirectPath = redirects.get(0); + LOGIN_REDIRECT_URL.set(redirectPath); } } @@ -961,9 +982,19 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I this.handleAlfrescoResourceAccessToken(session); } + final String alfRedirectUrl = req.getParameter(ALF_REDIRECT_URL); + if (facade.isEnded()) { LOGGER.debug("Authenticator already handled response"); + + if (alfRedirectUrl != null && !alfRedirectUrl.isBlank()) + { + LOGGER.debug("Found {} query parameter - redirecting to {}", ALF_REDIRECT_URL, alfRedirectUrl); + // this may override any redirect set by the authenticator + res.sendRedirect(alfRedirectUrl); + } + return; } @@ -1022,9 +1053,19 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I session.setAttribute(UserFactory.SESSION_ATTRIBUTE_EXTERNAL_AUTH, Boolean.TRUE); session.setAttribute(UserFactory.SESSION_ATTRIBUTE_KEY_USER_ID, userId); + final String alfRedirectUrl = req.getParameter(ALF_REDIRECT_URL); + if (facade.isEnded()) { LOGGER.debug("Authenticator already handled response"); + + if (alfRedirectUrl != null && !alfRedirectUrl.isBlank()) + { + LOGGER.debug("Found {} query parameter - redirecting to {}", ALF_REDIRECT_URL, alfRedirectUrl); + // this may override any redirect set by the authenticator + res.sendRedirect(alfRedirectUrl); + } + return; } @@ -1042,8 +1083,6 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I } } - this.completeRequestContext(req); - LOGGER.debug("Continueing with filter chain processing"); this.continueFilterChain(context, req, res, chain); } @@ -1773,11 +1812,9 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I final List
headers = new LinkedList<>(); - ClientCredentialsProviderUtils.setClientCredentials( - this.keycloakDeployment.getAdapterConfig(), - this.keycloakDeployment.getClientAuthenticator(), - new NameValueMapAdapter<>(headers, BasicHeader.class), - new NameValueMapAdapter<>(formParams, BasicNameValuePair.class)); + ClientCredentialsProviderUtils.setClientCredentials(this.keycloakDeployment.getAdapterConfig(), + this.keycloakDeployment.getClientAuthenticator(), new NameValueMapAdapter<>(headers, BasicHeader.class), + new NameValueMapAdapter<>(formParams, BasicNameValuePair.class)); for (final Header header : headers) { @@ -1900,41 +1937,54 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I params.setParameter(ConnRoutePNames.FORCED_ROUTE, route); } - protected HttpRoute createRoute(final ExtendedAdapterConfig adapterConfig, final HttpHost routeHost) throws UnknownHostException, MalformedURLException { + protected HttpRoute createRoute(final ExtendedAdapterConfig adapterConfig, final HttpHost routeHost) + throws UnknownHostException, MalformedURLException + { final boolean secure = "https".equalsIgnoreCase(routeHost.getSchemeName()); - if (adapterConfig.getProxyUrl() != null) { + if (adapterConfig.getProxyUrl() != null) + { // useful in parsing the URL for just what is needed for HttpHost final URL proxyUrl = new URL(adapterConfig.getProxyUrl()); final HttpHost proxyHost = new HttpHost(proxyUrl.getHost(), proxyUrl.getPort(), proxyUrl.getProtocol()); return new HttpRoute(routeHost, InetAddress.getLocalHost(), proxyHost, secure); - } else { + } + else + { return new HttpRoute(routeHost, InetAddress.getLocalHost(), secure); } } - protected HttpRoute createForcedRoute(final ExtendedAdapterConfig adapterConfig) throws UnknownHostException, MalformedURLException { + protected HttpRoute createForcedRoute(final ExtendedAdapterConfig adapterConfig) throws UnknownHostException, MalformedURLException + { // useful in parsing the URL for just what is needed for HttpHost final URL forcedRouteUrl = new URL(adapterConfig.getForcedRouteUrl()); final HttpHost forcedRouteHost = new HttpHost(forcedRouteUrl.getHost(), forcedRouteUrl.getPort(), forcedRouteUrl.getProtocol()); return this.createRoute(adapterConfig, forcedRouteHost); } - protected HttpRoutePlanner createForcedRoutePlanner(final ExtendedAdapterConfig adapterConfig) throws MalformedURLException { + protected HttpRoutePlanner createForcedRoutePlanner(final ExtendedAdapterConfig adapterConfig) throws MalformedURLException + { final URL authServerUrl = new URL(adapterConfig.getAuthServerUrl()); final HttpHost authServerHost = new HttpHost(authServerUrl.getHost(), authServerUrl.getPort(), authServerUrl.getProtocol()); return (target, request, context) -> { - try { - if (authServerHost.equals(target)) { + try + { + if (authServerHost.equals(target)) + { LOGGER.trace("Rerouting to forced route"); final HttpRoute route = KeycloakAuthenticationFilter.this.createForcedRoute(adapterConfig); LOGGER.trace("Rerouting to forced route: {}", route); return route; - } else { + } + else + { return KeycloakAuthenticationFilter.this.createRoute(adapterConfig, target); } - } catch (final IOException ie) { + } + catch (final IOException ie) + { throw new HttpException(ie.getMessage(), ie); } }; diff --git a/share/src/main/site-webscripts/de/acosix/keycloak/customisations/components/guest/login.get.js b/share/src/main/site-webscripts/de/acosix/keycloak/customisations/components/guest/login.get.js index c76b637..fdc6cd6 100644 --- a/share/src/main/site-webscripts/de/acosix/keycloak/customisations/components/guest/login.get.js +++ b/share/src/main/site-webscripts/de/acosix/keycloak/customisations/components/guest/login.get.js @@ -44,7 +44,17 @@ function main() parameterModel.value = decodeURIComponent(parameter.substring(parameter.indexOf('=') + 1)); if (parameterModel.value.indexOf('?') !== -1) { - parameterModel.value = parameterModel.value.substring(0, parameterModel.value.indexOf('?')); + if (parameterModel.value.indexOf('?alfRedirectUrl=') !== -1) + { + if (parameterModel.value.indexOf('&') !== -1) + { + parameterModel.value = parameterModel.value.substring(0, parameterModel.value.indexOf('&')); + } + } + else + { + parameterModel.value = parameterModel.value.substring(0, parameterModel.value.indexOf('?')); + } } } else