From 731c622e8fa5aabaa3af021310863fbc5a2245f0 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 5 Feb 2017 20:24:14 -0500 Subject: [PATCH] GUACAMOLE-197: Add some comments to document the logic and the functions. --- .../radius/AuthenticationProviderService.java | 13 ++++- .../auth/radius/ConfigurationService.java | 22 +++++++ .../auth/radius/RadiusConnectionService.java | 58 ++++++++++++++++++- .../form/RadiusChallengeResponseField.java | 18 ++++++ 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/AuthenticationProviderService.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/AuthenticationProviderService.java index 860f83189..e4965b2a1 100644 --- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/AuthenticationProviderService.java @@ -90,7 +90,7 @@ public class AuthenticationProviderService { public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException { - // Attempt bind + // Initialize Radius Packet and try to authenticate RadiusPacket radPack; try { radPack = radiusService.authenticate(credentials.getUsername(), @@ -107,10 +107,17 @@ public class AuthenticationProviderService { logger.debug("Nothing in the RADIUS packet."); throw new GuacamoleInvalidCredentialsException("Permission denied.", CredentialsInfo.USERNAME_PASSWORD); } + + // If we get back an AccessReject packet, login is denied. else if (radPack instanceof AccessReject) { logger.debug("Login has been rejected by RADIUS server."); throw new GuacamoleInvalidCredentialsException("Permission denied.", CredentialsInfo.USERNAME_PASSWORD); } + + /** + * If we receive an AccessChallenge package, the server needs more information - + * We create a new form/field with the challenge message. + */ else if (radPack instanceof AccessChallenge) { try { String replyMsg = radPack.getAttributeValue("Reply-Message").toString(); @@ -127,6 +134,8 @@ public class AuthenticationProviderService { throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD); } } + + // If we receive AccessAccept, authentication has succeeded else if (radPack instanceof AccessAccept) { try { @@ -139,6 +148,8 @@ public class AuthenticationProviderService { radiusService.disconnect(); } } + + // Something else we haven't thought of has happened, so we throw an error else throw new GuacamoleInvalidCredentialsException("Unknown error trying to authenticate.", CredentialsInfo.USERNAME_PASSWORD); 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/ConfigurationService.java index d30e33489..461243b0f 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/ConfigurationService.java @@ -128,6 +128,17 @@ public class ConfigurationService { ); } + /** + * Returns the number of retries for connecting to the RADIUS server + * from guacamole.properties. + * + * @return + * The number of retries for connection to the RADIUS server, + * from guacamole.properties. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ public int getRadiusRetries() throws GuacamoleException { return environment.getProperty( RadiusGuacamoleProperties.RADIUS_RETRIES, @@ -135,6 +146,17 @@ public class ConfigurationService { ); } + /** + * Returns the timeout for connecting to the RADIUS server + * from guacamole.properties. + * + * @return + * The timeout for connection to the RADIUS server, + * from guacamole.properties. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ public int getRadiusTimeout() throws GuacamoleException { return environment.getProperty( RadiusGuacamoleProperties.RADIUS_TIMEOUT, 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 8562ec9fe..02ad9869c 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 @@ -77,6 +77,7 @@ public class RadiusConnectionService { private void createRadiusConnection() { /* + * This is commented out right now because it isn't implemented, yet. // Map encryption method to proper connection and socket factory EncryptionMethod encryptionMethod = confService.getEncryptionMethod(); switch (encryptionMethod) { @@ -101,6 +102,8 @@ public class RadiusConnectionService { } */ + + // Create the RADIUS client with the configuration parameters try { radiusClient = new RadiusClient(InetAddress.getByName(confService.getRadiusServer()), confService.getRadiusSharedSecret(), @@ -126,27 +129,50 @@ public class RadiusConnectionService { } + /** + * Authenticate to the RADIUS server and return the response from the + * server. + * + * @param username + * The username for authentication. + * @param password + * The password for authentication. + * + * @return + * A RadiusPacket with the response of the server. + * + * @throws GuacamoleException + * If an error occurs while talking to the server. + */ public RadiusPacket authenticate(String username, String password) throws GuacamoleException { + // Create the connection and load the attribute dictionary createRadiusConnection(); AttributeFactory.loadAttributeDictionary("net.jradius.dictionary.AttributeDictionaryImpl"); + // If the client is null, we return null - something has gone wrong if (radiusClient == null) return null; + // If a username hasn't been provided, stop if (username == null || username.isEmpty()) { logger.warn("Anonymous access not allowed with RADIUS client."); return null; } + + // If a password hasn't been provided, stop if (password == null || password.isEmpty()) { logger.warn("Password required for RADIUS authentication."); return null; } + // Set up the authentication protocol as configured RadiusAuthenticator radAuth = radiusClient.getAuthProtocol(confService.getRadiusAuthProtocol()); if (radAuth == null) throw new GuacamoleException("Unknown RADIUS authentication protocol."); + + // Set up attributes, create the access request, and send the packet try { AttributeList radAttrs = new AttributeList(); radAttrs.add(new Attr_UserName(username)); @@ -157,11 +183,13 @@ public class RadiusConnectionService { radAuth.processRequest(radAcc); return radiusClient.sendReceive(radAcc, confService.getRadiusRetries()); } + catch (RadiusException e) { logger.error("Unable to complete authentication.", e.getMessage()); logger.debug("Authentication with RADIUS failed.", e); return null; } + catch (NoSuchAlgorithmException e) { logger.error("No such RADIUS algorithm: {}", e.getMessage()); logger.debug("Unknown RADIUS algorithm.", e); @@ -169,28 +197,56 @@ public class RadiusConnectionService { } } + /** + * Authenticate to the RADIUS server using existing state and a response + * + * @param username + * The username for the authentication + * @param state + * The previous state of the RADIUS connection + * @param response + * The response to the RADIUS challenge + * + * @return + * A RadiusPacket with the response of the server. + * + * @throws GuacamoleException + * If an error occurs while talking to the server. + */ public RadiusPacket authenticate(String username, String state, String response) throws GuacamoleException { + // Create the RADIUS connection and set up the dictionary createRadiusConnection(); AttributeFactory.loadAttributeDictionary("net.jradius.dictionary.AttributeDictionaryImpl"); + // Client failed to set up, so we return null if (radiusClient == null) return null; + // If a username wasn't passed, we quit if (username == null || username.isEmpty()) { logger.warn("Anonymous access not allowed with RADIUS client."); return null; } + + // If the state wasn't passed, we quit if (state == null || state.isEmpty()) { logger.warn("This method needs a previous RADIUS state to respond to."); return null; } + + // If the response wasn't passed, we quit if (response == null || response.isEmpty()) { logger.warn("Response required for RADIUS authentication."); return null; } + /** + * Set up the authenticator based on the configured protocol. + * Unless that fails, add the attributes to the packet, set up the packet + * and send the packet. + */ RadiusAuthenticator radAuth = radiusClient.getAuthProtocol(confService.getRadiusAuthProtocol()); if (radAuth == null) throw new GuacamoleException("Unknown RADIUS authentication protocol."); @@ -221,8 +277,6 @@ public class RadiusConnectionService { * Disconnects the given RADIUS connection, logging any failure to do so * appropriately. * - * @param radiusConnection - * The RADIUS connection to disconnect. */ public void disconnect() { diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/form/RadiusChallengeResponseField.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/form/RadiusChallengeResponseField.java index 4721d6175..2c7bba613 100644 --- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/form/RadiusChallengeResponseField.java +++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/form/RadiusChallengeResponseField.java @@ -31,11 +31,29 @@ public class RadiusChallengeResponseField extends Field { */ private final Logger logger = LoggerFactory.getLogger(RadiusChallengeResponseField.class); + /** + * The field returned by the RADIUS challenge/response. + */ private static final String RADIUS_FIELD_NAME = "guac-radius-challenge-response"; + + /** + * The type of field to initialize for the challenge/response. + */ private static final String RADIUS_FIELD_TYPE = "GUAC_RADIUS_CHALLENGE_RESPONSE"; + + /** + * The state of the connection passed by the previous RADIUS attempt. + */ private final String radiusState; + + /** + * The message the RADIUS server sent back in the challenge. + */ private final String replyMsg; + /** + * Initialize the field with the reply message and the state. + */ public RadiusChallengeResponseField(String replyMsg, String radiusState) { super(RADIUS_FIELD_NAME, RADIUS_FIELD_TYPE); logger.debug("Initializing the RADIUS challenge/response field: {}", replyMsg);