diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/pom.xml b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/pom.xml index 67515beab..f2d5a9e0c 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/pom.xml +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/pom.xml @@ -36,6 +36,52 @@ ../../ + + + + + + com.github.buckelieg + minify-maven-plugin + + + default-cli + + UTF-8 + + ${basedir}/src/main/resources + ${project.build.directory}/classes + + / + / + saml.js + + + license.txt + + + + **/*.js + + CLOSURE + + + + OFF + OFF + + + + + minify + + + + + + + + diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java index ace19d55e..f026916d4 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -24,9 +24,11 @@ import com.google.inject.Provider; import com.google.inject.Singleton; import java.net.URI; import java.util.Arrays; +import javax.ws.rs.core.UriBuilder; import org.apache.guacamole.auth.saml.user.SAMLAuthenticatedUser; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.saml.acs.AssertedIdentity; +import org.apache.guacamole.auth.saml.conf.ConfigurationService; import org.apache.guacamole.auth.saml.acs.SAMLAuthenticationSessionManager; import org.apache.guacamole.auth.saml.acs.SAMLService; import org.apache.guacamole.auth.sso.SSOAuthenticationProviderService; @@ -68,6 +70,12 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS @Inject private SAMLService saml; + /** + * Service for retrieving SAML configuration information. + */ + @Inject + private ConfigurationService confService; + /** * Return the value of the session identifier associated with the given * credentials, or null if no session identifier is found in the @@ -117,9 +125,25 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS return saml.createRequest(); } + @Override + public URI getLogoutURI(String idToken) throws GuacamoleException { + + // If no logout endpoint is configured, return null + URI logoutEndpoint = confService.getLogoutEndpoint(); + if (logoutEndpoint == null) + return null; + + // Build the logout URI with post-logout redirect + UriBuilder logoutUriBuilder = UriBuilder.fromUri(logoutEndpoint); + logoutUriBuilder.queryParam("RelayState", + confService.getPostLogoutRedirectURI()); + + return logoutUriBuilder.build(); + } + @Override public void shutdown() { sessionManager.shutdown(); } - + } diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java index 47ead8820..da10043ee 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java @@ -190,6 +190,30 @@ public class ConfigurationService { }; + /** + * The logout endpoint (URI) of the SAML IdP. When configured, users will + * be redirected to this endpoint when they log out of Guacamole. + */ + private static final URIGuacamoleProperty SAML_LOGOUT_ENDPOINT = + new URIGuacamoleProperty() { + + @Override + public String getName() { return "saml-logout-endpoint"; } + + }; + + /** + * The URI to redirect to after logout is complete. Defaults to the + * callback URL if not specified. + */ + private static final URIGuacamoleProperty SAML_POST_LOGOUT_REDIRECT_URI = + new URIGuacamoleProperty() { + + @Override + public String getName() { return "saml-post-logout-redirect-uri"; } + + }; + /** * The Guacamole server environment. */ @@ -390,6 +414,37 @@ public class ConfigurationService { return environment.getProperty(SAML_PRIVATE_KEY_PATH); } + /** + * Returns the logout endpoint (URI) of the SAML IdP. If not configured, + * null will be returned and logout will only end the Guacamole session. + * + * @return + * The logout endpoint of the SAML IdP, or null if not configured. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public URI getLogoutEndpoint() throws GuacamoleException { + return environment.getProperty(SAML_LOGOUT_ENDPOINT); + } + + /** + * Returns the URI to redirect to after logout is complete. If not + * configured, the callback URL will be used. + * + * @return + * The post-logout redirect URI. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public URI getPostLogoutRedirectURI() throws GuacamoleException { + URI postLogoutUri = environment.getProperty(SAML_POST_LOGOUT_REDIRECT_URI); + if (postLogoutUri != null) + return postLogoutUri; + return getCallbackUrl(); + } + /** * Returns the contents of a small file, such as a private key or certificate into * a String. If the file does not exist, or cannot be read for any reason, an exception diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resource-templates/guac-manifest.json b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resource-templates/guac-manifest.json index f19c11593..64db565cb 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resource-templates/guac-manifest.json +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resource-templates/guac-manifest.json @@ -17,6 +17,10 @@ "styles/sso-providers.css" ], + "js" : [ + "saml.min.js" + ], + "html" : [ "html/sso-providers.html", "html/sso-provider-saml.html" diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resources/samlModule.js b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resources/samlModule.js new file mode 100644 index 000000000..b3ee9869e --- /dev/null +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resources/samlModule.js @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * The module for code implementing SSO using SAML. + */ +angular.module('guacSsoSaml', []); + +/** + * Redirect to the SSO logout endpoint when the user logs out, allowing + * Single Logout to occur if configured. + */ +angular.module('guacSsoSaml').run(['$rootScope', '$window', + function guacSsoSamlLogout($rootScope, $window) { + + // Redirect to SSO logout endpoint when user logs out + $rootScope.$on('guacLogout', function handleLogout() { + $window.location.href = 'api/ext/saml/logout'; + }); + +}]); + +// Ensure the guacSsoSaml module is loaded along with the rest of the app +angular.module('index').requires.push('guacSsoSaml');