Merge remote-tracking branch 'janschumann/master' into future

This merge fixes all conflicts but is otherwise untested and might break
funktionality in the auth system somewhere. It NEEDS MAJOR TESTING!

Some refactoring of the auth plugins is still needed:

  * move to PHP5 style
  * fix comments
  * add plugin.info.txt

* janschumann/master:
  Refactored auth system: All auth methods are now introduced as plugins.
  Bugfix: auth types are now correcty added
  Setup auth system from plugins
  Added Auth-Plugin-Prototype to autoload
  Load auth types from plugins in settings_authtype class
  Added prototype for Auth-Plugins
  added plugin type 'auth'

Conflicts:
	inc/auth.php
	inc/auth/pgsql.class.php
	inc/init.php
	inc/load.php
	lib/plugins/auth.php
	lib/plugins/authad/auth.php
	lib/plugins/authldap/auth.php
	lib/plugins/authmysql/auth.php
	lib/plugins/authplain/auth.php
This commit is contained in:
Andreas Gohr 2012-10-06 10:46:10 +02:00
commit 93a7873eb0
16 changed files with 484 additions and 474 deletions

View File

@ -34,38 +34,34 @@ define('AUTH_ADMIN', 255);
*/
function auth_setup() {
global $conf;
/* @var auth_basic $auth */
/* @var DokuWiki_Auth_Plugin $auth */
global $auth;
/* @var Input $INPUT */
global $INPUT;
global $AUTH_ACL;
global $lang;
global $config_cascade;
global $plugin_controller;
$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']);
// 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;
}
}
if(!isset($auth) || !$auth) return false;
if(!$auth) return false;
if ($auth && $auth->success == false) {
// degrade to unauthenticated user
unset($auth);
auth_logoff();
msg($lang['authtempfail'], -1);
}
// do the login either by cookie or provided credentials XXX
$INPUT->set('http_credentials', false);
@ -91,7 +87,9 @@ function auth_setup() {
}
// apply cleaning
$INPUT->set('u', $auth->cleanUser($INPUT->str('u')));
if (true === $auth->success) {
$_REQUEST['u'] = $auth->cleanUser($_REQUEST['u']);
}
if($INPUT->str('authtok')) {
// when an authentication token is given, trust the session

View File

@ -1,419 +0,0 @@
<?php
/**
* PgSQL authentication backend
*
* This class inherits much functionality from the MySQL class
* and just reimplements the Postgres specific parts.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthias.grimmm@sourceforge.net>
*/
require_once(DOKU_INC.'inc/auth/mysql.class.php');
class auth_pgsql extends auth_mysql {
/**
* Constructor
*
* checks if the pgsql interface is available, otherwise it will
* set the variable $success of the basis class to false
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
* @author Andreas Gohr <andi@splitbrain.org>
*/
function __construct() {
global $conf;
$this->cnf = $conf['auth']['pgsql'];
if(!$this->cnf['port']){
$this->cnf['port'] = 5432;
}
if (method_exists($this, 'auth_basic')){
parent::auth_basic();
}
if(!function_exists('pg_connect')) {
if ($this->cnf['debug'])
msg("PgSQL err: PHP Postgres extension not found.",-1);
$this->success = false;
return;
}
$this->defaultgroup = $conf['defaultgroup'];
// set capabilities based upon config strings set
if (empty($this->cnf['user']) ||
empty($this->cnf['password']) || empty($this->cnf['database'])){
if ($this->cnf['debug']){
msg("PgSQL err: insufficient configuration.",-1,__LINE__,__FILE__);
}
$this->success = false;
return;
}
$this->cando['addUser'] = $this->_chkcnf(array(
'getUserInfo',
'getGroups',
'addUser',
'getUserID',
'getGroupID',
'addGroup',
'addUserGroup'));
$this->cando['delUser'] = $this->_chkcnf(array(
'getUserID',
'delUser',
'delUserRefs'));
$this->cando['modLogin'] = $this->_chkcnf(array(
'getUserID',
'updateUser',
'UpdateTarget'));
$this->cando['modPass'] = $this->cando['modLogin'];
$this->cando['modName'] = $this->cando['modLogin'];
$this->cando['modMail'] = $this->cando['modLogin'];
$this->cando['modGroups'] = $this->_chkcnf(array(
'getUserID',
'getGroups',
'getGroupID',
'addGroup',
'addUserGroup',
'delGroup',
'getGroupID',
'delUserGroup'));
/* getGroups is not yet supported
$this->cando['getGroups'] = $this->_chkcnf(array('getGroups',
'getGroupID')); */
$this->cando['getUsers'] = $this->_chkcnf(array(
'getUsers',
'getUserInfo',
'getGroups'));
$this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'));
}
/**
* Check if the given config strings are set
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
* @return bool
*/
function _chkcnf($keys, $wop=false){
foreach ($keys as $key){
if (empty($this->cnf[$key])) return false;
}
return true;
}
// @inherit function checkPass($user,$pass)
// @inherit function getUserData($user)
// @inherit function createUser($user,$pwd,$name,$mail,$grps=null)
// @inherit function modifyUser($user, $changes)
// @inherit function deleteUsers($users)
/**
* [public function]
*
* Counts users which meet certain $filter criteria.
*
* @param array $filter filter criteria in item/pattern pairs
* @return count of found users.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function getUserCount($filter=array()) {
$rc = 0;
if($this->_openDB()) {
$sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter);
// no equivalent of SQL_CALC_FOUND_ROWS in pgsql?
if (($result = $this->_queryDB($sql))){
$rc = count($result);
}
$this->_closeDB();
}
return $rc;
}
/**
* Bulk retrieval of user data. [public function]
*
* @param first index of first user to be returned
* @param limit max number of users to be returned
* @param filter array of field/pattern pairs
* @return array of userinfo (refer getUserData for internal userinfo details)
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function retrieveUsers($first=0,$limit=10,$filter=array()) {
$out = array();
if($this->_openDB()) {
$this->_lockTables("READ");
$sql = $this->_createSQLFilter($this->cnf['getUsers'], $filter);
$sql .= " ".$this->cnf['SortOrder']." LIMIT $limit OFFSET $first";
$result = $this->_queryDB($sql);
foreach ($result as $user)
if (($info = $this->_getUserInfo($user['user'])))
$out[$user['user']] = $info;
$this->_unlockTables();
$this->_closeDB();
}
return $out;
}
// @inherit function joinGroup($user, $group)
// @inherit function leaveGroup($user, $group) {
/**
* Adds a user to a group.
*
* If $force is set to '1' non existing groups would be created.
*
* The database connection must already be established. Otherwise
* this function does nothing and returns 'false'.
*
* @param $user user to add to a group
* @param $group name of the group
* @param $force '1' create missing groups
* @return bool 'true' on success, 'false' on error
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
* @author Andreas Gohr <andi@splitbrain.org>
*/
function _addUserToGroup($user, $group, $force=0) {
$newgroup = 0;
if (($this->dbcon) && ($user)) {
$gid = $this->_getGroupID($group);
if (!$gid) {
if ($force) { // create missing groups
$sql = str_replace('%{group}',addslashes($group),$this->cnf['addGroup']);
$this->_modifyDB($sql);
//group should now exists try again to fetch it
$gid = $this->_getGroupID($group);
$newgroup = 1; // group newly created
}
}
if (!$gid) return false; // group didn't exist and can't be created
$sql = $this->cnf['addUserGroup'];
if(strpos($sql,'%{uid}') !== false){
$uid = $this->_getUserID($user);
$sql = str_replace('%{uid}', addslashes($uid), $sql);
}
$sql = str_replace('%{user}', addslashes($user),$sql);
$sql = str_replace('%{gid}', addslashes($gid),$sql);
$sql = str_replace('%{group}',addslashes($group),$sql);
if ($this->_modifyDB($sql) !== false) return true;
if ($newgroup) { // remove previously created group on error
$sql = str_replace('%{gid}', addslashes($gid),$this->cnf['delGroup']);
$sql = str_replace('%{group}',addslashes($group),$sql);
$this->_modifyDB($sql);
}
}
return false;
}
// @inherit function _delUserFromGroup($user $group)
// @inherit function _getGroups($user)
// @inherit function _getUserID($user)
/**
* Adds a new User to the database.
*
* The database connection must already be established
* for this function to work. Otherwise it will return
* 'false'.
*
* @param $user login of the user
* @param $pwd encrypted password
* @param $name full name of the user
* @param $mail email address
* @param $grps array of groups the user should become member of
* @return bool
*
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function _addUser($user,$pwd,$name,$mail,$grps){
if($this->dbcon && is_array($grps)) {
$sql = str_replace('%{user}', addslashes($user),$this->cnf['addUser']);
$sql = str_replace('%{pass}', addslashes($pwd),$sql);
$sql = str_replace('%{name}', addslashes($name),$sql);
$sql = str_replace('%{email}',addslashes($mail),$sql);
if($this->_modifyDB($sql)){
$uid = $this->_getUserID($user);
}else{
return false;
}
if ($uid) {
foreach($grps as $group) {
$gid = $this->_addUserToGroup($user, $group, 1);
if ($gid === false) break;
}
if ($gid) return true;
else {
/* remove the new user and all group relations if a group can't
* be assigned. Newly created groups will remain in the database
* and won't be removed. This might create orphaned groups but
* is not a big issue so we ignore this problem here.
*/
$this->_delUser($user);
if ($this->cnf['debug'])
msg("PgSQL err: Adding user '$user' to group '$group' failed.",-1,__LINE__,__FILE__);
}
}
}
return false;
}
// @inherit function _delUser($user)
// @inherit function _getUserInfo($user)
// @inherit function _updateUserInfo($changes, $uid)
// @inherit function _getGroupID($group)
/**
* Opens a connection to a database and saves the handle for further
* usage in the object. The successful call to this functions is
* essential for most functions in this object.
*
* @return bool
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function _openDB() {
if (!$this->dbcon) {
$dsn = $this->cnf['server'] ? 'host='.$this->cnf['server'] : '';
$dsn .= ' port='.$this->cnf['port'];
$dsn .= ' dbname='.$this->cnf['database'];
$dsn .= ' user='.$this->cnf['user'];
$dsn .= ' password='.$this->cnf['password'];
$con = @pg_connect($dsn);
if ($con) {
$this->dbcon = $con;
return true; // connection and database successfully opened
} else if ($this->cnf['debug']){
msg ("PgSQL err: Connection to {$this->cnf['user']}@{$this->cnf['server']} not possible.",
-1,__LINE__,__FILE__);
}
return false; // connection failed
}
return true; // connection already open
}
/**
* Closes a database connection.
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function _closeDB() {
if ($this->dbcon) {
pg_close ($this->dbcon);
$this->dbcon = 0;
}
}
/**
* Sends a SQL query to the database and transforms the result into
* an associative array.
*
* This function is only able to handle queries that returns a
* table such as SELECT.
*
* @param $query SQL string that contains the query
* @return array with the result table
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function _queryDB($query) {
if ($this->dbcon) {
$result = @pg_query($this->dbcon,$query);
if ($result) {
while (($t = pg_fetch_assoc($result)) !== false)
$resultarray[]=$t;
pg_free_result ($result);
return $resultarray;
}elseif ($this->cnf['debug'])
msg('PgSQL err: '.pg_last_error($this->dbcon),-1,__LINE__,__FILE__);
}
return false;
}
/**
* Executes an update or insert query. This differs from the
* MySQL one because it does NOT return the last insertID
*
* @author Andreas Gohr
*/
function _modifyDB($query) {
if ($this->dbcon) {
$result = @pg_query($this->dbcon,$query);
if ($result) {
pg_free_result ($result);
return true;
}
if ($this->cnf['debug']){
msg('PgSQL err: '.pg_last_error($this->dbcon),-1,__LINE__,__FILE__);
}
}
return false;
}
/**
* Start a transaction
*
* @param $mode could be 'READ' or 'WRITE'
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function _lockTables($mode) {
if ($this->dbcon) {
$this->_modifyDB('BEGIN');
return true;
}
return false;
}
/**
* Commit a transaction
*
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
*/
function _unlockTables() {
if ($this->dbcon) {
$this->_modifyDB('COMMIT');
return true;
}
return false;
}
// @inherit function _createSQLFilter($sql, $filter)
/**
* Escape a string for insertion into the database
*
* @author Andreas Gohr <andi@splitbrain.org>
* @param string $string The string to escape
* @param boolean $like Escape wildcard chars as well?
*/
function _escape($string,$like=false){
$string = pg_escape_string($string);
if($like){
$string = addcslashes($string,'%_');
}
return $string;
}
}
//Setup VIM: ex: et ts=2 :

