GUACAMOLE-210: Add configuration options for scope, clock skew, etc., as well as sensible defaults.
Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/commit/4dbf9a3f Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/4dbf9a3f Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/4dbf9a3f Branch: refs/heads/master Commit: 4dbf9a3f9ed899ca614f74871c05b4cd901b6e73 Parents: aaf1b79 Author: Michael Jumper <mjum...@apache.org> Authored: Mon Aug 28 02:04:21 2017 -0700 Committer: Michael Jumper <mjum...@apache.org> Committed: Mon Sep 25 13:06:45 2017 -0700 ---------------------------------------------------------------------- .../openid/AuthenticationProviderService.java | 3 +- .../auth/openid/conf/ConfigurationService.java | 157 ++++++++++++++++++- .../guacamole/auth/openid/form/TokenField.java | 10 +- .../openid/token/TokenValidationService.java | 6 +- 4 files changed, 164 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/4dbf9a3f/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java index 46e8b02..47d99ff 100644 --- a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java @@ -118,9 +118,10 @@ public class AuthenticationProviderService { // to the authorization page via JavaScript) new TokenField( confService.getAuthorizationEndpoint(), + confService.getScope(), confService.getClientID(), confService.getRedirectURI(), - nonceService.generate(30000 /* FIXME: Calculate appropriate value based on configuration */) + nonceService.generate(confService.getMaxNonceValidity() * 60000L) ) })) http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/4dbf9a3f/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java index 6f7e44b..c742d89 100644 --- a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java @@ -22,6 +22,7 @@ package org.apache.guacamole.auth.openid.conf; import com.google.inject.Inject; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.properties.IntegerGuacamoleProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; /** @@ -31,6 +32,35 @@ import org.apache.guacamole.properties.StringGuacamoleProperty; public class ConfigurationService { /** + * The default claim type to use to retrieve an authenticated user's + * username. + */ + private static final String DEFAULT_USERNAME_CLAIM_TYPE = "email"; + + /** + * The default space-separated list of OpenID scopes to request. + */ + private static final String DEFAULT_SCOPE = "openid email profile"; + + /** + * The default amount of clock skew tolerated for timestamp comparisons + * between the Guacamole server and OpenID service clocks, in seconds. + */ + private static final int DEFAULT_ALLOWED_CLOCK_SKEW = 30; + + /** + * The default maximum amount of time that an OpenID token should remain + * valid, in minutes. + */ + private static final int DEFAULT_MAX_TOKEN_VALIDITY = 300; + + /** + * The default maximum amount of time that a nonce generated by the + * Guacamole server should remain valid, in minutes. + */ + private static final int DEFAULT_MAX_NONCE_VALIDITY = 10; + + /** * The authorization endpoint (URI) of the OpenID service. */ private static final StringGuacamoleProperty OPENID_AUTHORIZATION_ENDPOINT = @@ -77,6 +107,56 @@ public class ConfigurationService { }; /** + * The space-separated list of OpenID scopes to request. + */ + private static final StringGuacamoleProperty OPENID_SCOPE = + new StringGuacamoleProperty() { + + @Override + public String getName() { return "openid-scope"; } + + }; + + /** + * The amount of clock skew tolerated for timestamp comparisons between the + * Guacamole server and OpenID service clocks, in seconds. + */ + private static final IntegerGuacamoleProperty OPENID_ALLOWED_CLOCK_SKEW = + new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "openid-allowed-clock-skew"; } + + }; + + /** + * The maximum amount of time that an OpenID token should remain valid, in + * minutes. + */ + private static final IntegerGuacamoleProperty OPENID_MAX_TOKEN_VALIDITY = + new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "openid-max-token-validity"; } + + }; + + /** + * The maximum amount of time that a nonce generated by the Guacamole server + * should remain valid, in minutes. As each OpenID request has a unique + * nonce value, this imposes an upper limit on the amount of time any + * particular OpenID request can result in successful authentication within + * Guacamole. + */ + private static final IntegerGuacamoleProperty OPENID_MAX_NONCE_VALIDITY = + new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "openid-max-nonce-validity"; } + + }; + + /** * OpenID client ID which should be submitted to the OpenID service when * necessary. This value is typically provided by the OpenID service when * OpenID credentials are generated for your application. @@ -196,18 +276,87 @@ public class ConfigurationService { /** * Returns the claim type which contains the authenticated user's username - * within any valid JWT, as configured with guacamole.properties. + * within any valid JWT, as configured with guacamole.properties. By + * default, this will be "email". * * @return * The claim type which contains the authenticated user's username * within any valid JWT, as configured with guacamole.properties. * * @throws GuacamoleException - * If guacamole.properties cannot be parsed, or if the username claim - * type property is missing. + * If guacamole.properties cannot be parsed. */ public String getUsernameClaimType() throws GuacamoleException { - return environment.getRequiredProperty(OPENID_USERNAME_CLAIM_TYPE); + return environment.getProperty(OPENID_USERNAME_CLAIM_TYPE, DEFAULT_USERNAME_CLAIM_TYPE); + } + + /** + * Returns the space-separated list of OpenID scopes to request. By default, + * this will be "openid email profile". The OpenID scopes determine the + * information returned within the OpenID token, and thus affect what + * values can be used as an authenticated user's username. + * + * @return + * The space-separated list of OpenID scopes to request when identifying + * a user. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public String getScope() throws GuacamoleException { + return environment.getProperty(OPENID_SCOPE, DEFAULT_SCOPE); + } + + /** + * Returns the amount of clock skew tolerated for timestamp comparisons + * between the Guacamole server and OpenID service clocks, in seconds. Too + * much clock skew will affect token expiration calculations, possibly + * allowing old tokens to be used. By default, this will be 30. + * + * @return + * The amount of clock skew tolerated for timestamp comparisons, in + * seconds. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public int getAllowedClockSkew() throws GuacamoleException { + return environment.getProperty(OPENID_ALLOWED_CLOCK_SKEW, DEFAULT_ALLOWED_CLOCK_SKEW); + } + + /** + * Returns the maximum amount of time that an OpenID token should remain + * valid, in minutes. A token received from an OpenID service which is + * older than this amount of time will be rejected, even if it is otherwise + * valid. By default, this will be 300 (5 hours). + * + * @return + * The maximum amount of time that an OpenID token should remain valid, + * in minutes. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public int getMaxTokenValidity() throws GuacamoleException { + return environment.getProperty(OPENID_MAX_TOKEN_VALIDITY, DEFAULT_MAX_TOKEN_VALIDITY); + } + + /** + * Returns the maximum amount of time that a nonce generated by the + * Guacamole server should remain valid, in minutes. As each OpenID request + * has a unique nonce value, this imposes an upper limit on the amount of + * time any particular OpenID request can result in successful + * authentication within Guacamole. By default, this will be 10. + * + * @return + * The maximum amount of time that a nonce generated by the Guacamole + * server should remain valid, in minutes. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public int getMaxNonceValidity() throws GuacamoleException { + return environment.getProperty(OPENID_MAX_NONCE_VALIDITY, DEFAULT_MAX_NONCE_VALIDITY); } } http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/4dbf9a3f/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java index 3f7c454..d99c367 100644 --- a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java +++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java @@ -52,6 +52,10 @@ public class TokenField extends Field { * 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 @@ -65,8 +69,8 @@ public class TokenField extends Field { * A random string unique to this request. To defend against replay * attacks, this value must cease being valid after its first use. */ - public TokenField(String authorizationEndpoint, String clientID, - String redirectURI, String nonce) { + public TokenField(String authorizationEndpoint, String scope, + String clientID, String redirectURI, String nonce) { // Init base field properties super(PARAMETER_NAME, "GUAC_OPENID_TOKEN"); @@ -74,7 +78,7 @@ public class TokenField extends Field { // Build authorization URI from given values try { this.authorizationURI = authorizationEndpoint - + "?scope=openid%20email%20profile" + + "?scope=" + URLEncoder.encode(scope, "UTF-8") + "&response_type=id_token" + "&client_id=" + URLEncoder.encode(clientID, "UTF-8") + "&redirect_uri=" + URLEncoder.encode(redirectURI, "UTF-8") http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/4dbf9a3f/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java index 3d41eba..cde4f89 100644 --- a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java +++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java @@ -22,8 +22,6 @@ package org.apache.guacamole.auth.openid.token; import com.google.inject.Inject; import org.apache.guacamole.auth.openid.conf.ConfigurationService; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.GuacamoleSecurityException; -import org.apache.guacamole.GuacamoleServerException; import org.jose4j.jwk.HttpsJwks; import org.jose4j.jwt.JwtClaims; import org.jose4j.jwt.MalformedClaimException; @@ -82,8 +80,8 @@ public class TokenValidationService { // Create JWT consumer for validating received token JwtConsumer jwtConsumer = new JwtConsumerBuilder() .setRequireExpirationTime() - .setMaxFutureValidityInMinutes(300) - .setAllowedClockSkewInSeconds(30) + .setMaxFutureValidityInMinutes(confService.getMaxTokenValidity()) + .setAllowedClockSkewInSeconds(confService.getAllowedClockSkew()) .setRequireSubject() .setExpectedIssuer(confService.getIssuer()) .setExpectedAudience(confService.getClientID())