GUACAMOLE-197: Initial code for the guacamole-auth-radius authentication module.

This commit is contained in:
Nick Couchman
2017-02-05 15:02:10 -05:00
committed by Nick Couchman
parent 9d587496b0
commit d9d5573aa4
28 changed files with 2196 additions and 0 deletions

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>src/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,147 @@
/*
* 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 com.google.inject.Provider;
import java.util.Collections;
import org.apache.guacamole.auth.radius.user.AuthenticatedUser;
import org.apache.guacamole.auth.radius.form.RadiusChallengeResponseField;
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.exception.UnknownAttributeException;
import net.jradius.packet.RadiusPacket;
import net.jradius.packet.AccessAccept;
import net.jradius.packet.AccessChallenge;
import net.jradius.packet.AccessReject;
import net.jradius.packet.AccessRequest;
import net.jradius.packet.AccessResponse;
import net.jradius.packet.attribute.RadiusAttribute;
/**
* Service providing convenience functions for the RADIUS AuthenticationProvider
* implementation.
*
* @author Michael Jumper
*/
public class AuthenticationProviderService {
/**
* Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class);
/**
* Service for creating and managing connections to RADIUS servers.
*/
@Inject
private RadiusConnectionService radiusService;
/**
* Service for retrieving RADIUS server configuration information.
*/
@Inject
private ConfigurationService confService;
/**
* Provider for AuthenticatedUser objects.
*/
@Inject
private Provider<AuthenticatedUser> authenticatedUserProvider;
/**
* 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 {
// Attempt bind
RadiusPacket radPack;
try {
radPack = radiusService.authenticate(credentials.getUsername(),
credentials.getPassword());
}
catch (GuacamoleException e) {
logger.error("Cannot configure RADIUS server: {}", e.getMessage());
logger.debug("Error configuring RADIUS server.", e);
radPack = null;
}
// If configure fails, permission to login is denied
if(radPack == null) {
logger.debug("Nothing in the RADIUS packet.");
throw new GuacamoleInvalidCredentialsException("Permission denied.", CredentialsInfo.USERNAME_PASSWORD);
}
else if(radPack instanceof AccessReject) {
logger.debug("Login has been rejected by RADIUS server.");
throw new GuacamoleInvalidCredentialsException("Permission denied.", CredentialsInfo.USERNAME_PASSWORD);
}
else if(radPack instanceof AccessChallenge) {
try {
String replyMsg = radPack.getAttributeValue("Reply-Message").toString();
String radState = radPack.getAttributeValue("State").toString();
logger.debug("RADIUS sent challenge response: {}", replyMsg);
logger.debug("RADIUS sent state: {}", radState);
Field radiusResponseField = new RadiusChallengeResponseField(replyMsg, radState);
CredentialsInfo responseCredentials = new CredentialsInfo(Collections.singletonList(radiusResponseField));
throw new GuacamoleInsufficientCredentialsException("LOGIN.INFO_RADIUS_ADDL_REQUIRED", responseCredentials);
}
catch(UnknownAttributeException e) {
logger.error("Error in talks with RADIUS server.");
logger.debug("RADIUS challenged by didn't provide right attributes.");
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
}
}
else if(radPack instanceof AccessAccept) {
try {
// Return AuthenticatedUser if bind succeeds
AuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
authenticatedUser.init(credentials);
return authenticatedUser;
}
finally {
radiusService.disconnect();
}
}
else
throw new GuacamoleInvalidCredentialsException("Unknown error trying to authenticate.", CredentialsInfo.USERNAME_PASSWORD);
}
}

View File

@@ -0,0 +1,145 @@
/*
* 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.util.Collections;
import java.util.List;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.Environment;
/**
* Service for retrieving configuration information regarding the RADIUS server.
*
* @author Michael Jumper
*/
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_SERVER,
"localhost"
);
}
/**
* Returns the authentication port of the RADIUS server configured with
* guacamole.properties.
*
* @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 accounting port of the RADIUS server configured with
* guacamole.properties.
*
* @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 of the RADIUS server configured with
* guacamole.properties.
*
* @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,
null
);
}
/**
* Returns the authentication protocol of the RADIUS server
* from guacamole.properties.
*
* @return
* The authentication protocol of the RADIUS server,
* from guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public String getRadiusAuthProtocol() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_AUTH_PROTOCOL,
null
);
}
public int getRadiusRetries() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_RETRIES,
5
);
}
public int getRadiusTimeout() throws GuacamoleException {
return environment.getProperty(
RadiusGuacamoleProperties.RADIUS_TIMEOUT,
60
);
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.UserContext;
/**
* Allows users to be authenticated against an RADIUS server. Each user may have
* any number of authorized configurations. Authorized configurations may be
* shared.
*
* @author Michael Jumper
*/
public class RadiusAuthenticationProvider implements AuthenticationProvider {
/**
* 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);
}
@Override
public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
Credentials credentials) throws GuacamoleException {
return authenticatedUser;
}
@Override
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
throws GuacamoleException {
return null;
}
@Override
public UserContext updateUserContext(UserContext context,
AuthenticatedUser authenticatedUser,
Credentials credentials) throws GuacamoleException {
return context;
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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 org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.environment.LocalEnvironment;
import org.apache.guacamole.net.auth.AuthenticationProvider;
/**
* Guice module which configures RADIUS-specific injections.
*
* @author Michael Jumper
*/
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 = new LocalEnvironment();
// 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,233 @@
/*
* 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.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.jradius.client.RadiusClient;
import net.jradius.exception.RadiusException;
import net.jradius.packet.RadiusPacket;
import net.jradius.packet.AccessRequest;
import net.jradius.dictionary.*;
import net.jradius.packet.attribute.AttributeList;
import net.jradius.client.auth.RadiusAuthenticator;
import net.jradius.packet.attribute.AttributeFactory;
/**
* Service for creating and managing connections to RADIUS servers.
*
* @author Michael Jumper
*/
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;
/**
* The RADIUS client;
*/
private RadiusClient radiusClient;
/**
* Creates a new instance of RadiusConnection, configured as required to use
* whichever encryption method is requested within guacamole.properties.
*
* @return
* A new RadiusConnection instance which has already been configured to
* use the encryption method requested within guacamole.properties.
*
* @throws GuacamoleException
* If an error occurs while parsing guacamole.properties, or if the
* requested encryption method is actually not implemented (a bug).
*/
private void createRadiusConnection() {
/*
// Map encryption method to proper connection and socket factory
EncryptionMethod encryptionMethod = confService.getEncryptionMethod();
switch (encryptionMethod) {
// Unencrypted RADIUS connection
case NONE:
logger.debug("Connection to RADIUS server without encryption.");
radiusClient = new RadiusClient();
return radiusClient;
// Radius over TTLS (EAP-TTLS)
case TTLS:
logger.debug("Connecting to RADIUS server using TTLS.");
radiusClient = new RadiusClient();
return radiusClient;
// We default to unencrypted connections.
default:
logger.debug("Defaulting an unencrypted RADIUS connection.");
radiusClient = new RadiusClient();
return radiusClient;
}
*/
try {
radiusClient = new RadiusClient(InetAddress.getByName(confService.getRadiusServer()),
confService.getRadiusSharedSecret(),
confService.getRadiusAuthPort(),
confService.getRadiusAcctPort(),
confService.getRadiusTimeout());
}
catch (GuacamoleException e) {
logger.error("Unable to initialize RADIUS client: {}", e.getMessage());
logger.debug("Failed to init RADIUS client.", e);
return;
}
catch (UnknownHostException e) {
logger.error("Unable to resolve host: {}", e.getMessage());
logger.debug("Failed to resolve host.", e);
return;
}
catch (IOException e) {
logger.error("Unable to communicate with host: {}", e.getMessage());
logger.debug("Failed to communicate with host.", e);
return;
}
}
public RadiusPacket authenticate(String username, String password)
throws GuacamoleException {
createRadiusConnection();
AttributeFactory.loadAttributeDictionary("net.jradius.dictionary.AttributeDictionaryImpl");
if(radiusClient == null)
return null;
if(username == null || username.isEmpty()) {
logger.warn("Anonymous access not allowed with RADIUS client.");
return null;
}
if(password == null || password.isEmpty()) {
logger.warn("Password required for RADIUS authentication.");
return null;
}
RadiusAuthenticator radAuth = radiusClient.getAuthProtocol(confService.getRadiusAuthProtocol());
if(radAuth == null)
throw new GuacamoleException("Unknown RADIUS authentication protocol.");
try {
AttributeList radAttrs = new AttributeList();
radAttrs.add(new Attr_UserName(username));
radAttrs.add(new Attr_UserPassword(password));
AccessRequest radAcc = new AccessRequest(radiusClient, radAttrs);
logger.debug("Sending authentication request to radius server for user {}.", username);
radAuth.setupRequest(radiusClient, radAcc);
radAuth.processRequest(radAcc);
return radiusClient.sendReceive(radAcc, confService.getRadiusRetries());
}
catch (RadiusException e) {
logger.error("Unable to complete authentication.", e.getMessage());
logger.debug("Authentication with RADIUS failed.", e);
return null;
}
catch (NoSuchAlgorithmException e) {
logger.error("No such RADIUS algorithm: {}", e.getMessage());
logger.debug("Unknown RADIUS algorithm.", e);
return null;
}
}
public RadiusPacket authenticate(String username, String state, String response)
throws GuacamoleException {
createRadiusConnection();
AttributeFactory.loadAttributeDictionary("net.jradius.dictionary.AttributeDictionaryImpl");
if(radiusClient == null)
return null;
if(username == null || username.isEmpty()) {
logger.warn("Anonymous access not allowed with RADIUS client.");
return null;
}
if(state == null || state.isEmpty()) {
logger.warn("This method needs a previous RADIUS state to respond to.");
return null;
}
if(response == null || response.isEmpty()) {
logger.warn("Response required for RADIUS authentication.");
return null;
}
RadiusAuthenticator radAuth = radiusClient.getAuthProtocol(confService.getRadiusAuthProtocol());
if(radAuth == null)
throw new GuacamoleException("Unknown RADIUS authentication protocol.");
try {
AttributeList radAttrs = new AttributeList();
radAttrs.add(new Attr_UserName(username));
radAttrs.add(new Attr_State(state));
radAttrs.add(new Attr_UserPassword(response));
AccessRequest radAcc = new AccessRequest(radiusClient, radAttrs);
logger.debug("Sending authentication response to radius server for user {}.", username);
radAuth.setupRequest(radiusClient, radAcc);
radAuth.processRequest(radAcc);
return radiusClient.sendReceive(radAcc, confService.getRadiusRetries());
}
catch (RadiusException e) {
logger.error("Unable to complete authentication.", e.getMessage());
logger.debug("Authentication with RADIUS failed.", e);
return null;
}
catch (NoSuchAlgorithmException e) {
logger.error("No such RADIUS algorithm: {}", e.getMessage());
logger.debug("Unknown RADIUS algorithm.", e);
return null;
}
}
/**
* Disconnects the given RADIUS connection, logging any failure to do so
* appropriately.
*
* @param radiusConnection
* The RADIUS connection to disconnect.
*/
public void disconnect() {
radiusClient.close();
}
}

