From 334c12cd65b573f08af4f75ab1b8299956971fb9 Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Tue, 24 Mar 2009 08:51:42 +0000 Subject: [PATCH] New authentication module: radius:Radius. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1440 44740490-163a-0410-bde0-09ae8108e29a --- modules/radius/default-disable | 0 modules/radius/docs/radius.txt | 86 ++++++++++ modules/radius/lib/Auth/Source/Radius.php | 184 ++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 modules/radius/default-disable create mode 100644 modules/radius/docs/radius.txt create mode 100644 modules/radius/lib/Auth/Source/Radius.php diff --git a/modules/radius/default-disable b/modules/radius/default-disable new file mode 100644 index 000000000..e69de29bb diff --git a/modules/radius/docs/radius.txt b/modules/radius/docs/radius.txt new file mode 100644 index 000000000..4a7614404 --- /dev/null +++ b/modules/radius/docs/radius.txt @@ -0,0 +1,86 @@ +RADIUS module +============= + +The RADIUS module provides a single authentication module: + +`radius:Radius` +: Authenticate a user against a RADIUS server. + +This authentication module contacts a RADIUS server, and authenticates +the user by using username & password authentication. + +To use this module, enable the radius module by creating a file named +`enable` in the `modules/radius/`-directory. Then you need to add a +authentication source which uses the `radius:Radius` module to +`config/authsources.php`: + + 'example-radius' => array( + 'radius:Radius', + + /* + * The hostname of the RADIUS server. + * Required. + */ + 'hostname' => 'radius.example.org', + + /* + * The port number of the radius server. + * Optional, defaults to 1812. + */ + 'port' => 1812, + + /* + * The shared secret which is used when contacting the RADUIS server. + * Required. + */ + 'secret' => 'topsecret', + + /* + * The timeout for contacting the RADIUS server, in seconds. + * Optional, defaults to 5 seconds. + */ + 'timeout' => 5, + + /* + * The number of times we should retry connections to the RADIUS server. + * Optional, defaults to 3 attempts. + */ + 'retries' => 3, + + /* + * The attribute name we should store the username in. Ths username + * will not be saved in any attribute if this is NULL. + * Optional, defaults to NULL. + */ + 'username_attribute' => 'eduPersonPrincipalName', + ), + + +User attributes +--------------- + +If the RADIUS server is configured to include attributes for the user in +the response, this module may be able to extract them. This requires the +attributes to be stored in a vendor-specific attribute in the response +from the RADIUS server. + +The code expects one vendor-attribute with a specific vendor and a specific +vendor attribute type for each user attribute. The vendor-attribute must +contain a value on the form <name>=<value>. + +The following configuration options are available for user attributes: + + /* + * This is the vendor for the vendor-specific attribute which contains + * the attributes for this user. This can be NULL if no attributes are + * included in the response. + * Optional, defaults to NULL. + */ + 'attribute_vendor' => 23735, + + /* + * The vendor attribute-type of the attribute which contains the + * attributes for the user. + * Required if 'vendor' is set. + */ + 'attribute_vendor_type' => 4, diff --git a/modules/radius/lib/Auth/Source/Radius.php b/modules/radius/lib/Auth/Source/Radius.php new file mode 100644 index 000000000..283027ec0 --- /dev/null +++ b/modules/radius/lib/Auth/Source/Radius.php @@ -0,0 +1,184 @@ +<?php + +/** + * RADIUS authentication source. + * + * This class is based on www/auth/login-radius.php. + * + * @package simpleSAMLphp + * @version $Id$ + */ +class sspmod_radius_Auth_Source_Radius extends sspmod_core_Auth_UserPassBase { + + /** + * The hostname of the radius server. + */ + private $hostname; + + /** + * The port of the radius server. + */ + private $port; + + /** + * The secret used when communicating with the radius server. + */ + private $secret; + + /** + * The timeout for contacting the radius server. + */ + private $timeout; + + /** + * The number of retries which should be attempted. + */ + private $retries; + + /** + * The attribute name where the username should be stored. + */ + private $usernameAttribute; + + /** + * The vendor for the RADIUS attributes we are interrested in. + */ + private $vendor; + + /** + * The vendor-specific attribute for the RADIUS attributes we are interrested in. + */ + private $vendorType; + + + /** + * Constructor for this authentication source. + * + * @param array $info Information about this authentication source. + * @param array $config Configuration. + */ + public function __construct($info, $config) { + assert('is_array($info)'); + assert('is_array($config)'); + + /* Call the parent constructor first, as required by the interface. */ + parent::__construct($info, $config); + + /* Parse configuration. */ + $config = SimpleSAML_Configuration::loadFromArray($config, + 'Authentication source ' . var_export($this->authId, TRUE)); + + $this->hostname = $config->getString('hostname'); + $this->port = $config->getIntegerRange('port', 1, 65535, 1812); + $this->secret = $config->getString('secret'); + $this->timeout = $config->getInteger('timeout', 5); + $this->retries = $config->getInteger('retries', 3); + $this->usernameAttribute = $config->getString('username_attribute', NULL); + + $this->vendor = $config->getInteger('attribute_vendor', NULL); + if ($this->vendor !== NULL) { + $this->vendorType = $config->getInteger('attribute_vendor_type'); + } + } + + + /** + * Attempt to log in using the given username and password. + * + * @param string $username The username the user wrote. + * @param string $password The password the user wrote. + * @return array Associative array with the users attributes. + */ + protected function login($username, $password) { + assert('is_string($username)'); + assert('is_string($password)'); + + $radius = radius_auth_open(); + if (!radius_add_server($radius, $this->hostname, $this->port, $this->secret, $this->timeout, $this->retries)) { + throw new Exception('Error connecting to radius server: ' . radius_strerror($radius)); + } + + if (!radius_create_request($radius, RADIUS_ACCESS_REQUEST)) { + throw new Exception('Error creating radius request: ' . radius_strerror($radius)); + } + + radius_put_attr($radius, RADIUS_USER_NAME, $username); + radius_put_attr($radius, RADIUS_USER_PASSWORD, $password); + + $res = radius_send_request($radius); + if ($res != RADIUS_ACCESS_ACCEPT) { + switch ($res) { + case RADIUS_ACCESS_REJECT: + /* Invalid username or password. */ + throw new SimpleSAML_Error_Error('WRONGUSERPASS'); + case RADIUS_ACCESS_CHALLENGE: + throw new Exception('Radius authentication error: Challenge requested, but not supported.'); + default: + throw new Exception('Error during radius authentication: ' . radius_strerror($radius)); + } + } + + /* If we get this far, we have a valid login. */ + + $attributes = array(); + + if ($this->usernameAttribute !== NULL) { + $attributes[$this->usernameAttribute] = array($username); + } + + if ($this->vendor === NULL) { + /* + * We aren't interrested in any vendor-specific attributes. We are + * therefore done now. + */ + return $attributes; + } + + /* get AAI attribute sets. Contributed by Stefan Winter, (c) RESTENA */ + while ($resa = radius_get_attr($radius)) { + + if (!is_array($resa)) { + throw new Exception('Error getting radius attributes: ' . radius_strerror($radius)); + } + + if ($resa['attr'] !== RADIUS_VENDOR_SPECIFIC) { + continue; + } + + $resv = radius_get_vendor_attr($resa['data']); + if (!is_array($resv)) { + throw new Exception('Error getting vendor specific attribute: ' . radius_strerror($radius)); + } + + $vendor = $resv['vendor']; + $attrv = $resv['attr']; + $datav = $resv['data']; + + /* + * Uncomment this to debug vendor attributes. + */ + //printf("Got Vendor Attr:%d %d Bytes %s<br/>", $attrv, strlen($datav), bin2hex($datav)); + + if ($vendor != $this->vendor || $attrv != $this->vendorType) { + continue; + } + + $attrib_name = strtok($datav,'='); + $attrib_value = strtok('='); + + /* if the attribute name is already in result set, add another value */ + if (array_key_exists($attrib_name, $attributes)) { + $attributes[$attrib_name][] = $attrib_value; + } else { + $attributes[$attrib_name] = array($attrib_value); + } + } + /* end of contribution */ + + return $attributes; + } + +} + + +?> \ No newline at end of file -- GitLab