summaryrefslogtreecommitdiff
path: root/lib/plugins/authpgsql
diff options
context:
space:
mode:
Diffstat (limited to 'lib/plugins/authpgsql')
-rw-r--r--lib/plugins/authpgsql/auth.php418
-rw-r--r--lib/plugins/authpgsql/conf/default.php3
-rw-r--r--lib/plugins/authpgsql/conf/metadata.php33
-rw-r--r--lib/plugins/authpgsql/lang/en/settings.php33
-rw-r--r--lib/plugins/authpgsql/plugin.info.txt7
5 files changed, 494 insertions, 0 deletions
diff --git a/lib/plugins/authpgsql/auth.php b/lib/plugins/authpgsql/auth.php
new file mode 100644
index 000000000..3f8ff3249
--- /dev/null
+++ b/lib/plugins/authpgsql/auth.php
@@ -0,0 +1,418 @@
+<?php
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * PostgreSQL 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 {
+
+ /**
+ * 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>
+ */
+ public function __construct() {
+ // we don't want the stuff the MySQL constructor does, but the grandparent might do something
+ DokuWiki_Auth_Plugin::__construct();
+
+ if(!function_exists('pg_connect')) {
+ $this->_debug("PgSQL err: PHP Postgres extension not found.", -1, __LINE__, __FILE__);
+ $this->success = false;
+ return;
+ }
+
+ $this->loadConfig();
+
+ // set capabilities based upon config strings set
+ if(empty($this->conf['user']) ||
+ empty($this->conf['password']) || empty($this->conf['database'])
+ ) {
+ $this->_debug("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>
+ *
+ * @param array $keys
+ * @param bool $wop
+ * @return bool
+ */
+ protected function _chkcnf($keys, $wop = false) {
+ foreach($keys as $key) {
+ if(empty($this->conf[$key])) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Counts users which meet certain $filter criteria.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param array $filter filter criteria in item/pattern pairs
+ * @return int count of found users.
+ */
+ public function getUserCount($filter = array()) {
+ $rc = 0;
+
+ if($this->_openDB()) {
+ $sql = $this->_createSQLFilter($this->conf['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
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param int $first index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array $filter array of field/pattern pairs
+ * @return array userinfo (refer getUserData for internal userinfo details)
+ */
+ public function retrieveUsers($first = 0, $limit = 10, $filter = array()) {
+ $out = array();
+
+ if($this->_openDB()) {
+ $this->_lockTables("READ");
+ $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter);
+ $sql .= " ".$this->conf['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 true non existing groups would be created.
+ *
+ * The database connection must already be established. Otherwise
+ * this function does nothing and returns 'false'.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $user user to add to a group
+ * @param string $group name of the group
+ * @param bool $force create missing groups
+ * @return bool true on success, false on error
+ */
+ protected function _addUserToGroup($user, $group, $force = false) {
+ $newgroup = 0;
+
+ if(($this->dbcon) && ($user)) {
+ $gid = $this->_getGroupID($group);
+ if(!$gid) {
+ if($force) { // create missing groups
+ $sql = str_replace('%{group}', addslashes($group), $this->conf['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->conf['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->conf['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 string $user login of the user
+ * @param string $pwd encrypted password
+ * @param string $name full name of the user
+ * @param string $mail email address
+ * @param array $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>
+ */
+ protected function _addUser($user, $pwd, $name, $mail, $grps) {
+ if($this->dbcon && is_array($grps)) {
+ $sql = str_replace('%{user}', addslashes($user), $this->conf['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;
+ }
+
+ $group = '';
+ $gid = false;
+
+ if($uid) {
+ foreach($grps as $group) {
+ $gid = $this->_addUserToGroup($user, $group, 1);
+ if($gid === false) break;
+ }
+
+ if($gid !== false){
+ 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);
+ $this->_debug("PgSQL err: Adding user '$user' to group '$group' failed.", -1, __LINE__, __FILE__);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 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.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @return bool
+ */
+ protected function _openDB() {
+ if(!$this->dbcon) {
+ $dsn = $this->conf['server'] ? 'host='.$this->conf['server'] : '';
+ $dsn .= ' port='.$this->conf['port'];
+ $dsn .= ' dbname='.$this->conf['database'];
+ $dsn .= ' user='.$this->conf['user'];
+ $dsn .= ' password='.$this->conf['password'];
+
+ $con = @pg_connect($dsn);
+ if($con) {
+ $this->dbcon = $con;
+ return true; // connection and database successfully opened
+ } else {
+ $this->_debug(
+ "PgSQL err: Connection to {$this->conf['user']}@{$this->conf['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>
+ */
+ protected 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.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $query SQL string that contains the query
+ * @return array the result table
+ */
+ protected function _queryDB($query) {
+ $resultarray = array();
+ 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;
+ } else{
+ $this->_debug('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 <andi@splitbrain.org>
+ */
+ protected function _modifyDB($query) {
+ if($this->dbcon) {
+ $result = @pg_query($this->dbcon, $query);
+ if($result) {
+ pg_free_result($result);
+ return true;
+ }
+ $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__);
+ }
+ return false;
+ }
+
+ /**
+ * Start a transaction
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $mode could be 'READ' or 'WRITE'
+ * @return bool
+ */
+ protected function _lockTables($mode) {
+ if($this->dbcon) {
+ $this->_modifyDB('BEGIN');
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Commit a transaction
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ protected function _unlockTables() {
+ if($this->dbcon) {
+ $this->_modifyDB('COMMIT');
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Escape a string for insertion into the database
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $string The string to escape
+ * @param bool $like Escape wildcard chars as well?
+ * @return string
+ */
+ protected function _escape($string, $like = false) {
+ $string = pg_escape_string($string);
+ if($like) {
+ $string = addcslashes($string, '%_');
+ }
+ return $string;
+ }
+} \ No newline at end of file
diff --git a/lib/plugins/authpgsql/conf/default.php b/lib/plugins/authpgsql/conf/default.php
new file mode 100644
index 000000000..401da80b7
--- /dev/null
+++ b/lib/plugins/authpgsql/conf/default.php
@@ -0,0 +1,3 @@
+<?php
+
+$conf['port'] = 5432; \ No newline at end of file
diff --git a/lib/plugins/authpgsql/conf/metadata.php b/lib/plugins/authpgsql/conf/metadata.php
new file mode 100644
index 000000000..d52a17865
--- /dev/null
+++ b/lib/plugins/authpgsql/conf/metadata.php
@@ -0,0 +1,33 @@
+<?php
+
+$meta['server'] = array('string');
+$meta['port'] = array('numeric');
+$meta['user'] = array('string');
+$meta['password'] = array('password');
+$meta['database'] = array('string');
+$meta['debug'] = array('onoff');
+$meta['forwardClearPass'] = array('onoff');
+$meta['checkPass'] = array('');
+$meta['getUserInfo'] = array('');
+$meta['getGroups'] = array('');
+$meta['getUsers'] = array('');
+$meta['FilterLogin'] = array('string');
+$meta['FilterName'] = array('string');
+$meta['FilterEmail'] = array('string');
+$meta['FilterGroup'] = array('string');
+$meta['SortOrder'] = array('string');
+$meta['addUser'] = array('');
+$meta['addGroup'] = array('');
+$meta['addUserGroup'] = array('');
+$meta['delGroup'] = array('');
+$meta['getUserID'] = array('');
+$meta['delUser'] = array('');
+$meta['delUserRefs'] = array('');
+$meta['updateUser'] = array('string');
+$meta['UpdateLogin'] = array('string');
+$meta['UpdatePass'] = array('string');
+$meta['UpdateEmail'] = array('string');
+$meta['UpdateName'] = array('string');
+$meta['UpdateTarget'] = array('string');
+$meta['delUserGroup'] = array('');
+$meta['getGroupID'] = array(''); \ No newline at end of file
diff --git a/lib/plugins/authpgsql/lang/en/settings.php b/lib/plugins/authpgsql/lang/en/settings.php
new file mode 100644
index 000000000..74a1c1cc9
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/en/settings.php
@@ -0,0 +1,33 @@
+<?php
+
+$lang['server'] = 'Your PostgreSQL server';
+$lang['port'] = 'Your PostgreSQL server\'s port';
+$lang['user'] = 'PostreSQL user name';
+$lang['password'] = 'Password for above user';
+$lang['database'] = 'Database to use';
+$lang['debug'] = 'Display additional debug information';
+$lang['forwardClearPass'] = 'Pass user passwords as cleartext to the SQL statements below, instead of using the passcrypt option';
+$lang['checkPass'] = 'SQL statement for checking passwords';
+$lang['getUserInfo'] = 'SQL statement for retrieving user information';
+$lang['getGroups'] = 'SQL statement for retrieving a user\'s group memberships';
+$lang['getUsers'] = 'SQL statement to list all users';
+$lang['FilterLogin'] = 'SQL clause for filtering users by login name';
+$lang['FilterName'] = 'SQL clause for filtering users by full name';
+$lang['FilterEmail'] = 'SQL clause for filtering users by email address';
+$lang['FilterGroup'] = 'SQL clause for filtering users by group membership';
+$lang['SortOrder'] = 'SQL clause to sort users';
+$lang['addUser'] = 'SQL statement to add a new user';
+$lang['addGroup'] = 'SQL statement to add a new group';
+$lang['addUserGroup'] = 'SQL statment to add a user to an existing group';
+$lang['delGroup'] = 'SQL statement to remove a group';
+$lang['getUserID'] = 'SQL statement to get the primary ey of a user';
+$lang['delUser'] = 'SQL statement to delete a user';
+$lang['delUserRefs'] = 'SQL statement to remove a user from all groups';
+$lang['updateUser'] = 'SQL statement to update a user profile';
+$lang['UpdateLogin'] = 'Update clause for updating the user\'s login name';
+$lang['UpdatePass'] = 'Update clause for updating the user\'s password';
+$lang['UpdateEmail'] = 'Update clause for updating the user\'s email address';
+$lang['UpdateName'] = 'Update clause for updating the user\'s full name';
+$lang['UpdateTarget'] = 'Limit clause to identify the user when updating';
+$lang['delUserGroup'] = 'SQL statement to remove a user from a given group';
+$lang['getGroupID'] = 'SQL statement to get the primary key of a given group';
diff --git a/lib/plugins/authpgsql/plugin.info.txt b/lib/plugins/authpgsql/plugin.info.txt
new file mode 100644
index 000000000..598eb848b
--- /dev/null
+++ b/lib/plugins/authpgsql/plugin.info.txt
@@ -0,0 +1,7 @@
+base authad
+author Andreas Gohr
+email andi@splitbrain.org
+date 2012-10-06
+name active directory auth plugin
+desc Provides authentication against a Microsoft Active Directory
+url http://www.dokuwiki.org/plugin:authad