View File

@@ -0,0 +1,112 @@
/*
* 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 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.
*
* @author Michael Jumper
*/
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 RADIUS server to connect to when accounting users.
*/
public static final IntegerGuacamoleProperty RADIUS_ACCT_PORT = new IntegerGuacamoleProperty() {
@Override
public String getName() { return "radius-acct-port"; }
};
/**
* The hostname or ip of the RADIUS server to connect to when authenticating users.
*/
public static final StringGuacamoleProperty RADIUS_SERVER = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-server"; }
};
/**
* The shared secret of the RADIUS server to connect to when authenticating users.
*/
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 StringGuacamoleProperty RADIUS_AUTH_PROTOCOL = new StringGuacamoleProperty() {
@Override
public String getName() { return "radius-auth-protocol"; }
};
/**
* The number of retries when attempting a radius packet transaction.
*/
public static final IntegerGuacamoleProperty RADIUS_RETRIES = new IntegerGuacamoleProperty() {
@Override
public String getName() { return "radius-retries"; }
};
/**
* The network timeout when attempting a radius packet transaction.
*/
public static final IntegerGuacamoleProperty RADIUS_TIMEOUT = new IntegerGuacamoleProperty() {
@Override
public String getName() { return "radius-timeout"; }
};
}

View File

@@ -0,0 +1,55 @@
/*
* 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;
import org.codehaus.jackson.annotate.JsonProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RadiusChallengeResponseField extends Field {
/**
* Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(RadiusChallengeResponseField.class);
private static final String RADIUS_FIELD_NAME = "guac-radius-challenge-response";
private static final String RADIUS_FIELD_TYPE = "GUAC_RADIUS_CHALLENGE_RESPONSE";
private final String radiusState;
private final String replyMsg;
public RadiusChallengeResponseField(String replyMsg, String radiusState) {
super(RADIUS_FIELD_NAME, RADIUS_FIELD_TYPE);
logger.debug("Initializing the RADIUS challenge/response field: {}", replyMsg);
this.replyMsg = replyMsg;
this.radiusState = radiusState;
}
public String getRadiusState() {
return radiusState;
}
public String getReplyMsg() {
return replyMsg;
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.
*
* @author Michael Jumper
*/
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().toLowerCase());
}
@Override
public AuthenticationProvider getAuthenticationProvider() {
return authProvider;
}
@Override
public Credentials getCredentials() {
return credentials;
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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) {
console.log("In guacRadiusConfig() method.");
// Define field for the signed response from the RADIUS service
formServiceProvider.registerFieldType('GUAC_RADIUS_CHALLENGE_RESPONSE', {
module : 'guacRadius',
controller : 'guacRadiusController',
templateUrl : 'app/ext/radius/templates/radiusChallengeResponseField.html'
});
}]);