View File

@ -196,7 +196,7 @@ init_paths();
init_files();
// setup plugin controller class (can be overwritten in preload.php)
$plugin_types = array('admin','syntax','action','renderer', 'helper','remote');
$plugin_types = array('auth', 'admin','syntax','action','renderer', 'helper','remote');
global $plugin_controller_class, $plugin_controller;
if (empty($plugin_controller_class)) $plugin_controller_class = 'Doku_Plugin_Controller';

View File

@ -86,6 +86,7 @@ function load_autoload($name){
'DokuWiki_Admin_Plugin' => DOKU_PLUGIN.'admin.php',
'DokuWiki_Syntax_Plugin' => DOKU_PLUGIN.'syntax.php',
'DokuWiki_Remote_Plugin' => DOKU_PLUGIN.'remote.php',
'DokuWiki_Auth_Plugin' => DOKU_PLUGIN.'auth.php',
);
@ -95,7 +96,7 @@ function load_autoload($name){
}
// Plugin loading
if(preg_match('/^(helper|syntax|action|admin|renderer|remote)_plugin_('.DOKU_PLUGIN_NAME_REGEX.')(?:_([^_]+))?$/',
if(preg_match('/^(auth|helper|syntax|action|admin|renderer|remote)_plugin_('.DOKU_PLUGIN_NAME_REGEX.')(?:_([^_]+))?$/',
$name, $m)) {
// try to load the wanted plugin file
$c = ((count($m) === 4) ? "/{$m[3]}" : '');

View File

@ -1,14 +1,19 @@
<?php
/**
* auth/basic.class.php
* Auth Plugin Prototype
*
* foundation authorisation class
* all auth classes should inherit from this class
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Chris Smith <chris@jalakai.co.uk>
*/
* @author Jan Schumann <js@jschumann-it.com>
class auth_basic {
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
var $success = true;
/**
@ -397,5 +402,22 @@ class auth_basic {
return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge'));
}
/**
* loadConfig()
* merges the plugin's default settings with any local settings
* this function is automatically called through getConf()
*/
function loadConfig(){
global $conf;
parent::loadConfig();
$this->conf['debug'] = $conf['debug'];
$this->conf['useacl'] = $conf['useacl'];
$this->conf['disableactions'] = $conf['disableactions'];
$this->conf['autopasswd'] = $conf['autopasswd'];
$this->conf['passcrypt'] = $conf['ssha'];
}
}
//Setup VIM: ex: et ts=2 :

View File

@ -1,4 +1,9 @@
<?php
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
require_once(DOKU_INC.'inc/adLDAP.php');
/**
* Active Directory authentication backend for DokuWiki
*
@ -11,7 +16,7 @@
* $conf['useacl'] = 1;
* $conf['disableactions'] = 'register';
* $conf['autopasswd'] = 0;
* $conf['authtype'] = 'ad';
* $conf['authtype'] = 'authad';
* $conf['passcrypt'] = 'ssha';
*
* $conf['auth']['ad']['account_suffix'] = '
@ -33,17 +38,18 @@
*
* // get additional information to the userinfo array
* // add a list of comma separated ldap contact fields.
* $conf['auth']['ad']['additional'] = 'field1,field2';
* $conf['plugin']['authad']['additional'] = 'field1,field2';
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author James Van Lommel <jamesvl@gmail.com>
* @link http://www.nosq.com/blog/2005/08/ldap-activedirectory-and-dokuwiki/
* @author Andreas Gohr <andi@splitbrain.org>
* @author Jan Schumann <js@schumann-it.com>
*/
require_once(DOKU_INC.'inc/adLDAP/adLDAP.php');
class auth_ad extends auth_basic {
class auth_plugin_authad extends DokuWiki_Auth_Plugin {
/**
* @var array copy of the auth backend configuration
*/
@ -516,5 +522,3 @@ class auth_ad extends auth_basic {
}
}
}
//Setup VIM: ex: et ts=4 :

View File

@ -0,0 +1,7 @@
base authad
author
email
date
name active directory auth plugin
desc Provides authentication against a Microsoft Active Directory
url

View File

@ -1,13 +1,16 @@
<?php
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
/**
* LDAP authentication backend
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakaic.co.uk>
* @author Jan Schumann <js@schumann-it.com>
*/
class auth_ldap extends auth_basic {
class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
var $cnf = null;
var $con = null;
var $bound = 0; // 0: anonymous, 1: user, 2: superuser
@ -482,5 +485,3 @@ class auth_ldap extends auth_basic {
}
}
}
//Setup VIM: ex: et ts=4 :

View File

@ -0,0 +1,7 @@
base authldap
author
email
date
name ldap auth plugin
desc Provides authentication against am LDAP server
url

View File

@ -1,4 +1,7 @@
<?php
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
/**
* MySQLP authentication backend
*
@ -6,10 +9,9 @@
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthias.grimmm@sourceforge.net>
* @author Jan Schumann <js@schumann-it.com>
*/
class auth_mysql extends auth_basic {
class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
var $dbcon = 0;
var $dbver = 0; // database version
var $dbrev = 0; // database revision
@ -943,5 +945,3 @@ class auth_mysql extends auth_basic {
return $string;
}
}
//Setup VIM: ex: et ts=2 :

View File

@ -0,0 +1,7 @@
base authmysql
author
email
date
name mysql auth plugin
desc Provides authentication against a MySQL Server
url

View File

@ -0,0 +1,331 @@
<?php
/**
* Plugin auth provider
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Jan Schumann <js@schumann-it.com>
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
/**
* PgSQL authentication backend
*
* This class inherits much functionality from the MySQL class
* and just reimplements the Postgres specific parts.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Matthias Grimm <matthias.grimmm@sourceforge.net>
* @author Jan Schumann <js@schumann-it.com>
*/
class auth_plugin_authpgsql extends auth_plugin_authmysql
{
var $cnf = null;
var $opts = null;
var $adldap = null;
var $users = null;
/**
* Constructor
*/
function auth_plugin_authpgsql() {
global $conf;
$this->cnf = $conf['auth']['ad'];
// additional information fields
if (isset($this->cnf['additional'])) {
$this->cnf['additional'] = str_replace(' ', '', $this->cnf['additional']);
$this->cnf['additional'] = explode(',', $this->cnf['additional']);
} else $this->cnf['additional'] = array();
// ldap extension is needed
if (!function_exists('ldap_connect')) {
if ($this->cnf['debug'])
msg("AD Auth: PHP LDAP extension not found.",-1);
$this->success = false;
return;
}
// Prepare SSO
if($_SERVER['REMOTE_USER'] && $this->cnf['sso']){
// remove possible NTLM domain
list($dom,$usr) = explode('\\',$_SERVER['REMOTE_USER'],2);
if(!$usr) $usr = $dom;
// remove possible Kerberos domain
list($usr,$dom) = explode('@',$usr);
$dom = strtolower($dom);
$_SERVER['REMOTE_USER'] = $usr;
// we need to simulate a login
if(empty($_COOKIE[DOKU_COOKIE])){
$_REQUEST['u'] = $_SERVER['REMOTE_USER'];
$_REQUEST['p'] = 'sso_only';
}
}
// prepare adLDAP standard configuration
$this->opts = $this->cnf;
// add possible domain specific configuration
if($dom && is_array($this->cnf[$dom])) foreach($this->cnf[$dom] as $key => $val){
$this->opts[$key] = $val;
}
// handle multiple AD servers
$this->opts['domain_controllers'] = explode(',',$this->opts['domain_controllers']);
$this->opts['domain_controllers'] = array_map('trim',$this->opts['domain_controllers']);
$this->opts['domain_controllers'] = array_filter($this->opts['domain_controllers']);
// we can change the password if SSL is set
if($this->opts['use_ssl'] || $this->opts['use_tls']){
$this->cando['modPass'] = true;
}
$this->cando['modName'] = true;
$this->cando['modMail'] = true;
}
/**
* Check user+password [required auth function]
*
* Checks if the given user exists and the given
* plaintext password is correct by trying to bind
* to the LDAP server
*
* @author James Van Lommel <james@nosq.com>
* @return bool
*/
function checkPass($user, $pass){
if($_SERVER['REMOTE_USER'] &&
$_SERVER['REMOTE_USER'] == $user &&
$this->cnf['sso']) return true;
if(!$this->_init()) return false;
return $this->adldap->authenticate($user, $pass);
}
/**
* Return user info [required auth function]
*
* Returns info about the given user needs to contain
* at least these fields:
*
* name string full name of the user
* mail string email address of the user
* grps array list of groups the user is in
*
* This LDAP specific function returns the following
* addional fields:
*
* dn string distinguished name (DN)
* uid string Posix User ID
*
* @author James Van Lommel <james@nosq.com>
*/
function getUserData($user){
global $conf;
if(!$this->_init()) return false;
$fields = array('mail','displayname','samaccountname');
// add additional fields to read
$fields = array_merge($fields, $this->cnf['additional']);
$fields = array_unique($fields);
//get info for given user
$result = $this->adldap->user_info($user, $fields);
//general user info
$info['name'] = $result[0]['displayname'][0];
$info['mail'] = $result[0]['mail'][0];
$info['uid'] = $result[0]['samaccountname'][0];
$info['dn'] = $result[0]['dn'];
// additional information
foreach ($this->cnf['additional'] as $field) {
if (isset($result[0][strtolower($field)])) {
$info[$field] = $result[0][strtolower($field)][0];
}
}
// handle ActiveDirectory memberOf
$info['grps'] = $this->adldap->user_groups($user,(bool) $this->opts['recursive_groups']);
if (is_array($info['grps'])) {
foreach ($info['grps'] as $ndx => $group) {
$info['grps'][$ndx] = $this->cleanGroup($group);
}
}
// always add the default group to the list of groups
if(!is_array($info['grps']) || !in_array($conf['defaultgroup'],$info['grps'])){
$info['grps'][] = $conf['defaultgroup'];
}
return $info;
}
/**
* Make AD group names usable by DokuWiki.
*
* Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores.
*
* @author James Van Lommel (jamesvl@gmail.com)
*/
function cleanGroup($name) {
$sName = str_replace('\\', '', $name);
$sName = str_replace('#', '', $sName);
$sName = preg_replace('[\s]', '_', $sName);
return $sName;
}
/**
* Sanitize user names
*/
function cleanUser($name) {
return $this->cleanGroup($name);
}
/**
* Most values in LDAP are case-insensitive
*/
function isCaseSensitive(){
return false;
}
/**
* Bulk retrieval of user data
*
* @author Dominik Eckelmann <dokuwiki@cosmocode.de>
* @param start index of first user to be returned
* @param limit max number of users to be returned
* @param filter array of field/pattern pairs, null for no filter
* @return array of userinfo (refer getUserData for internal userinfo details)
*/
function retrieveUsers($start=0,$limit=-1,$filter=array()) {
if(!$this->_init()) return false;
if ($this->users === null) {
//get info for given user
$result = $this->adldap->all_users();
if (!$result) return array();
$this->users = array_fill_keys($result, false);
}
$i = 0;
$count = 0;
$this->_constructPattern($filter);
$result = array();
foreach ($this->users as $user => &$info) {
if ($i++ < $start) {
continue;
}
if ($info === false) {
$info = $this->getUserData($user);
}
if ($this->_filter($user, $info)) {
$result[$user] = $info;
if (($limit >= 0) && (++$count >= $limit)) break;
}
}
return $result;
}
/**
* Modify user data
*
* @param $user nick of the user to be changed
* @param $changes array of field/value pairs to be changed
* @return bool
*/
function modifyUser($user, $changes) {
$return = true;
// password changing
if(isset($changes['pass'])){
try {
$return = $this->adldap->user_password($user,$changes['pass']);
} catch (adLDAPException $e) {
if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
$return = false;
}
if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?',-1);
}
// changing user data
$adchanges = array();
if(isset($changes['name'])){
// get first and last name
$parts = explode(' ',$changes['name']);
$adchanges['surname'] = array_pop($parts);
$adchanges['firstname'] = join(' ',$parts);
$adchanges['display_name'] = $changes['name'];
}
if(isset($changes['mail'])){
$adchanges['email'] = $changes['mail'];
}
if(count($adchanges)){
try {
$return = $return & $this->adldap->user_modify($user,$adchanges);
} catch (adLDAPException $e) {
if ($this->cnf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
$return = false;
}
}
return $return;
}
/**
* Initialize the AdLDAP library and connect to the server
*/
function _init(){
if(!is_null($this->adldap)) return true;
// connect
try {
$this->adldap = new adLDAP($this->opts);
if (isset($this->opts['ad_username']) && isset($this->opts['ad_password'])) {
$this->canDo['getUsers'] = true;
}
return true;
} catch (adLDAPException $e) {
if ($this->cnf['debug']) {
msg('AD Auth: '.$e->getMessage(), -1);
}
$this->success = false;
$this->adldap = null;
}
return false;
}
/**
* return 1 if $user + $info match $filter criteria, 0 otherwise
*
* @author Chris Smith <chris@jalakai.co.uk>
*/
function _filter($user, $info) {
foreach ($this->_pattern as $item => $pattern) {
if ($item == 'user') {
if (!preg_match($pattern, $user)) return 0;
} else if ($item == 'grps') {
if (!count(preg_grep($pattern, $info['grps']))) return 0;
} else {
if (!preg_match($pattern, $info[$item])) return 0;
}
}
return 1;
}
function _constructPattern($filter) {
$this->_pattern = array();
foreach ($filter as $item => $pattern) {
// $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters
$this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters
}
}
}

View File

@ -0,0 +1,7 @@
base authad
author
email
date
name active directory auth plugin
desc Provides authentication against a Microsoft Active Directory
url

View File

@ -1,14 +1,16 @@
<?php
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
/**
* Plaintext authentication backend
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Chris Smith <chris@jalakai.co.uk>
* @author Jan Schumann <js@schumann-it.com>
*/
class auth_plain extends auth_basic {
class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
var $users = null;
var $_pattern = array();
@ -323,6 +325,4 @@ class auth_plain extends auth_basic {
$this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters
}
}
}
//Setup VIM: ex: et ts=2 :
}

View File

@ -0,0 +1,7 @@
base authplain
author
email
date
name auth plugin
desc Provides authentication against local password storage
url

View File

@ -43,17 +43,54 @@ if (!class_exists('setting_authtype')) {
class setting_authtype extends setting_multichoice {
function initialize($default,$local,$protected) {
global $plugin_controller;
// populate $this->_choices with a list of available auth mechanisms
$authtypes = glob(DOKU_INC.'inc/auth/*.class.php');
$authtypes = preg_replace('#^.*/([^/]*)\.class\.php$#i','$1', $authtypes);
$authtypes = array_diff($authtypes, array('basic'));
sort($authtypes);
$this->_choices = $authtypes;
// retrive auth types provided by plugins
foreach ($plugin_controller->getList('auth') as $plugin) {
$this->_choices[] = $plugin;
}
parent::initialize($default,$local,$protected);
}
function update($input) {
global $plugin_controller;
// is an update posible?
$mayUpdate = parent::update($input);
// is it an auth plugin?
if (in_array($input, $plugin_controller->getList('auth'))) {
// reject disabled plugins
if ($plugin_controller->isdisabled($input)) {
$this->_error = true;
msg('Auth type ' . $input . ' is disabled.');
return false;
}
// load the plugin
$auth_plugin = $plugin_controller->load('auth', $input);
// @TODO: throw an error in plugin controller instead of returning null
if (is_null($auth_plugin)) {
$this->_error = true;
msg('Cannot load Auth Plugin "' . $input . '"');
return false;
}
// verify proper instanciation (is this really a plugin?) @TODO use instanceof? impement interface?
if (is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) {
$this->_error = true;
msg('Cannot create Auth Plugin "' . $input . '"');
return false;
}
}
msg('Successfully changed auth system. Please re-login.');
auth_logoff();
return true;
}
}
}