/** * Initialize the auth system. * * This function is automatically called at the end of init.php * * This used to be the main() of the auth.php * * @todo backend loading maybe should be handled by the class autoloader * @todo maybe split into multiple functions at the XXX marked positions * @triggers AUTH_LOGIN_CHECK * @return bool */ function auth_setup() { global $conf; /* @var DokuWiki_Auth_Plugin $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; global $AUTH_ACL; global $lang; /* @var Doku_Plugin_Controller $plugin_controller */ global $plugin_controller; $AUTH_ACL = array(); if (!$conf['useacl']) { return false; } // try to load auth backend from plugins foreach ($plugin_controller->getList('auth') as $plugin) { if ($conf['authtype'] === $plugin) { $auth = $plugin_controller->load('auth', $plugin); break; } elseif ('auth' . $conf['authtype'] === $plugin) { // matches old auth backends (pre-Weatherwax) $auth = $plugin_controller->load('auth', $plugin); msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = "auth' . $conf['authtype'] . '"' . ' in your configuration (see <a href="https://www.dokuwiki.org/auth">Authentication Backends</a>)', -1, '', '', MSG_ADMINS_ONLY); } } if (!isset($auth) || !$auth) { msg($lang['authtempfail'], -1); return false; } if ($auth->success == false) { // degrade to unauthenticated user unset($auth); auth_logoff(); msg($lang['authtempfail'], -1); return false; } // do the login either by cookie or provided credentials XXX $INPUT->set('http_credentials', false); if (!$conf['rememberme']) { $INPUT->set('r', false); } // handle renamed HTTP_AUTHORIZATION variable (can happen when a fix like // the one presented at // http://www.besthostratings.com/articles/http-auth-php-cgi.html is used // for enabling HTTP authentication with CGI/SuExec) if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } // streamline HTTP auth credentials (IIS/rewrite -> mod_php) if (isset($_SERVER['HTTP_AUTHORIZATION'])) { list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))); } // if no credentials were given try to use HTTP auth (for SSO) if (!$INPUT->str('u') && empty($_COOKIE[DOKU_COOKIE]) && !empty($_SERVER['PHP_AUTH_USER'])) { $INPUT->set('u', $_SERVER['PHP_AUTH_USER']); $INPUT->set('p', $_SERVER['PHP_AUTH_PW']); $INPUT->set('http_credentials', true); } // apply cleaning (auth specific user names, remove control chars) if (true === $auth->success) { $INPUT->set('u', $auth->cleanUser(stripctl($INPUT->str('u')))); $INPUT->set('p', stripctl($INPUT->str('p'))); } if ($INPUT->str('authtok')) { // when an authentication token is given, trust the session auth_validateToken($INPUT->str('authtok')); } elseif (!is_null($auth) && $auth->canDo('external')) { // external trust mechanism in place $auth->trustExternal($INPUT->str('u'), $INPUT->str('p'), $INPUT->bool('r')); } else { $evdata = array('user' => $INPUT->str('u'), 'password' => $INPUT->str('p'), 'sticky' => $INPUT->bool('r'), 'silent' => $INPUT->bool('http_credentials')); trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper'); } //load ACL into a global array XXX $AUTH_ACL = auth_loadACL(); return true; }
/** * Initialize the auth system. * * This function is automatically called at the end of init.php * * This used to be the main() of the auth.php * * @todo backend loading maybe should be handled by the class autoloader * @todo maybe split into multiple functions at the XXX marked positions * @triggers AUTH_LOGIN_CHECK * @return bool */ function auth_setup() { global $conf; /* @var auth_basic $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; global $AUTH_ACL; global $lang; $AUTH_ACL = array(); if (!$conf['useacl']) { return false; } // load the the backend auth functions and instantiate the auth object XXX if (@file_exists(DOKU_INC . 'inc/auth/' . $conf['authtype'] . '.class.php')) { require_once DOKU_INC . 'inc/auth/basic.class.php'; require_once DOKU_INC . 'inc/auth/' . $conf['authtype'] . '.class.php'; $auth_class = "auth_" . $conf['authtype']; if (class_exists($auth_class)) { $auth = new $auth_class(); if ($auth->success == false) { // degrade to unauthenticated user unset($auth); auth_logoff(); msg($lang['authtempfail'], -1); } } else { nice_die($lang['authmodfailed']); } } else { nice_die($lang['authmodfailed']); } if (!isset($auth) || !$auth) { return false; } // do the login either by cookie or provided credentials XXX $INPUT->set('http_credentials', false); if (!$conf['rememberme']) { $INPUT->set('r', false); } // handle renamed HTTP_AUTHORIZATION variable (can happen when a fix like // the one presented at // http://www.besthostratings.com/articles/http-auth-php-cgi.html is used // for enabling HTTP authentication with CGI/SuExec) if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } // streamline HTTP auth credentials (IIS/rewrite -> mod_php) if (isset($_SERVER['HTTP_AUTHORIZATION'])) { list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))); } // if no credentials were given try to use HTTP auth (for SSO) if (!$INPUT->str('u') && empty($_COOKIE[DOKU_COOKIE]) && !empty($_SERVER['PHP_AUTH_USER'])) { $INPUT->set('u', $_SERVER['PHP_AUTH_USER']); $INPUT->set('p', $_SERVER['PHP_AUTH_PW']); $INPUT->set('http_credentials', true); } // apply cleaning $INPUT->set('u', $auth->cleanUser($INPUT->str('u'))); if ($INPUT->str('authtok')) { // when an authentication token is given, trust the session auth_validateToken($INPUT->str('authtok')); } elseif (!is_null($auth) && $auth->canDo('external')) { // external trust mechanism in place $auth->trustExternal($INPUT->str('u'), $INPUT->str('p'), $INPUT->bool('r')); } else { $evdata = array('user' => $INPUT->str('u'), 'password' => $INPUT->str('p'), 'sticky' => $INPUT->bool('r'), 'silent' => $INPUT->bool('http_credentials')); trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper'); } //load ACL into a global array XXX $AUTH_ACL = auth_loadACL(); return true; }
function test_wildcards() { global $conf; global $AUTH_ACL; global $USERINFO; $conf['useacl'] = 1; $_SERVER['REMOTE_USER'] = '******'; $USERINFO['grps'] = array('test', 'töst', 'foo bar'); $AUTH_ACL = auth_loadACL(); // default test file // default setting $this->assertEquals(AUTH_UPLOAD, auth_aclcheck('page', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); // user namespace $this->assertEquals(AUTH_DELETE, auth_aclcheck('users:john:foo', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); $this->assertEquals(AUTH_READ, auth_aclcheck('users:john:foo', 'schmock', array())); // group namespace $this->assertEquals(AUTH_DELETE, auth_aclcheck('groups:test:foo', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); $this->assertEquals(AUTH_READ, auth_aclcheck('groups:test:foo', 'schmock', array())); $this->assertEquals(AUTH_DELETE, auth_aclcheck('groups:toest:foo', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); $this->assertEquals(AUTH_READ, auth_aclcheck('groups:toest:foo', 'schmock', array())); $this->assertEquals(AUTH_DELETE, auth_aclcheck('groups:foo_bar:foo', $_SERVER['REMOTE_USER'], $USERINFO['grps'])); $this->assertEquals(AUTH_READ, auth_aclcheck('groups:foo_bar:foo', 'schmock', array())); }
/** * Returns the maximum rights a user has for * the given ID or its namespace * * @author Andreas Gohr <*****@*****.**> * * @param string $id page ID * @param string $user Username * @param array $groups Array of groups the user is in * @return int permission level */ function auth_aclcheck($id, $user, $groups, $_auth = 1) { global $AUTH_ACL; $AUTH_ACL = auth_loadACL($AUTH_ACL); if ($_auth == 255) { return 255; } elseif (isset($_SESSION['dwfck_acl']) && $_SESSION['dwfck_acl'] == 255) { return 255; } //make sure groups is an array if (!is_array($groups)) { $groups = array(); } //if user is superuser or in superusergroup return 255 (acl_admin) // if(auth_isadmin($user,$groups)) { return AUTH_ADMIN; } $ci = ''; if (!auth_isCaseSensitive()) { $ci = 'ui'; } $user = auth_nameencode($user); //prepend groups with @ and nameencode $cnt = count($groups); for ($i = 0; $i < $cnt; $i++) { $groups[$i] = '@' . auth_nameencode($groups[$i]); } $ns = getNS($id); $perm = -1; if ($user || count($groups)) { //add ALL group $groups[] = '@ALL'; //add User if ($user) { $groups[] = $user; } //build regexp $regexp = join('|', $groups); } else { $regexp = '@ALL'; } //check exact match first $matches = preg_grep('/^' . preg_quote($id, '/') . '\\s+(' . $regexp . ')\\s+/' . $ci, $AUTH_ACL); if (count($matches)) { foreach ($matches as $match) { $match = preg_replace('/#.*$/', '', $match); //ignore comments $acl = preg_split('/\\s+/', $match); if ($acl[2] > AUTH_DELETE) { $acl[2] = AUTH_DELETE; } //no admins in the ACL! if ($acl[2] > $perm) { $perm = $acl[2]; } } if ($perm > -1) { //we had a match - return it return $perm; } } //still here? do the namespace checks if ($ns) { $path = $ns . ':\\*'; } else { $path = '\\*'; //root document } do { $matches = preg_grep('/^' . $path . '\\s+(' . $regexp . ')\\s+/' . $ci, $AUTH_ACL); if (count($matches)) { foreach ($matches as $match) { $match = preg_replace('/#.*$/', '', $match); //ignore comments $acl = preg_split('/\\s+/', $match); if ($acl[2] > AUTH_DELETE) { $acl[2] = AUTH_DELETE; } //no admins in the ACL! if ($acl[2] > $perm) { $perm = $acl[2]; // checkacl_write_debug("$match;;$perm"); } } //we had a match - return it return $perm; } //get next higher namespace $ns = getNS($ns); if ($path != '\\*') { $path = $ns . ':\\*'; if ($path == ':\\*') { $path = '\\*'; } } else { //we did this already //looks like there is something wrong with the ACL //break here // msg('No ACL setup yet! Denying access to everyone.'); return AUTH_NONE; } } while (1); //this should never loop endless //still here? return no permissions return AUTH_NONE; }
/** * Initialize the auth system. * * This function is automatically called at the end of init.php * * This used to be the main() of the auth.php * * @todo backend loading maybe should be handled by the class autoloader * @todo maybe split into multiple functions at the XXX marked positions */ function auth_setup() { global $conf; global $auth; global $AUTH_ACL; global $lang; global $config_cascade; $AUTH_ACL = array(); if (!$conf['useacl']) { return false; } // load the the backend auth functions and instantiate the auth object XXX if (@file_exists(DOKU_INC . 'inc/auth/' . $conf['authtype'] . '.class.php')) { require_once DOKU_INC . 'inc/auth/basic.class.php'; require_once DOKU_INC . 'inc/auth/' . $conf['authtype'] . '.class.php'; $auth_class = "auth_" . $conf['authtype']; if (class_exists($auth_class)) { $auth = new $auth_class(); if ($auth->success == false) { // degrade to unauthenticated user unset($auth); auth_logoff(); msg($lang['authtempfail'], -1); } } else { nice_die($lang['authmodfailed']); } } else { nice_die($lang['authmodfailed']); } if (!$auth) { return; } // do the login either by cookie or provided credentials XXX if (!isset($_REQUEST['u'])) { $_REQUEST['u'] = ''; } if (!isset($_REQUEST['p'])) { $_REQUEST['p'] = ''; } if (!isset($_REQUEST['r'])) { $_REQUEST['r'] = ''; } $_REQUEST['http_credentials'] = false; if (!$conf['rememberme']) { $_REQUEST['r'] = false; } // streamline HTTP auth credentials (IIS/rewrite -> mod_php) if (isset($_SERVER['HTTP_AUTHORIZATION'])) { list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))); } // if no credentials were given try to use HTTP auth (for SSO) if (empty($_REQUEST['u']) && empty($_COOKIE[DOKU_COOKIE]) && !empty($_SERVER['PHP_AUTH_USER'])) { $_REQUEST['u'] = $_SERVER['PHP_AUTH_USER']; $_REQUEST['p'] = $_SERVER['PHP_AUTH_PW']; $_REQUEST['http_credentials'] = true; } // apply cleaning $_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']); if (isset($_REQUEST['authtok'])) { // when an authentication token is given, trust the session auth_validateToken($_REQUEST['authtok']); } elseif (!is_null($auth) && $auth->canDo('external')) { // external trust mechanism in place $auth->trustExternal($_REQUEST['u'], $_REQUEST['p'], $_REQUEST['r']); } else { $evdata = array('user' => $_REQUEST['u'], 'password' => $_REQUEST['p'], 'sticky' => $_REQUEST['r'], 'silent' => $_REQUEST['http_credentials']); trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper'); } //load ACL into a global array XXX $AUTH_ACL = auth_loadACL(); }
function test_standardtestacls() { $expect = array("*\t@ALL 8", "private:*\t@ALL 0", "users:*\t@ALL 1", "users:testuser:*\ttestuser 16", "groups:*\t@ALL 1", "groups:foo:*\t@foo 16", "groups:bar:*\t@bar 16"); $this->assertEquals($expect, auth_loadACL()); }
/** * Returns the maximum rights a user has for * the given ID or its namespace * * @author Andreas Gohr <*****@*****.**> * * @param string $id page ID * @param string $user Username * @param array $groups Array of groups the user is in * @return int permission level */ function auth_aclcheck($id, $user, $groups, $_auth = 1) { //checkacl_write_debug("$id,$user"); global $AUTH_ACL; $AUTH_ACL = auth_loadACL($AUTH_ACL); if ($_auth == 255) { return 255; } elseif (isset($_SESSION['dwfck_acl']) && $_SESSION['dwfck_acl'] == 255) { return 255; } //make sure groups is an array if (!is_array($groups)) { $groups = array(); } if (!auth_isCaseSensitive()) { $user = utf8_strtolower($user); $groups = array_map('utf8_strtolower', $groups); } $user = auth_cleanUser($user); $groups = array_map('auth_cleanGroup', (array) $groups); $user = auth_nameencode($user); //prepend groups with @ and nameencode $cnt = count($groups); for ($i = 0; $i < $cnt; $i++) { $groups[$i] = '@' . auth_nameencode($groups[$i]); } $ns = getNS($id); $perm = -1; if ($user || count($groups)) { //add ALL group $groups[] = '@ALL'; //add User if ($user) { $groups[] = $user; } } else { $groups[] = '@ALL'; } //check exact match first $matches = preg_grep('/^' . preg_quote($id, '/') . '[ \\t]+([^ \\t]+)[ \\t]+/', $AUTH_ACL); if (count($matches)) { foreach ($matches as $match) { $match = preg_replace('/#.*$/', '', $match); //ignore comments $acl = preg_split('/[ \\t]+/', $match); if (!auth_isCaseSensitive() && $acl[1] !== '@ALL') { $acl[1] = utf8_strtolower($acl[1]); } if (!in_array($acl[1], $groups)) { continue; } if ($acl[2] > AUTH_DELETE) { $acl[2] = AUTH_DELETE; } //no admins in the ACL! if ($acl[2] > $perm) { $perm = $acl[2]; } } if ($perm > -1) { //we had a match - return it return (int) $perm; } } //still here? do the namespace checks if ($ns) { $path = $ns . ':*'; } else { $path = '*'; //root document } do { $matches = preg_grep('/^' . preg_quote($path, '/') . '[ \\t]+([^ \\t]+)[ \\t]+/', $AUTH_ACL); if (count($matches)) { foreach ($matches as $match) { $match = preg_replace('/#.*$/', '', $match); //ignore comments $acl = preg_split('/[ \\t]+/', $match); if (!auth_isCaseSensitive() && $acl[1] !== '@ALL') { $acl[1] = utf8_strtolower($acl[1]); } if (!in_array($acl[1], $groups)) { continue; } if ($acl[2] > AUTH_DELETE) { $acl[2] = AUTH_DELETE; } //no admins in the ACL! if ($acl[2] > $perm) { $perm = $acl[2]; } } //we had a match - return it if ($perm != -1) { return (int) $perm; } } //get next higher namespace $ns = getNS($ns); if ($path != '*') { $path = $ns . ':*'; if ($path == ':*') { $path = '*'; } } else { //we did this already //looks like there is something wrong with the ACL //break here return AUTH_NONE; } } while (1); //this should never loop endless return AUTH_NONE; }