View File

@@ -0,0 +1,36 @@
/*
* 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_CHALLENGE_RESPONSE" field which uses the DuoWeb
* API to prompt the user for additional credentials, ultimately receiving a
* signed response from the Duo service.
*/
angular.module('guacRadius').controller('guacRadiusController', ['$scope', '$element',
function guacRadiusController($scope, $element) {
console.log("In guacRadiusController() method.");
var radiusChallenge = $element.find(document.querySelector('#radius-challenge-text'));
var radiusState = $element.find(document.querySelector('#radius-state'));
console.log("RADIUS Reply Message: " + $scope.field.replyMsg);
radiusChellenge.html($scope.field.replyMsg);
console.log("RADIUS State: " + scope.field.radiusState);
radiusState.value = $scope.field.radiusState;
}]);

View File

@@ -0,0 +1,28 @@
{
"guacamoleVersion" : "0.9.11-incubating",
"name" : "RADIUS Authentication Backend",
"namespace" : "radius",
"authProviders" : [
"org.apache.guacamole.auth.radius.RadiusAuthenticationProvider"
],
"translations" : [
"translations/en.json"
],
"js" : [
"radius.min.js"
],
"css" : [
"radius.min.css"
],
"resources" : {
"templates/radiusChallengeResponseField.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,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.
*/
console.log("Loading guac-radius Angular module.");
/**
* Module which provides handling for RADIUS challenge-response
* authentication.
*/
angular.module('guacRadius', [
'form'
]);
// Ensure the guacDuo module is loaded along with the rest of the app
angular.module('index').requires.push('guacRadius');

View File

@@ -0,0 +1,43 @@
/*
* 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.
*/
.radius-challenge-response-field-container {
height: 100%;
width: 100%;
position: fixed;
left: 0;
top: 0;
display: table;
background: white;
}
.radius-challenge-response-field {
width: 100%;
display: table-cell;
vertical-align: middle;
}
.radius-challenge-response-field input[type="submit"] {
display: none !important;
}
.radius-challenge-response-field.loading iframe {
opacity: 0;
}

View File

@@ -0,0 +1,9 @@
<div class="radius-challenge-response-field-container">
<div id="radius-challenge-text" />
<div class="password-field">
<input type="{{passwordInputType}}" ng-model="model" ng-trim="false" autocorrect="off" autocapitalize="off"/>
<div class="icon toggle-password" ng-click="togglePassword()" title="{{getTogglePasswordHelpText() | translate}}"></div>
</div>
<input type="hidden" id="radius-challenge-state" />
<input type="submit" />
</div>

View File

@@ -0,0 +1,14 @@
{
"DATA_SOURCE_RADIUS" : {
"NAME" : "RADIUS Backend"
},
"LOGIN" : {
"FIELD_HEADER_RADIUS_RESPONSE" : "",
"INFO_RADIUS_RESPONSE_INCORRECT" : "RADIUS response incorrect.",
"INFO_RADIUS_AUTH_REQUIRED" : "Please authenticate with RADIUS to continue.",
"INFO_RADIUS_ADDL_REQUIRED" : "Additional credentials required."
}
}