diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/.ratignore b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/.ratignore
index e69de29bb..da318d12f 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/.ratignore
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/.ratignore
@@ -0,0 +1 @@
+src/main/resources/html/*.html
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/pom.xml b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/pom.xml
index b23280596..11724ecf4 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/pom.xml
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/pom.xml
@@ -50,6 +50,12 @@
guice
+
+
+ javax.ws.rs
+ jsr311-api
+
+
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOAuthenticationProvider.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOAuthenticationProvider.java
index 1a389283f..c5b07fabc 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOAuthenticationProvider.java
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOAuthenticationProvider.java
@@ -24,6 +24,7 @@ import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
+import com.google.inject.binder.LinkedBindingBuilder;
import java.util.Arrays;
import java.util.Collections;
import org.apache.guacamole.GuacamoleException;
@@ -64,14 +65,20 @@ public abstract class SSOAuthenticationProvider extends AbstractAuthenticationPr
* The SSOAuthenticationProviderService implementation that should be
* used for core authentication functions.
*
+ * @param ssoResource
+ * The SSOResource that should be used to manually redirect the user to
+ * the IdP, as well as to provide any implementation-specific REST
+ * endpoints.
+ *
* @param modules
* Any additional modules that should be used when creating the Guice
* injector.
*/
public SSOAuthenticationProvider(
Class extends SSOAuthenticationProviderService> authService,
+ Class extends SSOResource> ssoResource,
Module... modules) {
- this(authService, Arrays.asList(modules));
+ this(authService, ssoResource, Arrays.asList(modules));
}
/**
@@ -86,20 +93,35 @@ public abstract class SSOAuthenticationProvider extends AbstractAuthenticationPr
* The SSOAuthenticationProviderService implementation that should be
* used for core authentication functions.
*
+ * @param ssoResource
+ * The SSOResource that should be used to manually redirect the user to
+ * the IdP, as well as to provide any implementation-specific REST
+ * endpoints.
+ *
* @param modules
* Any additional modules that should be used when creating the Guice
* injector.
*/
public SSOAuthenticationProvider(
Class extends SSOAuthenticationProviderService> authService,
+ Class extends SSOResource> ssoResource,
Iterable extends Module> modules) {
injector = Guice.createInjector(Iterables.concat(Collections.singletonList(new AbstractModule() {
@Override
protected void configure() {
+
bind(AuthenticationProvider.class).toInstance(SSOAuthenticationProvider.this);
bind(Environment.class).toInstance(LocalEnvironment.getInstance());
bind(SSOAuthenticationProviderService.class).to(authService);
+
+ // Bind custom SSOResource implementation if different from
+ // core implementation (explicitly binding SSOResource as
+ // SSOResource results in a runtime error from Guice otherwise)
+ LinkedBindingBuilder resourceBinding = bind(SSOResource.class);
+ if (ssoResource != SSOResource.class)
+ resourceBinding.to(ssoResource);
+
}
}), modules));
@@ -145,6 +167,11 @@ public abstract class SSOAuthenticationProvider extends AbstractAuthenticationPr
}
+ @Override
+ public SSOResource getResource() {
+ return getInjector().getInstance(SSOResource.class);
+ }
+
@Override
public void shutdown() {
injector.getInstance(SSOAuthenticationProviderService.class).shutdown();
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOAuthenticationProviderService.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOAuthenticationProviderService.java
index cd2d424b2..d35c07dab 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOAuthenticationProviderService.java
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOAuthenticationProviderService.java
@@ -19,6 +19,7 @@
package org.apache.guacamole.auth.sso;
+import java.net.URI;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.sso.user.SSOAuthenticatedUser;
import org.apache.guacamole.net.auth.Credentials;
@@ -49,6 +50,19 @@ public interface SSOAuthenticationProviderService {
SSOAuthenticatedUser authenticateUser(Credentials credentials)
throws GuacamoleException;
+ /**
+ * Returns the full URI of the login endpoint to which a user must be
+ * redirected in order to authenticate with the SSO identity provider.
+ *
+ * @return
+ * The full URI of the SSO login endpoint.
+ *
+ * @throws GuacamoleException
+ * If configuration information required for generating the login URI
+ * cannot be read.
+ */
+ URI getLoginURI() throws GuacamoleException;
+
/**
* Frees all resources associated with the relevant
* SSOAuthenticationProvider implementation. This function is automatically
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOResource.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOResource.java
new file mode 100644
index 000000000..91bd39ba2
--- /dev/null
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/SSOResource.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package org.apache.guacamole.auth.sso;
+
+import com.google.inject.Inject;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import org.apache.guacamole.GuacamoleException;
+
+/**
+ * REST API resource that provides allows the user to be manually redirected to
+ * the applicable identity provider. Implementations may also provide
+ * additional resources and endpoints beneath this resource as needed.
+ */
+public class SSOResource {
+
+ /**
+ * Service for authenticating users using CAS.
+ */
+ @Inject
+ private SSOAuthenticationProviderService authService;
+
+ /**
+ * Redirects the user to the relevant identity provider. If the SSO
+ * extension defining this resource is not the primary extension, and thus
+ * the user will not be automatically redirected to the IdP, this endpoint
+ * allows that redirect to occur manually upon a link/button click.
+ *
+ * @return
+ * An HTTP Response that will redirect the user to the IdP.
+ *
+ * @throws GuacamoleException
+ * If an error occurs preventing the redirect from being created.
+ */
+ @GET
+ @Path("login")
+ public Response redirectToIdentityProvider() throws GuacamoleException {
+ return Response.seeOther(authService.getLoginURI()).build();
+ }
+
+}
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/html/sso-providers.html b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/html/sso-providers.html
new file mode 100644
index 000000000..bac5f6e33
--- /dev/null
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/html/sso-providers.html
@@ -0,0 +1,7 @@
+
+
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/styles/sso-providers.css b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/styles/sso-providers.css
new file mode 100644
index 000000000..27eae1ea7
--- /dev/null
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/styles/sso-providers.css
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+.login-ui .sso-providers {
+ display: none;
+}
+
+.login-ui .sso-providers:last-child {
+ display: table-row;
+}
+
+.sso-providers ul {
+ list-style: none;
+}
+
+.sso-providers ul, .sso-providers li {
+ display: inline-block;
+ margin: 0;
+ padding: 0;
+}
+
+.sso-providers li::before {
+ content: ' / ';
+}
+
+.sso-providers li:first-child::before {
+ display: none;
+}
+
+.sso-providers-content {
+ display: table-cell;
+ padding: 0.25em 0.5em;
+ height: 1px;
+}
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/translations/en.json b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/translations/en.json
index 47fc299fa..859301568 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/translations/en.json
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/resources/translations/en.json
@@ -13,10 +13,14 @@
},
"LOGIN" : {
- "FIELD_HEADER_ID_TOKEN" : "",
- "FIELD_HEADER_STATE" : "",
- "FIELD_HEADER_TICKET" : "",
- "INFO_IDP_REDIRECT_PENDING" : "Please wait, redirecting to identity provider..."
+ "FIELD_HEADER_ID_TOKEN" : "",
+ "FIELD_HEADER_STATE" : "",
+ "FIELD_HEADER_TICKET" : "",
+ "INFO_IDP_REDIRECT_PENDING" : "Please wait, redirecting to identity provider...",
+ "NAME_IDP_CAS" : "CAS",
+ "NAME_IDP_OPENID" : "OpenID",
+ "NAME_IDP_SAML" : "SAML",
+ "SECTION_HEADER_SSO_OPTIONS" : "Sign in with:"
}
}
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/.ratignore b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/.ratignore
index e69de29bb..da318d12f 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/.ratignore
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/.ratignore
@@ -0,0 +1 @@
+src/main/resources/html/*.html
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/AuthenticationProviderService.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/AuthenticationProviderService.java
index 7aa3c1b87..f1e393d96 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/AuthenticationProviderService.java
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/AuthenticationProviderService.java
@@ -20,25 +20,39 @@
package org.apache.guacamole.auth.cas;
import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.net.URI;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.UriBuilder;
import org.apache.guacamole.form.Field;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
import org.apache.guacamole.auth.cas.conf.ConfigurationService;
-import org.apache.guacamole.auth.cas.form.CASTicketField;
import org.apache.guacamole.auth.cas.ticket.TicketValidationService;
import org.apache.guacamole.auth.sso.SSOAuthenticationProviderService;
import org.apache.guacamole.auth.sso.user.SSOAuthenticatedUser;
+import org.apache.guacamole.form.RedirectField;
import org.apache.guacamole.language.TranslatableMessage;
/**
* Service that authenticates Guacamole users by processing CAS tickets.
*/
+@Singleton
public class AuthenticationProviderService implements SSOAuthenticationProviderService {
+ /**
+ * The parameter that will be present upon successful CAS authentication.
+ */
+ public static final String TICKET_PARAMETER_NAME = "ticket";
+
+ /**
+ * The standard URI name for the CAS login resource.
+ */
+ private static final String CAS_LOGIN_URI = "login";
+
/**
* Service for retrieving CAS configuration information.
*/
@@ -58,29 +72,32 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS
// Pull CAS ticket from request if present
HttpServletRequest request = credentials.getRequest();
if (request != null) {
- String ticket = request.getParameter(CASTicketField.PARAMETER_NAME);
+ String ticket = request.getParameter(TICKET_PARAMETER_NAME);
if (ticket != null) {
return ticketService.validateTicket(ticket, credentials);
}
}
- // Request CAS ticket
+ // Request CAS ticket (will automatically redirect the user to the
+ // CAS authorization page via JavaScript)
throw new GuacamoleInvalidCredentialsException("Invalid login.",
new CredentialsInfo(Arrays.asList(new Field[] {
-
- // CAS-specific ticket (will automatically redirect the user
- // to the authorization page via JavaScript)
- new CASTicketField(
- confService.getAuthorizationEndpoint(),
- confService.getRedirectURI(),
- new TranslatableMessage("LOGIN.INFO_IDP_REDIRECT_PENDING")
- )
+ new RedirectField(TICKET_PARAMETER_NAME, getLoginURI(),
+ new TranslatableMessage("LOGIN.INFO_IDP_REDIRECT_PENDING"))
}))
);
}
+ @Override
+ public URI getLoginURI() throws GuacamoleException {
+ return UriBuilder.fromUri(confService.getAuthorizationEndpoint())
+ .path(CAS_LOGIN_URI)
+ .queryParam("service", confService.getRedirectURI())
+ .build();
+ }
+
@Override
public void shutdown() {
// Nothing to clean up
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/CASAuthenticationProvider.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/CASAuthenticationProvider.java
index dda5b73b5..2b542fc9f 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/CASAuthenticationProvider.java
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/CASAuthenticationProvider.java
@@ -20,6 +20,7 @@
package org.apache.guacamole.auth.cas;
import org.apache.guacamole.auth.sso.SSOAuthenticationProvider;
+import org.apache.guacamole.auth.sso.SSOResource;
/**
* Guacamole authentication backend which authenticates users using an
@@ -34,7 +35,8 @@ public class CASAuthenticationProvider extends SSOAuthenticationProvider {
* against an CAS service
*/
public CASAuthenticationProvider() {
- super(AuthenticationProviderService.class, new CASAuthenticationProviderModule());
+ super(AuthenticationProviderService.class,
+ SSOResource.class, new CASAuthenticationProviderModule());
}
@Override
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/form/CASTicketField.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/form/CASTicketField.java
deleted file mode 100644
index a925dfcc3..000000000
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/java/org/apache/guacamole/auth/cas/form/CASTicketField.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.guacamole.auth.cas.form;
-
-import java.net.URI;
-import javax.ws.rs.core.UriBuilder;
-import org.apache.guacamole.form.RedirectField;
-import org.apache.guacamole.language.TranslatableMessage;
-
-
-/**
- * Field definition which represents the ticket returned by an CAS service.
- * This is processed transparently - the user is redirected to CAS, authenticates
- * and then is returned to Guacamole where the ticket field is
- * processed.
- */
-public class CASTicketField extends RedirectField {
-
- /**
- * The parameter that will be present upon successful CAS authentication.
- */
- public static final String PARAMETER_NAME = "ticket";
-
- /**
- * The standard URI name for the CAS login resource.
- */
- private static final String CAS_LOGIN_URI = "login";
-
- /**
- * Creates a new CAS "ticket" field which links to the given CAS
- * service using the provided client ID. Successful authentication at the
- * CAS service will result in the client being redirected to the specified
- * redirect URI. The CAS ticket will be embedded in the fragment (the part
- * following the hash symbol) of that URI, which the JavaScript side of
- * this extension will move to the query parameters.
- *
- * @param authorizationEndpoint
- * The full URL of the endpoint accepting CAS authentication
- * requests.
- *
- * @param redirectURI
- * The URI that the CAS service should redirect to upon successful
- * authentication.
- *
- * @param redirectMessage
- * The message that will be displayed for the user while the redirect
- * is processed. This will be processed through Guacamole's translation
- * system.
- */
- public CASTicketField(URI authorizationEndpoint, URI redirectURI,
- TranslatableMessage redirectMessage) {
-
- super(PARAMETER_NAME, UriBuilder.fromUri(authorizationEndpoint)
- .path(CAS_LOGIN_URI)
- .queryParam("service", redirectURI)
- .build(),
- redirectMessage);
-
- }
-
-}
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/guac-manifest.json
index a2aaa9433..25584cf89 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/guac-manifest.json
@@ -9,6 +9,15 @@
"org.apache.guacamole.auth.cas.CASAuthenticationProvider"
],
+ "css" : [
+ "styles/sso-providers.css"
+ ],
+
+ "html" : [
+ "html/sso-providers.html",
+ "html/sso-provider-cas.html"
+ ],
+
"translations" : [
"translations/ca.json",
"translations/de.json",
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/html/sso-provider-cas.html b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/html/sso-provider-cas.html
new file mode 100644
index 000000000..348da10fa
--- /dev/null
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/html/sso-provider-cas.html
@@ -0,0 +1,4 @@
+
+
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/.ratignore b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/.ratignore
index e69de29bb..da318d12f 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/.ratignore
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/.ratignore
@@ -0,0 +1 @@
+src/main/resources/html/*.html
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java
index 08ad373dd..23ac815dc 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java
@@ -21,18 +21,21 @@ package org.apache.guacamole.auth.openid;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.UriBuilder;
import org.apache.guacamole.auth.openid.conf.ConfigurationService;
-import org.apache.guacamole.auth.openid.form.TokenField;
import org.apache.guacamole.auth.openid.token.NonceService;
import org.apache.guacamole.auth.openid.token.TokenValidationService;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.sso.SSOAuthenticationProviderService;
import org.apache.guacamole.auth.sso.user.SSOAuthenticatedUser;
import org.apache.guacamole.form.Field;
+import org.apache.guacamole.form.RedirectField;
import org.apache.guacamole.language.TranslatableMessage;
import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
@@ -42,8 +45,15 @@ import org.jose4j.jwt.JwtClaims;
/**
* Service that authenticates Guacamole users by processing OpenID tokens.
*/
+@Singleton
public class AuthenticationProviderService implements SSOAuthenticationProviderService {
+ /**
+ * The standard HTTP parameter which will be included within the URL by all
+ * OpenID services upon successful authentication and redirect.
+ */
+ public static final String TOKEN_PARAMETER_NAME = "id_token";
+
/**
* Service for retrieving OpenID configuration information.
*/
@@ -78,7 +88,7 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS
// Validate OpenID token in request, if present, and derive username
HttpServletRequest request = credentials.getRequest();
if (request != null) {
- String token = request.getParameter(TokenField.PARAMETER_NAME);
+ String token = request.getParameter(TOKEN_PARAMETER_NAME);
if (token != null) {
JwtClaims claims = tokenService.validateToken(token);
if (claims != null) {
@@ -99,26 +109,28 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS
}
- // Request OpenID token
+ // Request OpenID token (will automatically redirect the user to the
+ // OpenID authorization page via JavaScript)
throw new GuacamoleInvalidCredentialsException("Invalid login.",
new CredentialsInfo(Arrays.asList(new Field[] {
-
- // OpenID-specific token (will automatically redirect the user
- // to the authorization page via JavaScript)
- new TokenField(
- confService.getAuthorizationEndpoint(),
- confService.getScope(),
- confService.getClientID(),
- confService.getRedirectURI(),
- nonceService.generate(confService.getMaxNonceValidity() * 60000L),
- new TranslatableMessage("LOGIN.INFO_IDP_REDIRECT_PENDING")
- )
-
+ new RedirectField(TOKEN_PARAMETER_NAME, getLoginURI(),
+ new TranslatableMessage("LOGIN.INFO_IDP_REDIRECT_PENDING"))
}))
);
}
+ @Override
+ public URI getLoginURI() throws GuacamoleException {
+ return UriBuilder.fromUri(confService.getAuthorizationEndpoint())
+ .queryParam("scope", confService.getScope())
+ .queryParam("response_type", "id_token")
+ .queryParam("client_id", confService.getClientID())
+ .queryParam("redirect_uri", confService.getRedirectURI())
+ .queryParam("nonce", nonceService.generate(confService.getMaxNonceValidity() * 60000L))
+ .build();
+ }
+
@Override
public void shutdown() {
// Nothing to clean up
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProvider.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProvider.java
index 32588d811..a760854a6 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProvider.java
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProvider.java
@@ -20,6 +20,7 @@
package org.apache.guacamole.auth.openid;
import org.apache.guacamole.auth.sso.SSOAuthenticationProvider;
+import org.apache.guacamole.auth.sso.SSOResource;
/**
* Guacamole authentication backend which authenticates users using an
@@ -34,7 +35,8 @@ public class OpenIDAuthenticationProvider extends SSOAuthenticationProvider {
* against an OpenID service.
*/
public OpenIDAuthenticationProvider() {
- super(AuthenticationProviderService.class, new OpenIDAuthenticationProviderModule());
+ super(AuthenticationProviderService.class, SSOResource.class,
+ new OpenIDAuthenticationProviderModule());
}
@Override
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java
deleted file mode 100644
index 44d90a8fa..000000000
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.guacamole.auth.openid.form;
-
-import java.net.URI;
-import javax.ws.rs.core.UriBuilder;
-import org.apache.guacamole.form.RedirectField;
-import org.apache.guacamole.language.TranslatableMessage;
-
-/**
- * Field definition which represents the token returned by an OpenID Connect
- * service.
- */
-public class TokenField extends RedirectField {
-
- /**
- * The standard HTTP parameter which will be included within the URL by all
- * OpenID services upon successful authentication and redirect.
- */
- public static final String PARAMETER_NAME = "id_token";
-
- /**
- * Creates a new field which requests authentication via OpenID connect.
- * Successful authentication at the OpenID Connect service will result in
- * the client being redirected to the specified redirect URI. The OpenID
- * token will be embedded in the fragment (the part following the hash
- * symbol) of that URI, which the JavaScript side of this extension will
- * move to the query parameters.
- *
- * @param authorizationEndpoint
- * The full URL of the endpoint accepting OpenID authentication
- * requests.
- *
- * @param scope
- * The space-delimited list of OpenID scopes to request from the
- * identity provider, such as "openid" or "openid email profile".
- *
- * @param clientID
- * The ID of the OpenID client. This is normally determined ahead of
- * time by the OpenID service through some manual credential request
- * procedure.
- *
- * @param redirectURI
- * The URI that the OpenID service should redirect to upon successful
- * authentication.
- *
- * @param nonce
- * A random string unique to this request. To defend against replay
- * attacks, this value must cease being valid after its first use.
- *
- * @param redirectMessage
- * The message that will be displayed to the user during redirect. This
- * will be processed through Guacamole's translation system.
- */
- public TokenField(URI authorizationEndpoint, String scope,
- String clientID, URI redirectURI, String nonce,
- TranslatableMessage redirectMessage) {
-
- super(PARAMETER_NAME, UriBuilder.fromUri(authorizationEndpoint)
- .queryParam("scope", scope)
- .queryParam("response_type", "id_token")
- .queryParam("client_id", clientID)
- .queryParam("redirect_uri", redirectURI)
- .queryParam("nonce", nonce)
- .build(),
- redirectMessage);
-
- }
-
-}
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/guac-manifest.json
index b48bd2d31..3d96ab9de 100644
--- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/guac-manifest.json
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/guac-manifest.json
@@ -9,6 +9,15 @@
"org.apache.guacamole.auth.openid.OpenIDAuthenticationProvider"
],
+ "css" : [
+ "styles/sso-providers.css"
+ ],
+
+ "html" : [
+ "html/sso-providers.html",
+ "html/sso-provider-openid.html"
+ ],
+
"translations" : [
"translations/ca.json",
"translations/de.json",
diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/html/sso-provider-openid.html b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/html/sso-provider-openid.html
new file mode 100644
index 000000000..0da260f96
--- /dev/null
+++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/html/sso-provider-openid.html
@@ -0,0 +1,4 @@
+
+