Add .gitignore and .ratignore files for various directories
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
gyurix
2025-04-29 21:43:12 +02:00
parent 983ecbfc53
commit be9f66dee9
2167 changed files with 254128 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
src/main/resources/generated/
target/
*~

View File

@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.guacamole</groupId>
<artifactId>guacamole-auth-radius</artifactId>
<packaging>jar</packaging>
<version>1.6.0</version>
<name>guacamole-auth-radius</name>
<url>http://guacamole.apache.org/</url>
<parent>
<groupId>org.apache.guacamole</groupId>
<artifactId>extensions</artifactId>
<version>1.6.0</version>
<relativePath>../</relativePath>
</parent>
<build>
<plugins>
<!-- Pre-cache Angular templates with maven-angular-plugin -->
<plugin>
<groupId>com.keithbranton.mojo</groupId>
<artifactId>angular-maven-plugin</artifactId>
<version>0.3.4</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>html2js</goal>
</goals>
</execution>
</executions>
<configuration>
<sourceDir>${basedir}/src/main/resources</sourceDir>
<include>**/*.html</include>
<target>${basedir}/src/main/resources/generated/templates-main/templates.js</target>
<prefix>app/ext/radius</prefix>
</configuration>
</plugin>
<!-- JS/CSS Minification Plugin -->
<plugin>
<groupId>com.github.buckelieg</groupId>
<artifactId>minify-maven-plugin</artifactId>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<charset>UTF-8</charset>
<webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
<webappTargetDir>${project.build.directory}/classes</webappTargetDir>
<jsSourceDir>/</jsSourceDir>
<jsTargetDir>/</jsTargetDir>
<jsFinalFile>radius.js</jsFinalFile>
<jsSourceFiles>
<jsSourceFile>license.txt</jsSourceFile>
</jsSourceFiles>
<jsSourceIncludes>
<jsSourceInclude>**/*.js</jsSourceInclude>
</jsSourceIncludes>
<!-- Do not minify and include tests -->
<jsSourceExcludes>
<jsSourceExclude>**/*.test.js</jsSourceExclude>
</jsSourceExcludes>
<jsEngine>CLOSURE</jsEngine>
<!-- Disable warnings for JSDoc annotations -->
<closureWarningLevels>
<misplacedTypeAnnotation>OFF</misplacedTypeAnnotation>
<nonStandardJsDocs>OFF</nonStandardJsDocs>
</closureWarningLevels>
</configuration>
<goals>
<goal>minify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Guacamole Extension API -->
<dependency>
<groupId>org.apache.guacamole</groupId>
<artifactId>guacamole-ext</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>
<!-- Guava - Utility Library -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- Guice -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<!-- Java servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- JRadius Core Library -->
<dependency>
<groupId>net.jradius</groupId>
<artifactId>jradius-core</artifactId>
<version>1.1.5</version>
<exclusions>
<!-- Force consistent versions of Apache Commons libraries (see below) -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
<!-- Rely on Guacamole's existing use of logback rather than log4j -->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- JRadius Dictionary, for accessing packet attributes -->
<dependency>
<groupId>net.jradius</groupId>
<artifactId>jradius-dictionary</artifactId>
<version>1.1.5</version>
</dependency>
<!-- JRadius Extended, which inlcudes the SSL/TLS protocols -->
<dependency>
<groupId>net.jradius</groupId>
<artifactId>jradius-extended</artifactId>
<version>1.1.5</version>
</dependency>
<!-- Force single, specific versions of Apache Commons libraries
(multiple dependencies reference multiple versions of these). -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>dist</id>
<baseDirectory>${project.artifactId}-${project.version}</baseDirectory>
<!-- Output tar.gz -->
<formats>
<format>tar.gz</format>
</formats>
<!-- Include licenses and extension .jar -->
<fileSets>
<!-- Include licenses -->
<fileSet>
<outputDirectory></outputDirectory>
<directory>target/licenses</directory>
</fileSet>
<!-- Include extension .jar -->
<fileSet>
<directory>target</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@@ -0,0 +1,237 @@
/*
* 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;
import com.google.common.io.BaseEncoding;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Arrays;
import org.apache.guacamole.auth.radius.user.AuthenticatedUser;
import org.apache.guacamole.auth.radius.form.GuacamoleRadiusChallenge;
import org.apache.guacamole.auth.radius.form.RadiusStateField;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.form.Field;
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.net.auth.credentials.GuacamoleInsufficientCredentialsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.jradius.dictionary.Attr_State;
import net.jradius.dictionary.Attr_ReplyMessage;
import net.jradius.packet.RadiusPacket;
import net.jradius.packet.AccessAccept;
import net.jradius.packet.AccessChallenge;
import net.jradius.packet.AccessReject;
import net.jradius.packet.attribute.RadiusAttribute;
import org.apache.guacamole.form.PasswordField;
/**
* Service providing convenience functions for the RADIUS AuthenticationProvider
* implementation.
*/
public class AuthenticationProviderService {
/**
* Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class);
/**
* The name of the password field where the user will enter a response to
* the RADIUS challenge.
*/
private static final String CHALLENGE_RESPONSE_PARAM = "radiusChallenge";
/**
* Service for creating and managing connections to RADIUS servers.
*/
@Inject
private RadiusConnectionService radiusService;
/**
* Provider for AuthenticatedUser objects.
*/
@Inject
private Provider<AuthenticatedUser> authenticatedUserProvider;
/**
* Returns an object containing the challenge message and the expected
* credentials from a RADIUS challenge, or null if either state or reply
* attributes are missing from the challenge.
*
* @param challengePacket
* The AccessChallenge RadiusPacket received from the RADIUS
* server.
*
* @return
* A GuacamoleRadiusChallenge object that contains the challenge message
* sent by the RADIUS server and the expected credentials that should
* be requested of the user in order to continue authentication. One
* of the expected credentials *must* be the RADIUS state. If either
* state or the reply are missing from the challenge this method will
* return null.
*/
private GuacamoleRadiusChallenge getRadiusChallenge(RadiusPacket challengePacket) {
// Try to get the state attribute - if it's not there, we have a problem
RadiusAttribute stateAttr = challengePacket.findAttribute(Attr_State.TYPE);
if (stateAttr == null) {
logger.error("Something went wrong, state attribute not present.");
logger.debug("State Attribute turned up null, which shouldn't happen in AccessChallenge.");
return null;
}
// We need to get the reply message so we know what to ask the user
RadiusAttribute replyAttr = challengePacket.findAttribute(Attr_ReplyMessage.TYPE);
if (replyAttr == null) {
logger.error("No reply message received from the server.");
logger.debug("Expecting a Attr_ReplyMessage attribute on this packet, and did not get one.");
return null;
}
// We have the required attributes - convert to strings and then generate the additional login box/field
String replyMsg = replyAttr.getValue().toString();
String radiusState = BaseEncoding.base16().encode(stateAttr.getValue().getBytes());
Field radiusResponseField = new PasswordField(CHALLENGE_RESPONSE_PARAM);
Field radiusStateField = new RadiusStateField(radiusState);
// Return the GuacamoleRadiusChallenge object that has the state
// and the expected response.
return new GuacamoleRadiusChallenge(replyMsg,
new CredentialsInfo(Arrays.asList(radiusResponseField,
radiusStateField)));
}
/**
* Returns an AuthenticatedUser representing the user authenticated by the
* given credentials.
*
* @param credentials
* The credentials to use for authentication.
*
* @return
* An AuthenticatedUser representing the user authenticated by the
* given credentials.
*
* @throws GuacamoleException
* If an error occurs while authenticating the user, or if access is
* denied.
*/
public AuthenticatedUser authenticateUser(Credentials credentials)
throws GuacamoleException {
// Ignore anonymous users
if (credentials.getUsername() == null || credentials.getUsername().isEmpty())
return null;
// Password is required
if (credentials.getPassword() == null || credentials.getPassword().isEmpty())
return null;
// Grab HTTP request object and a response to a challenge.
String challengeResponse = credentials.getParameter(CHALLENGE_RESPONSE_PARAM);
// RadiusPacket object to store response from server.
RadiusPacket radPack;
// No challenge response, proceed with username/password authentication.
if (challengeResponse == null) {
try {
radPack = radiusService.authenticate(credentials.getUsername(),
credentials.getPassword(),
credentials.getRemoteAddress(),
null);
}
catch (GuacamoleException e) {
logger.error("Cannot configure RADIUS server: {}", e.getMessage());
logger.debug("Error configuring RADIUS server.", e);
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
}
}
// This is a response to a previous challenge, authenticate with that.
else {
try {
String stateString = credentials.getParameter(RadiusStateField.PARAMETER_NAME);
if (stateString == null) {
logger.warn("Expected state parameter was not present in challenge/response.");
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
}
byte[] stateBytes = BaseEncoding.base16().decode(stateString);
radPack = radiusService.sendChallengeResponse(credentials.getUsername(),
challengeResponse,
credentials.getRemoteAddress(),
stateBytes);
}
catch (IllegalArgumentException e) {
logger.warn("Illegal hexadecimal value while parsing RADIUS state string: {}", e.getMessage());
logger.debug("Encountered exception while attempting to parse the hexidecimal state value.", e);
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
}
catch (GuacamoleException e) {
logger.error("Cannot configure RADIUS server: {}", e.getMessage());
logger.debug("Error configuring RADIUS server.", e);
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
}
}
// No RadiusPacket is returned, we've encountered an error.
if (radPack == null) {
logger.debug("Nothing in the RADIUS packet.");
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
}
// Received AccessReject packet, login is denied.
else if (radPack instanceof AccessReject) {
logger.debug("Login has been rejected by RADIUS server.");
throw new GuacamoleInvalidCredentialsException("Authentication failed.", CredentialsInfo.USERNAME_PASSWORD);
}
// Received AccessAccept, authentication has succeeded
else if (radPack instanceof AccessAccept) {
AuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
authenticatedUser.init(credentials);
return authenticatedUser;
}
// Received AccessChallenge packet, more credentials required to complete authentication
else if (radPack instanceof AccessChallenge) {
GuacamoleRadiusChallenge challenge = getRadiusChallenge(radPack);
if (challenge == null)
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
throw new GuacamoleInsufficientCredentialsException(
challenge.getChallengeText(),
challenge.getExpectedCredentials());
}
// Something unanticipated happened, so panic and go back to login.
else {
logger.error("Unexpected failure authenticating with RADIUS server.");
throw new GuacamoleInvalidCredentialsException("Unknown error trying to authenticate.", CredentialsInfo.USERNAME_PASSWORD);
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.AbstractAuthenticationProvider;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.Credentials;
/**
* Allows users to be authenticated against an RADIUS server. Each user may have
* any number of authorized configurations. Authorized configurations may be
* shared.
*/
public class RadiusAuthenticationProvider extends AbstractAuthenticationProvider {
/**
* Injector which will manage the object graph of this authentication
* provider.
*/
private final Injector injector;
/**
* Creates a new RadiusAuthenticationProvider that authenticates users
* against an RADIUS service.
*
* @throws GuacamoleException
* If a required property is missing, or an error occurs while parsing
* a property.
*/
public RadiusAuthenticationProvider() throws GuacamoleException {
// Set up Guice injector.
injector = Guice.createInjector(
new RadiusAuthenticationProviderModule(this)
);
}
@Override
public String getIdentifier() {
return "radius";
}
@Override
public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException {
AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
return authProviderService.authenticateUser(credentials);
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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;
import com.google.inject.AbstractModule;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
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;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* Guice module which configures RADIUS-specific injections.
*/
public class RadiusAuthenticationProviderModule extends AbstractModule {
/**
* Guacamole server environment.
*/
private final Environment environment;
/**
* A reference to the RadiusAuthenticationProvider on behalf of which this
* module has configured injection.
*/
private final AuthenticationProvider authProvider;
/**
* Creates a new RADIUS authentication provider module which configures
* injection for the RadiusAuthenticationProvider.
*
* @param authProvider
* The AuthenticationProvider for which injection is being configured.
*
* @throws GuacamoleException
* If an error occurs while retrieving the Guacamole server
* environment.
*/
public RadiusAuthenticationProviderModule(AuthenticationProvider authProvider)
throws GuacamoleException {
// Get local environment
this.environment = LocalEnvironment.getInstance();
// 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.MSCHAP_V1
|| authProtocol == RadiusAuthenticationProtocol.MSCHAP_V2
|| innerProtocol == RadiusAuthenticationProtocol.MSCHAP_V1
|| innerProtocol == RadiusAuthenticationProtocol.MSCHAP_V2) {
try {
MessageDigest.getInstance("MD4");
}
catch (NoSuchAlgorithmException e) {
Security.addProvider(new BouncyCastleProvider());
}
}
// Store associated auth provider
this.authProvider = authProvider;
}
@Override
protected void configure() {
// Bind core implementations of guacamole-ext classes
bind(AuthenticationProvider.class).toInstance(authProvider);
bind(Environment.class).toInstance(environment);
// Bind RADIUS-specific services
bind(ConfigurationService.class);
bind(RadiusConnectionService.class);
}
}

View File

@@ -0,0 +1,315 @@
/*
* 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;
import com.google.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
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;
import net.jradius.dictionary.Attr_CleartextPassword;
import net.jradius.dictionary.Attr_ClientIPAddress;
import net.jradius.dictionary.Attr_NASIPAddress;
import net.jradius.dictionary.Attr_NASPortType;
import net.jradius.dictionary.Attr_ReplyMessage;
import net.jradius.dictionary.Attr_State;
import net.jradius.dictionary.Attr_UserName;
import net.jradius.dictionary.Attr_UserPassword;
import net.jradius.exception.RadiusException;
import net.jradius.packet.RadiusPacket;
import net.jradius.packet.AccessRequest;
import net.jradius.packet.attribute.AttributeList;
import net.jradius.client.auth.EAPTLSAuthenticator;
import net.jradius.client.auth.EAPTTLSAuthenticator;
import net.jradius.client.auth.RadiusAuthenticator;
import net.jradius.packet.attribute.AttributeFactory;
import net.jradius.packet.AccessChallenge;
import net.jradius.packet.RadiusResponse;
/**
* Service for creating and managing connections to RADIUS servers.
*/
public class RadiusConnectionService {
/**
* Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(RadiusConnectionService.class);
/**
* Service for retrieving RADIUS server configuration information.
*/
@Inject
private ConfigurationService confService;
/**
* Creates a new instance of RadiusClient, configured with parameters
* from guacamole.properties.
*
* @return
* A RadiusClient instance, configured with server, shared secret,
* ports, and timeout, as configured in guacamole.properties.
*
* @throws GuacamoleException
* If an error occurs while parsing guacamole.properties, or if the
* configuration of RadiusClient fails.
*/
private RadiusClient createRadiusConnection() throws GuacamoleException {
// Create the RADIUS client with the configuration parameters
try {
return new RadiusClient(InetAddress.getByName(confService.getRadiusServer()),
confService.getRadiusSharedSecret(),
confService.getRadiusAuthPort(),
confService.getRadiusAcctPort(),
confService.getRadiusTimeout());
}
catch (UnknownHostException e) {
logger.debug("Failed to resolve host.", e);
throw new GuacamoleServerException("Unable to resolve RADIUS server host.", e);
}
catch (IOException e) {
logger.debug("Failed to communicate with host.", e);
throw new GuacamoleServerException("Failed to communicate with RADIUS server.", e);
}
}
/**
* Creates a new instance of RadiusAuthenticator, configured with
* parameters specified within guacamole.properties.
*
* @return
* A new RadiusAuthenticator instance which has been configured
* with parameters from guacamole.properties.
*
* @throws GuacamoleException
* If the configuration cannot be read or the inner protocol is
* not configured when the client is set up for a tunneled
* RADIUS connection.
*/
private RadiusAuthenticator getRadiusAuthenticator() throws GuacamoleException {
RadiusAuthenticator radAuth = confService.getRadiusAuthProtocol().getAuthenticator();
// If we're using any of the TLS protocols, we need to configure them
if (radAuth instanceof EAPTLSAuthenticator) {
EAPTLSAuthenticator tlsAuth = (EAPTLSAuthenticator) radAuth;
// If provided, use the configured certificate authority for
// validating the connection to the RADIUS server
File caFile = confService.getRadiusCAFile();
if (caFile != null) {
tlsAuth.setCaFile(caFile.toString());
tlsAuth.setCaFileType(confService.getRadiusCAType());
String caPassword = confService.getRadiusCAPassword();
if (caPassword != null)
tlsAuth.setCaPassword(caPassword);
}
// Use configured password for unlocking the RADIUS private key,
// if specified
String keyPassword = confService.getRadiusKeyPassword();
if (keyPassword != null)
tlsAuth.setKeyPassword(keyPassword);
// Use configured RADIUS certificate and private key (always
// required for TLS-based protocols)
File keyFile = confService.getRadiusKeyFile();
tlsAuth.setKeyFile(keyFile.toString());
tlsAuth.setKeyFileType(confService.getRadiusKeyType());
tlsAuth.setTrustAll(confService.getRadiusTrustAll());
}
// If we're using EAP-TTLS, we need to define tunneled protocol
if (radAuth instanceof EAPTTLSAuthenticator) {
RadiusAuthenticationProtocol innerProtocol = confService.getRadiusEAPTTLSInnerProtocol();
((EAPTTLSAuthenticator)radAuth).setInnerProtocol(innerProtocol.JRADIUS_PROTOCOL_NAME);
}
return radAuth;
}
/**
* Authenticate to the RADIUS server using existing state and a response
*
* @param username
* The username for the authentication
*
* @param secret
* The secret, usually a password or challenge response, to send
* to authenticate to the RADIUS server.
*
* @param clientAddress
* The IP address of the client, if known, which will be set in as
* the RADIUS client address.
*
* @param state
* The previous state of the RADIUS connection
*
* @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 secret,
String clientAddress, byte[] state)
throws GuacamoleException {
// 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 secret wasn't passed, we quit
if (secret == null || secret.isEmpty()) {
logger.warn("Password/secret required for RADIUS authentication.");
return null;
}
// Create the RADIUS connection and set up the dictionary
RadiusClient radiusClient = createRadiusConnection();
AttributeFactory.loadAttributeDictionary("net.jradius.dictionary.AttributeDictionaryImpl");
// Set up the RadiusAuthenticator
RadiusAuthenticator radAuth = getRadiusAuthenticator();
// Add attributes to the connection and send the packet
try {
AttributeList radAttrs = new AttributeList();
radAttrs.add(new Attr_UserName(username));
radAttrs.add(new Attr_ClientIPAddress(InetAddress.getByName(clientAddress)));
radAttrs.add(new Attr_NASIPAddress(confService.getRadiusNasIp()));
radAttrs.add(new Attr_NASPortType(Attr_NASPortType.Virtual));
if (state != null && state.length > 0)
radAttrs.add(new Attr_State(state));
radAttrs.add(new Attr_UserPassword(secret));
radAttrs.add(new Attr_CleartextPassword(secret));
AccessRequest radAcc = new AccessRequest(radiusClient);
// EAP-TTLS tunnels protected attributes inside the TLS layer
if (radAuth instanceof EAPTTLSAuthenticator) {
radAuth.setUsername(new Attr_UserName(username));
((EAPTTLSAuthenticator)radAuth).setTunneledAttributes(radAttrs);
}
else
radAcc.addAttributes(radAttrs);
radAuth.setupRequest(radiusClient, radAcc);
radAuth.processRequest(radAcc);
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)) {
radAuth.processChallenge(radAcc, reply);
reply = radiusClient.sendReceive(radAcc,
confService.getRadiusMaxRetries());
}
return reply;
}
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);
return null;
}
catch (UnknownHostException e) {
logger.error("Could not resolve address: {}", e.getMessage());
logger.debug("Exception resolving host address.", e);
return null;
}
finally {
radiusClient.close();
}
}
/**
* Send a challenge response to the RADIUS server by validating the input and
* then sending it along to the authenticate method.
*
* @param username
* The username to send to the RADIUS server for authentication.
*
* @param response
* The response phrase to send to the RADIUS server in response to the
* challenge previously provided.
*
* @param clientAddress
* The IP address of the client, if known, which will be set in as
* the RADIUS client address.
*
* @param state
* The state data provided by the RADIUS server in order to continue
* the RADIUS conversation.
*
* @return
* A RadiusPacket containing the server's response to the authentication
* attempt.
*
* @throws GuacamoleException
* If an error is encountered trying to talk to the RADIUS server.
*/
public RadiusPacket sendChallengeResponse(String username, String response,
String clientAddress, byte[] state) throws GuacamoleException {
if (username == null || username.isEmpty()) {
logger.error("Challenge/response to RADIUS requires a username.");
return null;
}
if (state == null || state.length == 0) {
logger.error("Challenge/response to RADIUS requires a prior state.");
return null;
}
if (response == null || response.isEmpty()) {
logger.error("Challenge/response to RADIUS requires a response.");
return null;
}
return authenticate(username, response, clientAddress, state);
}
}

View File

@@ -0,0 +1,366 @@
/*
* 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 com.google.inject.Inject;
import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.environment.Environment;
/**
* Service for retrieving configuration information regarding the RADIUS server.
*/
public class ConfigurationService {
/**
* The Guacamole server environment.
*/
@Inject
private Environment environment;
/**
* Returns the hostname of the RADIUS server as configured with
* guacamole.properties. By default, this will be "localhost".
*
* @return
* The hostname of the RADIUS server, as configured with
* guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getRadiusServer() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_HOSTNAME,
"localhost"
);
}
/**
* Returns the UDP port that will be used to communicate authentication
* and authorization information to the RADIUS server, as configured in
* guacamole.properties. By default this will be 1812.
*
* @return
* The authentication port of the RADIUS server, as configured with
* guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public int getRadiusAuthPort() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_AUTH_PORT,
1812
);
}
/**
* Returns the UDP port that will be used to communicate accounting
* information to the RADIUS server, as configured in
* guacamole.properties. The default is 1813.
*
* @return
* The accouting port of the RADIUS server, as configured with
* guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public int getRadiusAcctPort() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_ACCT_PORT,
1813
);
}
/**
* Returns the shared secret used to communicate with the RADIUS server,
* as configured in guacamole.properties. This must match the value
* in the RADIUS server configuration.
*
* @return
* The shared secret of the RADIUS server, as configured with
* guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getRadiusSharedSecret() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_SHARED_SECRET
);
}
/**
* Returns the authentication protocol Guacamole should use when
* communicating with the RADIUS server, as configured in
* guacamole.properties. This must match the configuration
* of the RADIUS server, so that the RADIUS server and Guacamole
* client are "speaking the same language."
*
* @return
* The authentication protocol of the RADIUS server,
* from guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public RadiusAuthenticationProtocol getRadiusAuthProtocol()
throws GuacamoleException {
return environment.getRequiredProperty(
RadiusGuacamoleProperties.RADIUS_AUTH_PROTOCOL
);
}
/**
* Returns the maximum number of retries for connecting to the RADIUS server
* from guacamole.properties. The default number of retries is 5.
*
* @return
* The number of retries for connection to the RADIUS server,
* from guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public int getRadiusMaxRetries() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_MAX_RETRIES,
5
);
}
/**
* Returns the timeout, in seconds, for connecting to the RADIUS server
* from guacamole.properties. The default timeout is 60 seconds.
*
* @return
* The timeout, in seconds, 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,
60
);
}
/**
* Returns the CA file for validating certificates for encrypted
* connections to the RADIUS server, as configured in
* guacamole.properties.
*
* @return
* The file name for the CA file for validating
* RADIUS server certificates
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public File getRadiusCAFile() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_CA_FILE,
new File(environment.getGuacamoleHome(), "ca.crt")
);
}
/**
* Returns the key file for the client for creating encrypted
* connections to RADIUS servers as specified in
* guacamole.properties. By default a file called radius.pem
* is used.
*
* @return
* The file name for the client certificate/key pair
* for making encrypted RADIUS connections.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public File getRadiusKeyFile() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_KEY_FILE,
new File(environment.getGuacamoleHome(), "radius.key")
);
}
/**
* Returns the password for the CA file, if it is
* password-protected, as configured in guacamole.properties.
*
* @return
* The password for the CA file
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getRadiusCAPassword() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_CA_PASSWORD
);
}
/**
* Returns the type of store that the CA file represents
* so that it can be correctly processed by the RADIUS
* library, as configured in guacamole.properties. By
* default the pem type is used.
*
* @return
* The type of store that the CA file is encoded
* as, as configured in guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getRadiusCAType() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_CA_TYPE,
"pem"
);
}
/**
* Returns the password for the key file, if it is
* password-protected, as configured in guacamole.properties.
*
* @return
* The password for the key file
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getRadiusKeyPassword() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_KEY_PASSWORD
);
}
/**
* Returns the type of store that the key file represents
* so that it can be correctly processed by the RADIUS
* library, as configured in guacamole.properties. By
* default the pem type is used.
*
* @return
* The type of store that the key file is encoded
* as, as configured in guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getRadiusKeyType() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_KEY_TYPE,
"pem"
);
}
/**
* Returns the boolean value of whether or not the
* RADIUS library should trust all server certificates
* or should validate them against known CA certificates,
* as configured in guacamole.properties. By default
* this is false, indicating that server certificates
* must be validated against a known good CA.
*
* @return
* True if the RADIUS client should trust all
* server certificates; false if it should
* validate against known good CA certificates.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public Boolean getRadiusTrustAll() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_TRUST_ALL,
false
);
}
/**
* Returns the tunneled protocol that RADIUS should use
* when the authentication protocol is set to EAP-TTLS, as
* configured in the guacamole.properties file.
*
* @return
* The tunneled protocol that should be used inside
* an EAP-TTLS RADIUS connection.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed, or if EAP-TTLS is specified
* as the inner protocol.
*/
public RadiusAuthenticationProtocol getRadiusEAPTTLSInnerProtocol()
throws GuacamoleException {
RadiusAuthenticationProtocol authProtocol = environment.getRequiredProperty(
RadiusGuacamoleProperties.RADIUS_EAP_TTLS_INNER_PROTOCOL
);
if (authProtocol == RadiusAuthenticationProtocol.EAP_TTLS)
throw new GuacamoleServerException("Invalid inner protocol specified for EAP-TTLS.");
return authProtocol;
}
/**
* Returns the InetAddress containing the NAS IP address that should be
* used to identify this RADIUS client when communicating with the RADIUS
* server. If no explicit configuration of this property is defined
* in guacamole.properties, it falls back to attempting to determine the
* IP address using Java's built-in mechanisms for querying local addresses.
*
* @return
* The InetAddress corresponding to the NAS IP address specified in
* guacamole.properties, or the IP determined by querying the address
* of the server on which Guacamole is running.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed, or if the InetAddress
* for the NAS IP cannot be read or determined from the system.
*/
public InetAddress getRadiusNasIp() throws GuacamoleException {
try {
String nasIpStr = environment.getProperty(RadiusGuacamoleProperties.RADIUS_NAS_IP);
// If property is specified and non-empty, attempt to return converted address.
if (nasIpStr != null && !nasIpStr.isEmpty())
return InetAddress.getByName(nasIpStr);
// By default, return the address of the server.
return InetAddress.getLocalHost();
}
catch (UnknownHostException e) {
throw new GuacamoleServerException("Unknown host specified for NAS IP.", e);
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* 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 net.jradius.client.RadiusClient;
import net.jradius.client.auth.CHAPAuthenticator;
import net.jradius.client.auth.EAPMD5Authenticator;
import net.jradius.client.auth.EAPTLSAuthenticator;
import net.jradius.client.auth.EAPTTLSAuthenticator;
import net.jradius.client.auth.MSCHAPv1Authenticator;
import net.jradius.client.auth.MSCHAPv2Authenticator;
import net.jradius.client.auth.PAPAuthenticator;
import net.jradius.client.auth.RadiusAuthenticator;
import org.apache.guacamole.properties.EnumGuacamoleProperty.PropertyValue;
/**
* This enum represents supported RADIUS authentication protocols for
* the guacamole-auth-radius extension.
*/
public enum RadiusAuthenticationProtocol {
/**
* Password Authentication Protocol (PAP).
*/
@PropertyValue("pap")
PAP(PAPAuthenticator.NAME),
/**
* Challenge-Handshake Authentication Protocol (CHAP).
*/
@PropertyValue("chap")
CHAP(CHAPAuthenticator.NAME),
/**
* Microsoft implementation of CHAP, Version 1 (MS-CHAPv1).
*/
@PropertyValue("mschapv1")
MSCHAP_V1(MSCHAPv1Authenticator.NAME),
/**
* Microsoft implementation of CHAP, Version 2 (MS-CHAPv2).
*/
@PropertyValue("mschapv2")
MSCHAP_V2(MSCHAPv2Authenticator.NAME),
/**
* Extensible Authentication Protocol (EAP) with MD5 Hashing (EAP-MD5).
*/
@PropertyValue("eap-md5")
EAP_MD5(EAPMD5Authenticator.NAME),
/**
* Extensible Authentication Protocol (EAP) with TLS encryption (EAP-TLS).
*/
@PropertyValue("eap-tls")
EAP_TLS(EAPTLSAuthenticator.NAME),
/**
* Extensible Authentication Protocol (EAP) with Tunneled TLS (EAP-TTLS).
*/
@PropertyValue("eap-ttls")
EAP_TTLS(EAPTTLSAuthenticator.NAME);
/**
* The unique name of the JRadius {@link RadiusAuthenticator} that
* implements this protocol.
*/
public final String JRADIUS_PROTOCOL_NAME;
/**
* Creates a new RadiusAuthenticationProtocol associated with the given
* JRadius protocol name.
*
* @param protocolName
* The unique name of the JRadius {@link RadiusAuthenticator} that
* implements this protocol.
*/
RadiusAuthenticationProtocol(String protocolName) {
this.JRADIUS_PROTOCOL_NAME = protocolName;
}
/**
* Returns a new instance of the JRadius {@link RadiusAuthenticator} that
* implements this protocol. This function will never return null.
*
* @return
* A new instance of the JRadius {@link RadiusAuthenticator} that
* implements this protocol.
*
* @throws IllegalStateException
* If a bug within the JRadius library prevents retrieval of the
* authenticator for a protocol that is known to be supported.
*/
public RadiusAuthenticator getAuthenticator() throws IllegalStateException {
// As we are using JRadius' own NAME constants for retrieving
// authenticator instances, the retrieval operation should always
// succeed except in the case of a bug within the JRadius library
RadiusAuthenticator authenticator = RadiusClient.getAuthProtocol(JRADIUS_PROTOCOL_NAME);
if (authenticator == null)
throw new IllegalStateException(String.format("JRadius failed "
+"to locate its own support for protocol \"%s\". This is "
+ "likely a bug in the JRadius library.",
JRADIUS_PROTOCOL_NAME));
return authenticator;
}
}

View File

@@ -0,0 +1,208 @@
/*
* 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.properties.BooleanGuacamoleProperty;
import org.apache.guacamole.properties.EnumGuacamoleProperty;
import org.apache.guacamole.properties.FileGuacamoleProperty;
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
import org.apache.guacamole.properties.StringGuacamoleProperty;
/**
* Provides properties required for use of the RADIUS authentication provider.
* These properties will be read from guacamole.properties when the RADIUS
* authentication provider is used.
*/
public class RadiusGuacamoleProperties {
/**
* This class should not be instantiated.
*/
private RadiusGuacamoleProperties() {}
/**
* The port on the RADIUS server to connect to when authenticating users.
*/
public static final IntegerGuacamoleProperty RADIUS_AUTH_PORT = new IntegerGuacamoleProperty() {
@Override
public String getName() { return "radius-auth-port"; }
};
/**
* The port on the server to connect to when performing RADIUS accounting.
*/
public static final IntegerGuacamoleProperty RADIUS_ACCT_PORT = new IntegerGuacamoleProperty() {
@Override
public String getName() { return "radius-acct-port"; }
};
/**
* The hostname or IP address of the RADIUS server to connect to when authenticating users.
*/
public static final StringGuacamoleProperty RADIUS_HOSTNAME = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-hostname"; }
};
/**
* The shared secret to use when connecting to the RADIUS server.
*/
public static final StringGuacamoleProperty RADIUS_SHARED_SECRET = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-shared-secret"; }
};
/**
* The authentication protocol of the RADIUS server to connect to when authenticating users.
*/
public static final EnumGuacamoleProperty<RadiusAuthenticationProtocol> RADIUS_AUTH_PROTOCOL =
new EnumGuacamoleProperty<RadiusAuthenticationProtocol>(RadiusAuthenticationProtocol.class) {
@Override
public String getName() { return "radius-auth-protocol"; }
};
/**
* The maximum number of retries when attempting a RADIUS packet transaction.
*/
public static final IntegerGuacamoleProperty RADIUS_MAX_RETRIES = new IntegerGuacamoleProperty() {
@Override
public String getName() { return "radius-max-retries"; }
};
/**
* The network timeout, in seconds, when attempting a RADIUS packet transaction.
*/
public static final IntegerGuacamoleProperty RADIUS_TIMEOUT = new IntegerGuacamoleProperty() {
@Override
public String getName() { return "radius-timeout"; }
};
/**
* The CA file to use to validate RADIUS server certificates.
*/
public static final FileGuacamoleProperty RADIUS_CA_FILE = new FileGuacamoleProperty() {
@Override
public String getName() { return "radius-ca-file"; }
};
/**
* The type of file the RADIUS CA file is (PEM, PKCS12, DER).
*/
public static final StringGuacamoleProperty RADIUS_CA_TYPE = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-ca-type"; }
};
/**
* The password for the CA file.
*/
public static final StringGuacamoleProperty RADIUS_CA_PASSWORD = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-ca-password"; }
};
/**
* The file that stores the key/certificate pair to use for the RADIUS client connection.
*/
public static final FileGuacamoleProperty RADIUS_KEY_FILE = new FileGuacamoleProperty() {
@Override
public String getName() { return "radius-key-file"; }
};
/**
* The type of file the RADIUS key file is (PEM, PKCS12, DER).
*/
public static final StringGuacamoleProperty RADIUS_KEY_TYPE = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-key-type"; }
};
/**
* The password for the key file.
*/
public static final StringGuacamoleProperty RADIUS_KEY_PASSWORD = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-key-password"; }
};
/**
* Whether or not to trust all RADIUS server certificates.
*/
public static final BooleanGuacamoleProperty RADIUS_TRUST_ALL = new BooleanGuacamoleProperty() {
@Override
public String getName() { return "radius-trust-all"; }
};
/**
* The tunneled protocol to use inside a RADIUS EAP-TTLS connection.
*/
public static final EnumGuacamoleProperty<RadiusAuthenticationProtocol> RADIUS_EAP_TTLS_INNER_PROTOCOL =
new EnumGuacamoleProperty<RadiusAuthenticationProtocol>(RadiusAuthenticationProtocol.class) {
@Override
public String getName() { return "radius-eap-ttls-inner-protocol"; }
};
/**
* Manually configure the NAS IP address that the RADIUS client will pass
* to the server when requesting authentication. Normally this is automatically
* determined by gathering the IP address of the system on which Guacamole
* is running; however, there are certain scenarios (as in running in a
* Docker container) where specifying this manually may be useful.
*/
public static final StringGuacamoleProperty RADIUS_NAS_IP = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-nas-ip"; }
};
}

