Add .gitignore and .ratignore files for various directories
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
3
extensions/guacamole-auth-radius/.gitignore
vendored
Normal file
3
extensions/guacamole-auth-radius/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
src/main/resources/generated/
|
||||
target/
|
||||
*~
|
0
extensions/guacamole-auth-radius/.ratignore
Normal file
0
extensions/guacamole-auth-radius/.ratignore
Normal file
201
extensions/guacamole-auth-radius/pom.xml
Normal file
201
extensions/guacamole-auth-radius/pom.xml
Normal 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>
|
53
extensions/guacamole-auth-radius/src/main/assembly/dist.xml
Normal file
53
extensions/guacamole-auth-radius/src/main/assembly/dist.xml
Normal 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>
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -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"; }
|
||||
|
||||
};
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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'
|
||||
});
|
||||
|
||||
}]);
|
@@ -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;
|
||||
|
||||
}]);
|
@@ -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"
|
||||
}
|
||||
|
||||
}
|
@@ -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.
|
||||
*/
|
@@ -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');
|
@@ -0,0 +1 @@
|
||||
<input type="hidden" ng-model="model">
|
@@ -0,0 +1,12 @@
|
||||
{
|
||||
|
||||
"DATA_SOURCE_RADIUS" : {
|
||||
"NAME" : "RADIUS Backend"
|
||||
},
|
||||
|
||||
"LOGIN" : {
|
||||
"FIELD_HEADER_GUAC_RADIUS_STATE" : "",
|
||||
"FIELD_HEADER_RADIUSCHALLENGE" : ""
|
||||
}
|
||||
|
||||
}
|
@@ -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."
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
{
|
||||
|
||||
"DATA_SOURCE_RADIUS" : {
|
||||
"NAME" : "RADIUS Backend"
|
||||
},
|
||||
|
||||
"LOGIN" : {
|
||||
"FIELD_HEADER_GUAC_RADIUS_STATE" : "",
|
||||
"FIELD_HEADER_RADIUSCHALLENGE" : ""
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
|
||||
"LOGIN" : {
|
||||
"INFO_RADIUS_ADDL_REQUIRED" : "追加の認証情報を入力してください"
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
|
||||
"DATA_SOURCE_RADIUS" : {
|
||||
"NAME" : "Бэкенд RADIUS"
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
{
|
||||
|
||||
"DATA_SOURCE_RADIUS" : {
|
||||
"NAME" : "RADIUS后端"
|
||||
},
|
||||
|
||||
"LOGIN" : {
|
||||
"FIELD_HEADER_GUAC_RADIUS_STATE" : "",
|
||||
"FIELD_HEADER_RADIUSCHALLENGE" : ""
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user