GUACAMOLE-774: Merge dynamic loading of MD4 support (for RADIUS MSCHAPv1/2).
diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusAuthenticationProviderModule.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusAuthenticationProviderModule.java
index 37ecb79..d34b0b3 100644
--- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusAuthenticationProviderModule.java
@@ -20,7 +20,12 @@
package org.apache.guacamole.auth.radius;
import com.google.inject.AbstractModule;
+import java.security.Provider;
+import java.security.Security;
import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.radius.conf.ConfigurationService;
+import org.apache.guacamole.auth.radius.conf.RadiusAuthenticationProtocol;
+import org.apache.guacamole.auth.radius.conf.RadiusGuacamoleProperties;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.environment.LocalEnvironment;
import org.apache.guacamole.net.auth.AuthenticationProvider;
@@ -57,6 +62,22 @@
// Get local environment
this.environment = new LocalEnvironment();
+
+ // Check for MD4 requirement
+ RadiusAuthenticationProtocol authProtocol = environment.getProperty(RadiusGuacamoleProperties.RADIUS_AUTH_PROTOCOL);
+ RadiusAuthenticationProtocol innerProtocol = environment.getProperty(RadiusGuacamoleProperties.RADIUS_EAP_TTLS_INNER_PROTOCOL);
+ if (authProtocol == RadiusAuthenticationProtocol.MSCHAPv1
+ || authProtocol == RadiusAuthenticationProtocol.MSCHAPv2
+ || innerProtocol == RadiusAuthenticationProtocol.MSCHAPv1
+ || innerProtocol == RadiusAuthenticationProtocol.MSCHAPv2) {
+
+ Security.addProvider(new Provider("MD4", 0.00, "MD4 for MSCHAPv1/2 Support") {
+ {
+ this.put("MessageDigest.MD4", org.bouncycastle.jce.provider.JDKMessageDigest.MD4.class.getName());
+ }
+ });
+
+ }
// Store associated auth provider
this.authProvider = authProvider;
diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusConnectionService.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusConnectionService.java
index ec82a63..c8a21d6 100644
--- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusConnectionService.java
+++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusConnectionService.java
@@ -27,6 +27,8 @@
import java.security.NoSuchAlgorithmException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
+import org.apache.guacamole.auth.radius.conf.ConfigurationService;
+import org.apache.guacamole.auth.radius.conf.RadiusAuthenticationProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.jradius.client.RadiusClient;
@@ -62,8 +64,7 @@
*/
@Inject
private ConfigurationService confService;
-
-
+
/**
* Creates a new instance of RadiusClient, configured with parameters
* from guacamole.properties.
@@ -115,8 +116,8 @@
* not configured when the client is set up for a tunneled
* RADIUS connection.
*/
- private RadiusAuthenticator setupRadiusAuthenticator(RadiusClient radiusClient)
- throws GuacamoleException {
+ private RadiusAuthenticator setupRadiusAuthenticator(
+ RadiusClient radiusClient) throws GuacamoleException {
// If we don't have a radiusClient object, yet, don't go any further.
if (radiusClient == null) {
@@ -125,7 +126,9 @@
return null;
}
- RadiusAuthenticator radAuth = radiusClient.getAuthProtocol(confService.getRadiusAuthProtocol());
+ RadiusAuthenticator radAuth = radiusClient.getAuthProtocol(
+ confService.getRadiusAuthProtocol().toString());
+
if (radAuth == null)
throw new GuacamoleException("Could not get a valid RadiusAuthenticator for specified protocol: " + confService.getRadiusAuthProtocol());
@@ -157,11 +160,13 @@
// If we're using EAP-TTLS, we need to define tunneled protocol
if (radAuth instanceof EAPTTLSAuthenticator) {
- String innerProtocol = confService.getRadiusEAPTTLSInnerProtocol();
+ RadiusAuthenticationProtocol innerProtocol =
+ confService.getRadiusEAPTTLSInnerProtocol();
+
if (innerProtocol == null)
- throw new GuacamoleException("Trying to use EAP-TTLS, but no inner protocol specified.");
+ throw new GuacamoleException("Missing or invalid inner protocol for EAP-TTLS.");
- ((EAPTTLSAuthenticator)radAuth).setInnerProtocol(innerProtocol);
+ ((EAPTTLSAuthenticator)radAuth).setInnerProtocol(innerProtocol.toString());
}
return radAuth;
@@ -236,14 +241,21 @@
radAuth.setupRequest(radiusClient, radAcc);
radAuth.processRequest(radAcc);
- RadiusResponse reply = radiusClient.sendReceive(radAcc, confService.getRadiusMaxRetries());
+ RadiusResponse reply = radiusClient.sendReceive(radAcc,
+ confService.getRadiusMaxRetries());
// We receive a Challenge not asking for user input, so silently process the challenge
- while((reply instanceof AccessChallenge) && (reply.findAttribute(Attr_ReplyMessage.TYPE) == null)) {
+ while((reply instanceof AccessChallenge)
+ && (reply.findAttribute(Attr_ReplyMessage.TYPE) == null)) {
+
radAuth.processChallenge(radAcc, reply);
- reply = radiusClient.sendReceive(radAcc, confService.getRadiusMaxRetries());
+ reply = radiusClient.sendReceive(radAcc,
+ confService.getRadiusMaxRetries());
+
}
+
return reply;
+
}
catch (RadiusException e) {
logger.error("Unable to complete authentication.", e.getMessage());
@@ -282,8 +294,8 @@
* @throws GuacamoleException
* If an error is encountered trying to talk to the RADIUS server.
*/
- public RadiusPacket sendChallengeResponse(String username, String response, byte[] state)
- throws GuacamoleException {
+ public RadiusPacket sendChallengeResponse(String username, String response,
+ byte[] state) throws GuacamoleException {
if (username == null || username.isEmpty()) {
logger.error("Challenge/response to RADIUS requires a username.");
diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/ConfigurationService.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/ConfigurationService.java
similarity index 92%
rename from extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/ConfigurationService.java
rename to extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/ConfigurationService.java
index 381ea13..2809f7c 100644
--- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/ConfigurationService.java
+++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/ConfigurationService.java
@@ -17,11 +17,12 @@
* under the License.
*/
-package org.apache.guacamole.auth.radius;
+package org.apache.guacamole.auth.radius.conf;
import com.google.inject.Inject;
import java.io.File;
import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.environment.Environment;
/**
@@ -123,8 +124,9 @@
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
- public String getRadiusAuthProtocol() throws GuacamoleException {
- return environment.getProperty(
+ public RadiusAuthenticationProtocol getRadiusAuthProtocol()
+ throws GuacamoleException {
+ return environment.getRequiredProperty(
RadiusGuacamoleProperties.RADIUS_AUTH_PROTOCOL
);
}
@@ -309,12 +311,21 @@
* an EAP-TTLS RADIUS connection.
*
* @throws GuacamoleException
- * If guacamole.properties cannot be parsed.
+ * If guacamole.properties cannot be parsed, or if EAP-TTLS is specified
+ * as the inner protocol.
*/
- public String getRadiusEAPTTLSInnerProtocol() throws GuacamoleException {
- return environment.getProperty(
+ public RadiusAuthenticationProtocol getRadiusEAPTTLSInnerProtocol()
+ throws GuacamoleException {
+
+ RadiusAuthenticationProtocol authProtocol = environment.getProperty(
RadiusGuacamoleProperties.RADIUS_EAP_TTLS_INNER_PROTOCOL
);
+
+ if (authProtocol == RadiusAuthenticationProtocol.EAP_TTLS)
+ throw new GuacamoleServerException("Invalid inner protocol specified for EAP-TTLS.");
+
+ return authProtocol;
+
}
}
diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusAuthenticationProtocol.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusAuthenticationProtocol.java
new file mode 100644
index 0000000..e64a695
--- /dev/null
+++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusAuthenticationProtocol.java
@@ -0,0 +1,118 @@
+/*
+ * 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.radius.conf;
+
+/**
+ * This enum represents supported RADIUS authentication protocols for
+ * the guacamole-auth-radius extension.
+ */
+public enum RadiusAuthenticationProtocol {
+
+ /**
+ * Password Authentication Protocol (PAP)
+ */
+ PAP("pap"),
+
+ /**
+ * Challenge-Handshake Authentication Protocol (CHAP)
+ */
+ CHAP("chap"),
+
+ /**
+ * Microsoft implementation of CHAP, Version 1 (MS-CHAPv1)
+ */
+ MSCHAPv1("mschapv1"),
+
+ /**
+ * Microsoft implementation of CHAP, Version 2 (MS-CHAPv2)
+ */
+ MSCHAPv2("mschapv2"),
+
+ /**
+ * Extensible Authentication Protocol (EAP) with MD5 Hashing (EAP-MD5)
+ */
+ EAP_MD5("eap-md5"),
+
+ /**
+ * Extensible Authentication Protocol (EAP) with TLS encryption (EAP-TLS).
+ */
+ EAP_TLS("eap-tls"),
+
+ /**
+ * Extensible Authentication Protocol (EAP) with Tunneled TLS (EAP-TTLS).
+ */
+ EAP_TTLS("eap-ttls");
+
+ /**
+ * This variable stores the string value of the protocol, and is also
+ * used within the extension to pass to JRadius for configuring the
+ * library to talk to the RADIUS server.
+ */
+ private final String strValue;
+
+ /**
+ * Create a new RadiusAuthenticationProtocol object having the
+ * given string value.
+ *
+ * @param strValue
+ * The value of the protocol to store as a string, which will be used
+ * in specifying the protocol within the guacamole.properties file, and
+ * will also be used by the JRadius library for its configuration.
+ */
+ RadiusAuthenticationProtocol(String strValue) {
+ this.strValue = strValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This function returns the stored string values of the selected RADIUS
+ * protocol, which is used both in Guacamole configuration and also to pass
+ * on to the JRadius library for its configuration.
+ *
+ * @return
+ * The string value stored for the selected RADIUS protocol.
+ */
+ @Override
+ public String toString() {
+ return strValue;
+ }
+
+ /**
+ * For a given String value, return the enum value that matches that string,
+ * or null if no matchi is found.
+ *
+ * @param value
+ * The string value to search for in the list of enums.
+ *
+ * @return
+ * The RadiusAuthenticationProtocol value that is identified by the
+ * provided String value.
+ */
+ public static RadiusAuthenticationProtocol getEnum(String value) {
+
+ for (RadiusAuthenticationProtocol v : values())
+ if(v.toString().equals(value))
+ return v;
+
+ return null;
+ }
+
+}
diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusAuthenticationProtocolProperty.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusAuthenticationProtocolProperty.java
new file mode 100644
index 0000000..c92c0a3
--- /dev/null
+++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusAuthenticationProtocolProperty.java
@@ -0,0 +1,54 @@
+/*
+ * 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.radius.conf;
+
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleServerException;
+import org.apache.guacamole.properties.GuacamoleProperty;
+
+/**
+ * A GuacamoleProperty whose value is a RadiusAuthenticationProtocol.
+ */
+public abstract class RadiusAuthenticationProtocolProperty
+ implements GuacamoleProperty<RadiusAuthenticationProtocol> {
+
+ @Override
+ public RadiusAuthenticationProtocol parseValue(String value)
+ throws GuacamoleException {
+
+ // Nothing provided, nothing returned
+ if (value == null)
+ return null;
+
+ // Attempt to parse the string value
+ RadiusAuthenticationProtocol authProtocol =
+ RadiusAuthenticationProtocol.getEnum(value);
+
+ // Throw an exception if nothing matched.
+ if (authProtocol == null)
+ throw new GuacamoleServerException(
+ "Invalid or unsupported RADIUS authentication protocol.");
+
+ // Return the answer
+ return authProtocol;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusGuacamoleProperties.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusGuacamoleProperties.java
similarity index 93%
rename from extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusGuacamoleProperties.java
rename to extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusGuacamoleProperties.java
index aaa445e..af6839b 100644
--- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusGuacamoleProperties.java
+++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusGuacamoleProperties.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.apache.guacamole.auth.radius;
+package org.apache.guacamole.auth.radius.conf;
import org.apache.guacamole.properties.BooleanGuacamoleProperty;
import org.apache.guacamole.properties.FileGuacamoleProperty;
@@ -81,7 +81,8 @@
/**
* The authentication protocol of the RADIUS server to connect to when authenticating users.
*/
- public static final StringGuacamoleProperty RADIUS_AUTH_PROTOCOL = new StringGuacamoleProperty() {
+ public static final RadiusAuthenticationProtocolProperty RADIUS_AUTH_PROTOCOL =
+ new RadiusAuthenticationProtocolProperty() {
@Override
public String getName() { return "radius-auth-protocol"; }
@@ -181,7 +182,8 @@
/**
* The tunneled protocol to use inside a RADIUS EAP-TTLS connection.
*/
- public static final StringGuacamoleProperty RADIUS_EAP_TTLS_INNER_PROTOCOL = new StringGuacamoleProperty() {
+ public static final RadiusAuthenticationProtocolProperty RADIUS_EAP_TTLS_INNER_PROTOCOL =
+ new RadiusAuthenticationProtocolProperty() {
@Override
public String getName() { return "radius-eap-ttls-inner-protocol"; }