View File

@@ -0,0 +1,77 @@
/*
* 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.form;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
/**
* Stores the RADIUS challenge message and expected credentials in a single
* object.
*/
public class GuacamoleRadiusChallenge {
/**
* The challenge text sent by the RADIUS server.
*/
private final String challengeText;
/**
* The expected credentials that need to be provided to satisfy the
* RADIUS authentication challenge.
*/
private final CredentialsInfo expectedCredentials;
/**
* Creates a new GuacamoleRadiusChallenge object with the provided
* challenge message and expected credentials.
*
* @param challengeText
* The challenge message sent by the RADIUS server.
*
* @param expectedCredentials
* The credentials required to complete the challenge.
*/
public GuacamoleRadiusChallenge(String challengeText,
CredentialsInfo expectedCredentials) {
this.challengeText = challengeText;
this.expectedCredentials = expectedCredentials;
}
/**
* Returns the challenge message provided by the RADIUS server.
*
* @return
* The challenge message provided by the RADIUS server.
*/
public String getChallengeText() {
return challengeText;
}
/**
* Returns the credentials required to satisfy the RADIUS challenge.
*
* @return
* The credentials required to satisfy the RADIUS challenge.
*/
public CredentialsInfo getExpectedCredentials() {
return expectedCredentials;
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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.form;
import org.apache.guacamole.form.Field;
/**
* The invisible field that stores the state of the RADIUS
* connection. The state is simply a placeholder that helps
* the client and server pick back up the conversation
* at the correct spot during challenge/response.
*/
public class RadiusStateField extends Field {
/**
* The parameter returned by the RADIUS state.
*/
public static final String PARAMETER_NAME = "guac-radius-state";
/**
* The type of field to initialize for the state.
*/
private static final String RADIUS_FIELD_TYPE = "GUAC_RADIUS_STATE";
/**
* The state of the connection passed by the previous RADIUS attempt.
*/
private final String radiusState;
/**
* Initialize the field with the state returned by the RADIUS server.
*
* @param radiusState
* The state returned by the RADIUS server.
*/
public RadiusStateField(String radiusState) {
super(PARAMETER_NAME, RADIUS_FIELD_TYPE);
this.radiusState = radiusState;
}
/**
* Get the state provided by the RADIUS server.
*
* @return
* The state provided by the RADIUS server.
*/
public String getRadiusState() {
return radiusState;
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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.user;
import com.google.inject.Inject;
import org.apache.guacamole.net.auth.AbstractAuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials;
/**
* An RADIUS-specific implementation of AuthenticatedUser, associating a
* particular set of credentials with the RADIUS authentication provider.
*/
public class AuthenticatedUser extends AbstractAuthenticatedUser {
/**
* Reference to the authentication provider associated with this
* authenticated user.
*/
@Inject
private AuthenticationProvider authProvider;
/**
* The credentials provided when this user was authenticated.
*/
private Credentials credentials;
/**
* Initializes this AuthenticatedUser using the given credentials.
*
* @param credentials
* The credentials provided when this user was authenticated.
*/
public void init(Credentials credentials) {
this.credentials = credentials;
setIdentifier(credentials.getUsername());
}
@Override
public AuthenticationProvider getAuthenticationProvider() {
return authProvider;
}
@Override
public Credentials getCredentials() {
return credentials;
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.
*/
/**
* Config block which registers Radius-specific field types.
*/
angular.module('guacRadius').config(['formServiceProvider',
function guacRadiusConfig(formServiceProvider) {
// Define the hidden field for the RADIUS state
formServiceProvider.registerFieldType('GUAC_RADIUS_STATE', {
module : 'guacRadius',
controller : 'radiusStateController',
templateUrl : 'app/ext/radius/templates/radiusStateField.html'
});
}]);

View File

@@ -0,0 +1,31 @@
/*
* 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.
*/
/**
* Controller for the "GUAC_RADIUS_STATE" field which is used to pass
* the RADIUS server state to maintain the session with the RADIUS
* server.
*/
angular.module('guacRadius').controller('radiusStateController', ['$scope', '$injector',
function radiusStateController($scope, $injector) {
// Populate the hidden field for the connection state
$scope.model = $scope.field.radiusState;
}]);

View File

@@ -0,0 +1,29 @@
{
"guacamoleVersion" : "1.6.0",
"name" : "RADIUS Authentication Backend",
"namespace" : "radius",
"authProviders" : [
"org.apache.guacamole.auth.radius.RadiusAuthenticationProvider"
],
"translations" : [
"translations/ca.json",
"translations/de.json",
"translations/en.json",
"translations/ja.json",
"translations/ru.json",
"translations/zh.json"
],
"js" : [
"radius.min.js"
],
"resources" : {
"templates/radiusStateField.html" : "text/html"
}
}

View File

@@ -0,0 +1,18 @@
/*
* 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.
*/

View File

@@ -0,0 +1,29 @@
/*
* 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.
*/
/**
* Module which provides handling for RADIUS challenge-response
* authentication.
*/
angular.module('guacRadius', [
'form'
]);
// Ensure the guacRadius module is loaded along with the rest of the app
angular.module('index').requires.push('guacRadius');

View File

@@ -0,0 +1 @@
<input type="hidden" ng-model="model">

View File

@@ -0,0 +1,12 @@
{
"DATA_SOURCE_RADIUS" : {
"NAME" : "RADIUS Backend"
},
"LOGIN" : {
"FIELD_HEADER_GUAC_RADIUS_STATE" : "",
"FIELD_HEADER_RADIUSCHALLENGE" : ""
}
}

View File

@@ -0,0 +1,13 @@
{
"DATA_SOURCE_RADIUS" : {
"NAME" : "RADIUS Backend"
},
"LOGIN" : {
"FIELD_HEADER_GUAC_RADIUS_CHALLENGE_RESPONSE" : "",
"FIELD_HEADER_GUAC_RADIUS_STATE" : "",
"INFO_RADIUS_ADDL_REQUIRED" : "Bitte zusätzliche Logindaten eingeben."
}
}

View File

@@ -0,0 +1,12 @@
{
"DATA_SOURCE_RADIUS" : {
"NAME" : "RADIUS Backend"
},
"LOGIN" : {
"FIELD_HEADER_GUAC_RADIUS_STATE" : "",
"FIELD_HEADER_RADIUSCHALLENGE" : ""
}
}

View File

@@ -0,0 +1,7 @@
{
"LOGIN" : {
"INFO_RADIUS_ADDL_REQUIRED" : "追加の認証情報を入力してください"
}
}

View File

@@ -0,0 +1,7 @@
{
"DATA_SOURCE_RADIUS" : {
"NAME" : "Бэкенд RADIUS"
}
}

View File

@@ -0,0 +1,12 @@
{
"DATA_SOURCE_RADIUS" : {
"NAME" : "RADIUS后端"
},
"LOGIN" : {
"FIELD_HEADER_GUAC_RADIUS_STATE" : "",
"FIELD_HEADER_RADIUSCHALLENGE" : ""
}
}