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