1<?php 2/** 3 * Copyright 2002-2017 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file COPYING for license information (LGPL). If you did 6 * not receive this file, see http://www.horde.org/licenses/lgpl21. 7 * 8 * @author Michael Slusarz <slusarz@horde.org> 9 * @category Horde 10 * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 11 * @package Auth 12 */ 13 14/** 15 * The Horde_Auth_Radius class provides a RADIUS implementation of the Horde 16 * authentication system. 17 * 18 * This class requires the 'radius' PECL extension: 19 * http://pecl.php.net/package/radius 20 * 21 * @author Michael Slusarz <slusarz@horde.org> 22 * @category Horde 23 * @copyright 2002-2017 Horde LLC 24 * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1 25 * @package Auth 26 */ 27class Horde_Auth_Radius extends Horde_Auth_Base 28{ 29 /** 30 * Constructor. 31 * 32 * @param array $params Connection parameters. 33 * <pre> 34 * 'host' - (string) [REQUIRED] The RADIUS host to use (IP address or 35 * fully qualified hostname). 36 * 'method' - (string) [REQUIRED] The RADIUS method to use for validating 37 * the request. 38 * Either: 'PAP', 'CHAP_MD5', 'MSCHAPv1', or 'MSCHAPv2'. 39 * ** CURRENTLY, only 'PAP' is supported. ** 40 * 'nas' - (string) The RADIUS NAS identifier to use. 41 * DEFAULT: The value of $_SERVER['HTTP_HOST'] or, if not 42 * defined, then 'localhost'. 43 * 'port' - (integer) The port to use on the RADIUS server. 44 * DEFAULT: Whatever the local system identifies as the 45 * 'radius' UDP port 46 * 'retries' - (integer) The maximum number of repeated requests to make 47 * before giving up. 48 * DEFAULT: 3 49 * 'secret' - (string) [REQUIRED] The RADIUS shared secret string for the 50 * host. The RADIUS protocol ignores all but the leading 128 51 * bytes of the shared secret. 52 * 'suffix' - (string) The domain name to add to unqualified user names. 53 * DEFAULT: NONE 54 * 'timeout' - (integer) The timeout for receiving replies from the server 55 * (in seconds). 56 * DEFAULT: 3 57 * </pre> 58 * 59 * @throws InvalidArgumentException 60 */ 61 public function __construct(array $params = array()) 62 { 63 if (!Horde_Util::extensionExists('radius')) { 64 throw new Horde_Auth_Exception(__CLASS__ . ': requires the radius PECL extension to be loaded.'); 65 } 66 67 foreach (array('host', 'secret', 'method') as $val) { 68 if (!isset($params[$val])) { 69 throw new InvalidArgumentException('Missing ' . $val . ' parameter.'); 70 } 71 } 72 73 $params = array_merge(array( 74 'nas' => (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost'), 75 'port' => 0, 76 'retries' => 3, 77 'suffix' => '', 78 'timeout' => 3 79 ), $params); 80 81 parent::__construct($params); 82 } 83 84 /** 85 * Find out if a set of login credentials are valid. 86 * 87 * @param string $username The userId to check. 88 * @param array $credentials An array of login credentials. 89 * For radius, this must contain a password 90 * entry. 91 * 92 * @throws Horde_Auth_Exception 93 */ 94 protected function _authenticate($username, $credentials) 95 { 96 /* Password is required. */ 97 if (!isset($credentials['password'])) { 98 throw new Horde_Auth_Exception('Password required for RADIUS authentication.'); 99 } 100 101 $res = radius_auth_open(); 102 radius_add_server($res, $this->_params['host'], $this->_params['port'], $this->_params['secret'], $this->_params['timeout'], $this->_params['retries']); 103 radius_create_request($res, RADIUS_ACCESS_REQUEST); 104 radius_put_attr($res, RADIUS_NAS_IDENTIFIER, $this->_params['nas']); 105 radius_put_attr($res, RADIUS_NAS_PORT_TYPE, RADIUS_VIRTUAL); 106 radius_put_attr($res, RADIUS_SERVICE_TYPE, RADIUS_FRAMED); 107 radius_put_attr($res, RADIUS_FRAMED_PROTOCOL, RADIUS_PPP); 108 radius_put_attr($res, RADIUS_CALLING_STATION_ID, isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : '127.0.0.1'); 109 110 /* Insert username/password into request. */ 111 radius_put_attr($res, RADIUS_USER_NAME, $username); 112 radius_put_attr($res, RADIUS_USER_PASSWORD, $credentials['password']); 113 114 /* Send request. */ 115 $success = radius_send_request($res); 116 117 switch ($success) { 118 case RADIUS_ACCESS_ACCEPT: 119 break; 120 121 case RADIUS_ACCESS_REJECT: 122 throw new Horde_Auth_Exception('Authentication rejected by RADIUS server.'); 123 124 default: 125 throw new Horde_Auth_Exception(radius_strerror($res)); 126 } 127 } 128 129} 130