diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/SAMLAuthenticationBackend.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/SAMLAuthenticationBackend.java index 6f99c556..294c88a1 100644 --- a/src/main/java/eu/openanalytics/containerproxy/auth/impl/SAMLAuthenticationBackend.java +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/SAMLAuthenticationBackend.java @@ -43,8 +43,9 @@ public class SAMLAuthenticationBackend implements IAuthenticationBackend { public static final String NAME = "saml"; - private static final String PROP_LOGOUT_URL = "proxy.saml.logout-url"; - + private static final String PROP_SUCCESS_LOGOUT_URL = "proxy.saml.logout-url"; + private static final String PROP_SAML_LOGOUT_METHOD = "proxy.saml.logout-method"; + @Autowired(required = false) private SAMLEntryPoint samlEntryPoint; @@ -90,17 +91,29 @@ public void configureAuthenticationManagerBuilder(AuthenticationManagerBuilder a @Override public String getLogoutURL() { - if (environment.getProperty(PROP_LOGOUT_URL) != null) { + LogoutMethod logoutMethod = environment.getProperty(PROP_SAML_LOGOUT_METHOD, LogoutMethod.class, LogoutMethod.LOCAL); + if (logoutMethod == LogoutMethod.LOCAL) { return "/logout"; } - return "/saml/logout"; + return "/saml/logout"; // LogoutMethod.SAML } @Override public String getLogoutSuccessURL() { - String logoutURL = environment.getProperty(PROP_LOGOUT_URL); - System.out.println("LogoutURL: " + logoutURL); - if (logoutURL == null || logoutURL.trim().isEmpty()) logoutURL = "/"; + return determineLogoutSuccessURL(environment); + } + + public static String determineLogoutSuccessURL(Environment environment) { + String logoutURL = environment.getProperty(PROP_SUCCESS_LOGOUT_URL); + if (logoutURL == null || logoutURL.trim().isEmpty()) { + logoutURL = "/"; + } return logoutURL; } + + private enum LogoutMethod { + LOCAL, + SAML + } + } diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/saml/AuthenticationFailureHandler.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/saml/AuthenticationFailureHandler.java new file mode 100644 index 00000000..6d513f68 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/saml/AuthenticationFailureHandler.java @@ -0,0 +1,52 @@ +/** + * ContainerProxy + * + * Copyright (C) 2016-2020 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.saml; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.saml.SAMLStatusException; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { + + public void onAuthenticationFailure(HttpServletRequest request, + HttpServletResponse response, AuthenticationException exception) + throws IOException, ServletException { + + + if (exception.getCause() instanceof SAMLStatusException) { + SAMLStatusException samlException = (SAMLStatusException) exception.getCause(); + + if (samlException.getStatusCode().equals("urn:oasis:names:tc:SAML:2.0:status:RequestDenied")) { + response.sendRedirect(ServletUriComponentsBuilder.fromCurrentContextPath().path("/app-access-denied").build().toUriString()); + return; + } + } + + super.onAuthenticationFailure(request, response, exception); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/saml/SAMLConfiguration.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/saml/SAMLConfiguration.java index dd6701a7..2563992d 100644 --- a/src/main/java/eu/openanalytics/containerproxy/auth/impl/saml/SAMLConfiguration.java +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/saml/SAMLConfiguration.java @@ -31,6 +31,7 @@ import javax.inject.Inject; +import eu.openanalytics.containerproxy.auth.impl.SAMLAuthenticationBackend; import org.apache.commons.httpclient.HttpClient; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -157,7 +158,7 @@ public SecurityContextLogoutHandler securityContextLogoutHandler() { @Bean public SimpleUrlLogoutSuccessHandler successLogoutHandler() { SimpleUrlLogoutSuccessHandler successLogoutHandler = new SimpleUrlLogoutSuccessHandler(); - successLogoutHandler.setDefaultTargetUrl("/"); + successLogoutHandler.setDefaultTargetUrl(SAMLAuthenticationBackend.determineLogoutSuccessURL(environment)); return successLogoutHandler; } @@ -310,7 +311,7 @@ public SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler() { @Bean public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() { - SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler(); + AuthenticationFailureHandler failureHandler = new AuthenticationFailureHandler(); failureHandler.setUseForward(true); failureHandler.setDefaultFailureUrl("/error"); return failureHandler; diff --git a/src/main/java/eu/openanalytics/containerproxy/security/WebSecurityConfig.java b/src/main/java/eu/openanalytics/containerproxy/security/WebSecurityConfig.java index dab18181..3813db2b 100644 --- a/src/main/java/eu/openanalytics/containerproxy/security/WebSecurityConfig.java +++ b/src/main/java/eu/openanalytics/containerproxy/security/WebSecurityConfig.java @@ -20,13 +20,10 @@ */ package eu.openanalytics.containerproxy.security; -import java.util.List; - -import javax.inject.Inject; - +import eu.openanalytics.containerproxy.auth.IAuthenticationBackend; +import eu.openanalytics.containerproxy.auth.UserLogoutHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; @@ -43,8 +40,8 @@ import org.springframework.security.web.header.writers.StaticHeadersWriter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import eu.openanalytics.containerproxy.auth.IAuthenticationBackend; -import eu.openanalytics.containerproxy.auth.UserLogoutHandler; +import javax.inject.Inject; +import java.util.List; @Configuration @EnableWebSecurity @@ -61,7 +58,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Inject private Environment environment; - + @Autowired(required=false) private List customConfigs; @@ -128,8 +125,8 @@ protected void configure(HttpSecurity http) throws Exception { if (auth.hasAuthorization()) { http.authorizeRequests().antMatchers( - "/login", "/signin/**", "/auth-error", - "/favicon.ico", "/css/**", "/img/**", "/js/**", "/assets/**", "/webjars/**").permitAll(); + "/login", "/signin/**", "/auth-error", "/app-access-denied", "/logout-success", + "/favicon.ico", "/css/**", "/img/**", "/js/**", "/assets/**", "/webjars/**").permitAll(); http .formLogin() .loginPage("/login") diff --git a/src/main/java/eu/openanalytics/containerproxy/service/UserService.java b/src/main/java/eu/openanalytics/containerproxy/service/UserService.java index 537da53d..6d3d0f91 100644 --- a/src/main/java/eu/openanalytics/containerproxy/service/UserService.java +++ b/src/main/java/eu/openanalytics/containerproxy/service/UserService.java @@ -188,6 +188,7 @@ public void logout(Authentication auth) { eventService.post(EventType.Logout.toString(), userId, null); if (logoutStrategy != null) logoutStrategy.onLogout(userId); log.info(String.format("User logged out [user: %s]", userId)); + } } diff --git a/src/main/java/eu/openanalytics/containerproxy/ui/AuthErrorController.java b/src/main/java/eu/openanalytics/containerproxy/ui/AuthController.java similarity index 86% rename from src/main/java/eu/openanalytics/containerproxy/ui/AuthErrorController.java rename to src/main/java/eu/openanalytics/containerproxy/ui/AuthController.java index 3b59e981..10c34a1d 100644 --- a/src/main/java/eu/openanalytics/containerproxy/ui/AuthErrorController.java +++ b/src/main/java/eu/openanalytics/containerproxy/ui/AuthController.java @@ -32,7 +32,7 @@ import eu.openanalytics.containerproxy.api.BaseController; @Controller -public class AuthErrorController extends BaseController { +public class AuthController extends BaseController { @Inject private Environment environment; @@ -43,4 +43,9 @@ public String getAuthErrorPage(ModelMap map, HttpServletRequest request) { return "auth-error"; } + @RequestMapping(value = "/app-access-denied", method = RequestMethod.GET) + public String getAppAccessDeniedPage(ModelMap map, HttpServletRequest request) { + return "app-access-denied"; + } + } \ No newline at end of file diff --git a/src/main/java/eu/openanalytics/containerproxy/ui/LogoutSuccessController.java b/src/main/java/eu/openanalytics/containerproxy/ui/LogoutSuccessController.java new file mode 100644 index 00000000..d565fa56 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/ui/LogoutSuccessController.java @@ -0,0 +1,44 @@ +/** + * ContainerProxy + * + * Copyright (C) 2016-2020 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.ui; + +import eu.openanalytics.containerproxy.api.BaseController; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; + +@Controller +public class LogoutSuccessController extends BaseController { + + @Inject + private Environment environment; + + @RequestMapping(value = "/logout-success", method = RequestMethod.GET) + public String getAuthErrorPage() { + return "logout-success"; + } + +} \ No newline at end of file diff --git a/src/main/resources/templates/app-access-denied.html b/src/main/resources/templates/app-access-denied.html new file mode 100644 index 00000000..f9ed3ca9 --- /dev/null +++ b/src/main/resources/templates/app-access-denied.html @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + +
+

You do not have access to this application.

+

Your account does not have the required roles or groups required for accessing this application.

+

Please contact your administrator if you believe this is a mistake.

+
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/logout-success.html b/src/main/resources/templates/logout-success.html new file mode 100644 index 00000000..fe184faf --- /dev/null +++ b/src/main/resources/templates/logout-success.html @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + +
+

You have been logged out successfully.

+

Login again

+
+ + + + + + \ No newline at end of file