From 709c2f99f1bf99022ee8ba670cfd8025e2c71592 Mon Sep 17 00:00:00 2001 From: jim-p Date: Wed, 12 Aug 2015 12:07:15 -0400 Subject: [PATCH] Fix GUI auth from RADIUS to grab group names from the Class attribute. Implements #935 The RADIUS server must populate the Class attribute with a string, semicolon-separated, of user groups. Similar to LDAP, local groups must exist with matching names, and privileges are determined by the local matching groups. --- etc/inc/auth.inc | 27 ++++++++++++++++++++++++--- etc/inc/authgui.inc | 2 +- etc/inc/priv.inc | 7 +++++-- etc/inc/radius.inc | 2 +- usr/local/www/diag_authentication.php | 5 +++-- 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/etc/inc/auth.inc b/etc/inc/auth.inc index e21628989b..44a90d87d9 100644 --- a/etc/inc/auth.inc +++ b/etc/inc/auth.inc @@ -1236,6 +1236,24 @@ function radius_backed($username, $passwd, $authcfg, &$attributes = array()) { return $ret; } +/* + $attributes must contain a "class" key containing the groups and local + groups must exist to match. +*/ +function radius_get_groups($attributes) { + $groups = array(); + if (!empty($attributes) && is_array($attributes) && !empty($attributes['class'])) { + $groups = explode(";", $attributes['class']); + foreach ($groups as & $grp) { + $grp = strtolower(trim($grp)); + if (substr($grp, 0, 3) == "ou=") { + $grp = substr($grp, 3); + } + } + } + return $groups; +} + function get_user_expiration_date($username) { $user = getUserEntry($username); if ($user['expires']) @@ -1289,7 +1307,7 @@ function auth_get_authserver_list() { return $list; } -function getUserGroups($username, $authcfg) { +function getUserGroups($username, $authcfg, &$attributes = array()) { global $config; $allowed_groups = array(); @@ -1299,6 +1317,7 @@ function getUserGroups($username, $authcfg) { $allowed_groups = @ldap_get_groups($username, $authcfg); break; case 'radius': + $allowed_groups = @radius_get_groups($attributes); break; default: $user = getUserEntry($username); @@ -1363,14 +1382,16 @@ function session_auth() { return false; /* Validate incoming login request */ + $attributes = array(); if (isset($_POST['login']) && !empty($_POST['usernamefld']) && !empty($_POST['passwordfld'])) { $authcfg = auth_get_authserver($config['system']['webgui']['authmode']); - if (authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg) || - authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) { + if (authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg, $attributes) || + authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) { // Generate a new id to avoid session fixation session_regenerate_id(); $_SESSION['Logged_In'] = "True"; $_SESSION['Username'] = $_POST['usernamefld']; + $_SESSION['user_radius_attributes'] = $attributes; $_SESSION['last_access'] = time(); $_SESSION['protocol'] = $config['system']['webgui']['protocol']; if(! isset($config['system']['webgui']['quietlogin'])) { diff --git a/etc/inc/authgui.inc b/etc/inc/authgui.inc index 0999452c5b..2ca4aa5ee3 100644 --- a/etc/inc/authgui.inc +++ b/etc/inc/authgui.inc @@ -53,7 +53,7 @@ if (!session_auth()) { * We give them access only to the appropriate pages based on * the user or group privileges. */ -$allowedpages = getAllowedPages($_SESSION['Username']); +$allowedpages = getAllowedPages($_SESSION['Username'], $_SESSION['user_radius_attributes']); /* * redirect to first allowed page if requesting a wrong url diff --git a/etc/inc/priv.inc b/etc/inc/priv.inc index c6b244fa33..e6fa96f439 100644 --- a/etc/inc/priv.inc +++ b/etc/inc/priv.inc @@ -240,7 +240,7 @@ function getPrivPages(& $entry, & $allowed_pages) { } } -function getAllowedPages($username) { +function getAllowedPages($username, &$attributes = array()) { global $config, $_SESSION; if (!function_exists("ldap_connect")) @@ -251,8 +251,11 @@ function getAllowedPages($username) { $authcfg = auth_get_authserver($config['system']['webgui']['authmode']); // obtain ldap groups if we are in ldap mode - if ($authcfg['type'] == "ldap") + if ($authcfg['type'] == "ldap") { $allowed_groups = @ldap_get_groups($username, $authcfg); + } elseif ($authcfg['type'] == "radius") { + $allowed_groups = @radius_get_groups($attributes); + } if (!$allowed_groups) { // search for a local user by name diff --git a/etc/inc/radius.inc b/etc/inc/radius.inc index bb8bf6cf80..2b4d472ef8 100644 --- a/etc/inc/radius.inc +++ b/etc/inc/radius.inc @@ -484,7 +484,7 @@ class Auth_RADIUS extends PEAR { break; case RADIUS_CLASS: - $this->attributes['class'] = radius_cvt_int($data); + $this->attributes['class'] = radius_cvt_string($data); break; case RADIUS_FRAMED_PROTOCOL: diff --git a/usr/local/www/diag_authentication.php b/usr/local/www/diag_authentication.php index df68560055..704e92ab98 100644 --- a/usr/local/www/diag_authentication.php +++ b/usr/local/www/diag_authentication.php @@ -55,9 +55,10 @@ if ($_POST) { $input_errors[] = gettext("A username and password must be specified."); if (!$input_errors) { - if (authenticate_user($_POST['username'], $_POST['passwordfld'], $authcfg)) { + $attributes = array(); + if (authenticate_user($_POST['username'], $_POST['passwordfld'], $authcfg, $attributes)) { $savemsg = gettext("User") . ": " . $_POST['username'] . " " . gettext("authenticated successfully."); - $groups = getUserGroups($_POST['username'], $authcfg); + $groups = getUserGroups($_POST['username'], $authcfg, $attributes); $savemsg .= "
" . gettext("This user is a member of these groups") . ":
"; foreach ($groups as $group) $savemsg .= "{$group} ";