mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-10-27 15:13:07 +00:00
GUACAMOLE-210: Add configuration options for scope, clock skew, etc., as well as sensible defaults.
This commit is contained in:
@@ -118,9 +118,10 @@ public class AuthenticationProviderService {
|
|||||||
// to the authorization page via JavaScript)
|
// to the authorization page via JavaScript)
|
||||||
new TokenField(
|
new TokenField(
|
||||||
confService.getAuthorizationEndpoint(),
|
confService.getAuthorizationEndpoint(),
|
||||||
|
confService.getScope(),
|
||||||
confService.getClientID(),
|
confService.getClientID(),
|
||||||
confService.getRedirectURI(),
|
confService.getRedirectURI(),
|
||||||
nonceService.generate(30000 /* FIXME: Calculate appropriate value based on configuration */)
|
nonceService.generate(confService.getMaxNonceValidity() * 60000L)
|
||||||
)
|
)
|
||||||
|
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package org.apache.guacamole.auth.openid.conf;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.environment.Environment;
|
import org.apache.guacamole.environment.Environment;
|
||||||
|
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
|
||||||
import org.apache.guacamole.properties.StringGuacamoleProperty;
|
import org.apache.guacamole.properties.StringGuacamoleProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +31,35 @@ import org.apache.guacamole.properties.StringGuacamoleProperty;
|
|||||||
*/
|
*/
|
||||||
public class ConfigurationService {
|
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.
|
* The authorization endpoint (URI) of the OpenID service.
|
||||||
*/
|
*/
|
||||||
@@ -76,6 +106,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
|
* OpenID client ID which should be submitted to the OpenID service when
|
||||||
* necessary. This value is typically provided by the OpenID service when
|
* necessary. This value is typically provided by the OpenID service when
|
||||||
@@ -196,18 +276,87 @@ public class ConfigurationService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the claim type which contains the authenticated user's username
|
* 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
|
* @return
|
||||||
* The claim type which contains the authenticated user's username
|
* 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.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If guacamole.properties cannot be parsed, or if the username claim
|
* If guacamole.properties cannot be parsed.
|
||||||
* type property is missing.
|
|
||||||
*/
|
*/
|
||||||
public String getUsernameClaimType() throws GuacamoleException {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ public class TokenField extends Field {
|
|||||||
* The full URL of the endpoint accepting OpenID authentication
|
* The full URL of the endpoint accepting OpenID authentication
|
||||||
* requests.
|
* 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
|
* @param clientID
|
||||||
* The ID of the OpenID client. This is normally determined ahead of
|
* The ID of the OpenID client. This is normally determined ahead of
|
||||||
* time by the OpenID service through some manual credential request
|
* 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
|
* A random string unique to this request. To defend against replay
|
||||||
* attacks, this value must cease being valid after its first use.
|
* attacks, this value must cease being valid after its first use.
|
||||||
*/
|
*/
|
||||||
public TokenField(String authorizationEndpoint, String clientID,
|
public TokenField(String authorizationEndpoint, String scope,
|
||||||
String redirectURI, String nonce) {
|
String clientID, String redirectURI, String nonce) {
|
||||||
|
|
||||||
// Init base field properties
|
// Init base field properties
|
||||||
super(PARAMETER_NAME, "GUAC_OPENID_TOKEN");
|
super(PARAMETER_NAME, "GUAC_OPENID_TOKEN");
|
||||||
@@ -74,7 +78,7 @@ public class TokenField extends Field {
|
|||||||
// Build authorization URI from given values
|
// Build authorization URI from given values
|
||||||
try {
|
try {
|
||||||
this.authorizationURI = authorizationEndpoint
|
this.authorizationURI = authorizationEndpoint
|
||||||
+ "?scope=openid%20email%20profile"
|
+ "?scope=" + URLEncoder.encode(scope, "UTF-8")
|
||||||
+ "&response_type=id_token"
|
+ "&response_type=id_token"
|
||||||
+ "&client_id=" + URLEncoder.encode(clientID, "UTF-8")
|
+ "&client_id=" + URLEncoder.encode(clientID, "UTF-8")
|
||||||
+ "&redirect_uri=" + URLEncoder.encode(redirectURI, "UTF-8")
|
+ "&redirect_uri=" + URLEncoder.encode(redirectURI, "UTF-8")
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ package org.apache.guacamole.auth.openid.token;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import org.apache.guacamole.auth.openid.conf.ConfigurationService;
|
import org.apache.guacamole.auth.openid.conf.ConfigurationService;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.GuacamoleSecurityException;
|
|
||||||
import org.apache.guacamole.GuacamoleServerException;
|
|
||||||
import org.jose4j.jwk.HttpsJwks;
|
import org.jose4j.jwk.HttpsJwks;
|
||||||
import org.jose4j.jwt.JwtClaims;
|
import org.jose4j.jwt.JwtClaims;
|
||||||
import org.jose4j.jwt.MalformedClaimException;
|
import org.jose4j.jwt.MalformedClaimException;
|
||||||
@@ -82,8 +80,8 @@ public class TokenValidationService {
|
|||||||
// Create JWT consumer for validating received token
|
// Create JWT consumer for validating received token
|
||||||
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
|
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
|
||||||
.setRequireExpirationTime()
|
.setRequireExpirationTime()
|
||||||
.setMaxFutureValidityInMinutes(300)
|
.setMaxFutureValidityInMinutes(confService.getMaxTokenValidity())
|
||||||
.setAllowedClockSkewInSeconds(30)
|
.setAllowedClockSkewInSeconds(confService.getAllowedClockSkew())
|
||||||
.setRequireSubject()
|
.setRequireSubject()
|
||||||
.setExpectedIssuer(confService.getIssuer())
|
.setExpectedIssuer(confService.getIssuer())
|
||||||
.setExpectedAudience(confService.getClientID())
|
.setExpectedAudience(confService.getClientID())
|
||||||
|
|||||||
Reference in New Issue
Block a user