This commit is contained in:
4
.hg_archival.txt
Normal file
4
.hg_archival.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
repo: 3f045a88dd7014290a9bf60cbd740c8548dba967
|
||||||
|
node: 77b8809852f4a8599200c9a538f94319ca5a4ff4
|
||||||
|
branch: default
|
||||||
|
tag: v.2.3.1
|
||||||
14
.hgtags
Normal file
14
.hgtags
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
8401b998f40be1e93d05b5c4db61ba98932c3de3 v0.2
|
||||||
|
c74b035788ebbcade6bfae22963632f4c5f49540 v0.3
|
||||||
|
5ee6481afb63f32dcfeaf93a72c07c4bc2a1a993 v0.4
|
||||||
|
5ee6481afb63f32dcfeaf93a72c07c4bc2a1a993 v0.4
|
||||||
|
f9eb8e6e4b4f2bcb521554bc513cc94d9ccf6fbd v0.4
|
||||||
|
df3dc7358b79abdd7075ba78b58fff1da7fa3fde to
|
||||||
|
df3dc7358b79abdd7075ba78b58fff1da7fa3fde 0.5
|
||||||
|
df3dc7358b79abdd7075ba78b58fff1da7fa3fde to
|
||||||
|
0000000000000000000000000000000000000000 to
|
||||||
|
df3dc7358b79abdd7075ba78b58fff1da7fa3fde 0.5
|
||||||
|
0000000000000000000000000000000000000000 0.5
|
||||||
|
845b75d72ec18f3fbf2a74f1a1ec3cf54ca4a304 v0.7
|
||||||
|
599b774a4b6ac81b44971ac1a319fc41c04e3589 v2.3
|
||||||
|
1fedd27cb5d8c69a998c8278463c8e8abd1f371a v2.3.0
|
||||||
253
PasswordHash.php
Normal file
253
PasswordHash.php
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
<?php
|
||||||
|
#
|
||||||
|
# Portable PHP password hashing framework.
|
||||||
|
#
|
||||||
|
# Version 0.3 / genuine.
|
||||||
|
#
|
||||||
|
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
|
||||||
|
# the public domain. Revised in subsequent years, still public domain.
|
||||||
|
#
|
||||||
|
# There's absolutely no warranty.
|
||||||
|
#
|
||||||
|
# The homepage URL for this framework is:
|
||||||
|
#
|
||||||
|
# http://www.openwall.com/phpass/
|
||||||
|
#
|
||||||
|
# Please be sure to update the Version line if you edit this file in any way.
|
||||||
|
# It is suggested that you leave the main version number intact, but indicate
|
||||||
|
# your project name (after the slash) and add your own revision information.
|
||||||
|
#
|
||||||
|
# Please do not change the "private" password hashing method implemented in
|
||||||
|
# here, thereby making your hashes incompatible. However, if you must, please
|
||||||
|
# change the hash type identifier (the "$P$") to something different.
|
||||||
|
#
|
||||||
|
# Obviously, since this code is in the public domain, the above are not
|
||||||
|
# requirements (there can be none), but merely suggestions.
|
||||||
|
#
|
||||||
|
class PasswordHash {
|
||||||
|
var $itoa64;
|
||||||
|
var $iteration_count_log2;
|
||||||
|
var $portable_hashes;
|
||||||
|
var $random_state;
|
||||||
|
|
||||||
|
function PasswordHash($iteration_count_log2, $portable_hashes)
|
||||||
|
{
|
||||||
|
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||||
|
|
||||||
|
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
|
||||||
|
$iteration_count_log2 = 8;
|
||||||
|
$this->iteration_count_log2 = $iteration_count_log2;
|
||||||
|
|
||||||
|
$this->portable_hashes = $portable_hashes;
|
||||||
|
|
||||||
|
$this->random_state = microtime();
|
||||||
|
if (function_exists('getmypid'))
|
||||||
|
$this->random_state .= getmypid();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_random_bytes($count)
|
||||||
|
{
|
||||||
|
$output = '';
|
||||||
|
if (is_readable('/dev/urandom') &&
|
||||||
|
($fh = @fopen('/dev/urandom', 'rb'))) {
|
||||||
|
$output = fread($fh, $count);
|
||||||
|
fclose($fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($output) < $count) {
|
||||||
|
$output = '';
|
||||||
|
for ($i = 0; $i < $count; $i += 16) {
|
||||||
|
$this->random_state =
|
||||||
|
md5(microtime() . $this->random_state);
|
||||||
|
$output .=
|
||||||
|
pack('H*', md5($this->random_state));
|
||||||
|
}
|
||||||
|
$output = substr($output, 0, $count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function encode64($input, $count)
|
||||||
|
{
|
||||||
|
$output = '';
|
||||||
|
$i = 0;
|
||||||
|
do {
|
||||||
|
$value = ord($input[$i++]);
|
||||||
|
$output .= $this->itoa64[$value & 0x3f];
|
||||||
|
if ($i < $count)
|
||||||
|
$value |= ord($input[$i]) << 8;
|
||||||
|
$output .= $this->itoa64[($value >> 6) & 0x3f];
|
||||||
|
if ($i++ >= $count)
|
||||||
|
break;
|
||||||
|
if ($i < $count)
|
||||||
|
$value |= ord($input[$i]) << 16;
|
||||||
|
$output .= $this->itoa64[($value >> 12) & 0x3f];
|
||||||
|
if ($i++ >= $count)
|
||||||
|
break;
|
||||||
|
$output .= $this->itoa64[($value >> 18) & 0x3f];
|
||||||
|
} while ($i < $count);
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gensalt_private($input)
|
||||||
|
{
|
||||||
|
$output = '$P$';
|
||||||
|
$output .= $this->itoa64[min($this->iteration_count_log2 +
|
||||||
|
((PHP_VERSION >= '5') ? 5 : 3), 30)];
|
||||||
|
$output .= $this->encode64($input, 6);
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function crypt_private($password, $setting)
|
||||||
|
{
|
||||||
|
$output = '*0';
|
||||||
|
if (substr($setting, 0, 2) === $output)
|
||||||
|
$output = '*1';
|
||||||
|
|
||||||
|
$id = substr($setting, 0, 3);
|
||||||
|
# We use "$P$", phpBB3 uses "$H$" for the same thing
|
||||||
|
if ($id !== '$P$' && $id !== '$H$')
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
$count_log2 = strpos($this->itoa64, $setting[3]);
|
||||||
|
if ($count_log2 < 7 || $count_log2 > 30)
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
$count = 1 << $count_log2;
|
||||||
|
|
||||||
|
$salt = substr($setting, 4, 8);
|
||||||
|
if (strlen($salt) !== 8)
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
# We're kind of forced to use MD5 here since it's the only
|
||||||
|
# cryptographic primitive available in all versions of PHP
|
||||||
|
# currently in use. To implement our own low-level crypto
|
||||||
|
# in PHP would result in much worse performance and
|
||||||
|
# consequently in lower iteration counts and hashes that are
|
||||||
|
# quicker to crack (by non-PHP code).
|
||||||
|
if (PHP_VERSION >= '5') {
|
||||||
|
$hash = md5($salt . $password, TRUE);
|
||||||
|
do {
|
||||||
|
$hash = md5($hash . $password, TRUE);
|
||||||
|
} while (--$count);
|
||||||
|
} else {
|
||||||
|
$hash = pack('H*', md5($salt . $password));
|
||||||
|
do {
|
||||||
|
$hash = pack('H*', md5($hash . $password));
|
||||||
|
} while (--$count);
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = substr($setting, 0, 12);
|
||||||
|
$output .= $this->encode64($hash, 16);
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gensalt_extended($input)
|
||||||
|
{
|
||||||
|
$count_log2 = min($this->iteration_count_log2 + 8, 24);
|
||||||
|
# This should be odd to not reveal weak DES keys, and the
|
||||||
|
# maximum valid value is (2**24 - 1) which is odd anyway.
|
||||||
|
$count = (1 << $count_log2) - 1;
|
||||||
|
|
||||||
|
$output = '_';
|
||||||
|
$output .= $this->itoa64[$count & 0x3f];
|
||||||
|
$output .= $this->itoa64[($count >> 6) & 0x3f];
|
||||||
|
$output .= $this->itoa64[($count >> 12) & 0x3f];
|
||||||
|
$output .= $this->itoa64[($count >> 18) & 0x3f];
|
||||||
|
|
||||||
|
$output .= $this->encode64($input, 3);
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gensalt_blowfish($input)
|
||||||
|
{
|
||||||
|
# This one needs to use a different order of characters and a
|
||||||
|
# different encoding scheme from the one in encode64() above.
|
||||||
|
# We care because the last character in our encoded string will
|
||||||
|
# only represent 2 bits. While two known implementations of
|
||||||
|
# bcrypt will happily accept and correct a salt string which
|
||||||
|
# has the 4 unused bits set to non-zero, we do not want to take
|
||||||
|
# chances and we also do not want to waste an additional byte
|
||||||
|
# of entropy.
|
||||||
|
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
|
$output = '$2a$';
|
||||||
|
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
|
||||||
|
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
|
||||||
|
$output .= '$';
|
||||||
|
|
||||||
|
$i = 0;
|
||||||
|
do {
|
||||||
|
$c1 = ord($input[$i++]);
|
||||||
|
$output .= $itoa64[$c1 >> 2];
|
||||||
|
$c1 = ($c1 & 0x03) << 4;
|
||||||
|
if ($i >= 16) {
|
||||||
|
$output .= $itoa64[$c1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$c2 = ord($input[$i++]);
|
||||||
|
$c1 |= $c2 >> 4;
|
||||||
|
$output .= $itoa64[$c1];
|
||||||
|
$c1 = ($c2 & 0x0f) << 2;
|
||||||
|
|
||||||
|
$c2 = ord($input[$i++]);
|
||||||
|
$c1 |= $c2 >> 6;
|
||||||
|
$output .= $itoa64[$c1];
|
||||||
|
$output .= $itoa64[$c2 & 0x3f];
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HashPassword($password)
|
||||||
|
{
|
||||||
|
$random = '';
|
||||||
|
|
||||||
|
if (CRYPT_BLOWFISH === 1 && !$this->portable_hashes) {
|
||||||
|
$random = $this->get_random_bytes(16);
|
||||||
|
$hash =
|
||||||
|
crypt($password, $this->gensalt_blowfish($random));
|
||||||
|
if (strlen($hash) === 60)
|
||||||
|
return $hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CRYPT_EXT_DES === 1 && !$this->portable_hashes) {
|
||||||
|
if (strlen($random) < 3)
|
||||||
|
$random = $this->get_random_bytes(3);
|
||||||
|
$hash =
|
||||||
|
crypt($password, $this->gensalt_extended($random));
|
||||||
|
if (strlen($hash) === 20)
|
||||||
|
return $hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($random) < 6)
|
||||||
|
$random = $this->get_random_bytes(6);
|
||||||
|
$hash =
|
||||||
|
$this->crypt_private($password,
|
||||||
|
$this->gensalt_private($random));
|
||||||
|
if (strlen($hash) === 34)
|
||||||
|
return $hash;
|
||||||
|
|
||||||
|
# Returning '*' on error is safe here, but would _not_ be safe
|
||||||
|
# in a crypt(3)-like function used _both_ for generating new
|
||||||
|
# hashes and for validating passwords against existing hashes.
|
||||||
|
return '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
function CheckPassword($password, $stored_hash)
|
||||||
|
{
|
||||||
|
$hash = $this->crypt_private($password, $stored_hash);
|
||||||
|
if ($hash[0] === '*')
|
||||||
|
$hash = crypt($password, $stored_hash);
|
||||||
|
|
||||||
|
return $hash === $stored_hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
user_sql
|
||||||
|
========
|
||||||
|
|
||||||
|
Owncloud SQL authentification
|
||||||
|
|
||||||
|
This is plugin is heavily based on user_imap, user_pwauth, user_ldap and user_redmine!
|
||||||
|
|
||||||
|
Enable it in your Admin -> Apps section and configure your server's details.
|
||||||
|
Currently, it supports most of postfixadmin's encryption options, except dovecot and saslauthd.
|
||||||
|
It was tested and developed for a postfixadmin database.
|
||||||
|
|
||||||
|
Password changing is disabled by default, but can be enabled in the Admin area.
|
||||||
|
Caution: user_sql does not recreate password salts, which imposes a security risk.
|
||||||
|
Password salts should be newly generated whenever the password changes.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
|
||||||
|
* Johan Hendriks provided his user_postfixadmin
|
||||||
|
* Ed Wildgoose for fixing possible SQL injection vulnerability
|
||||||
260
ajax/settings.php
Normal file
260
ajax/settings.php
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - user_sql
|
||||||
|
*
|
||||||
|
* @author Andreas Böhler and contributors
|
||||||
|
* @copyright 2012-2015 Andreas Böhler <dev (at) aboehler (dot) at>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the AJAX portion of the settings page.
|
||||||
|
*
|
||||||
|
* It can:
|
||||||
|
* - Verify the connection settings
|
||||||
|
* - Load autocomplete values for tables
|
||||||
|
* - Load autocomplete values for columns
|
||||||
|
* - Save settings for a given domain
|
||||||
|
* - Load settings for a given domain
|
||||||
|
*
|
||||||
|
* It always returns JSON encoded responses
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\user_sql;
|
||||||
|
|
||||||
|
// Init owncloud
|
||||||
|
|
||||||
|
// Check if we are a user
|
||||||
|
\OCP\User::checkAdminUser();
|
||||||
|
\OCP\JSON::checkAppEnabled('user_sql');
|
||||||
|
|
||||||
|
// CSRF checks
|
||||||
|
\OCP\JSON::callCheck();
|
||||||
|
|
||||||
|
|
||||||
|
$helper = new \OCA\user_sql\lib\Helper;
|
||||||
|
|
||||||
|
$l = \OC::$server->getL10N('user_sql');
|
||||||
|
|
||||||
|
$params = $helper -> getParameterArray();
|
||||||
|
$response = new \OCP\AppFramework\Http\JSONResponse();
|
||||||
|
|
||||||
|
// Check if the request is for us
|
||||||
|
if(isset($_POST['appname']) && ($_POST['appname'] === 'user_sql') && isset($_POST['function']) && isset($_POST['domain']))
|
||||||
|
{
|
||||||
|
$domain = $_POST['domain'];
|
||||||
|
switch($_POST['function'])
|
||||||
|
{
|
||||||
|
// Save the settings for the given domain to the database
|
||||||
|
case 'saveSettings':
|
||||||
|
$parameters = array('host' => $_POST['sql_hostname'],
|
||||||
|
'password' => $_POST['sql_password'],
|
||||||
|
'user' => $_POST['sql_username'],
|
||||||
|
'dbname' => $_POST['sql_database'],
|
||||||
|
'tablePrefix' => ''
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if the table exists
|
||||||
|
if(!$helper->verifyTable($parameters, $_POST['sql_driver'], $_POST['sql_table']))
|
||||||
|
{
|
||||||
|
$response->setData(array('status' => 'error',
|
||||||
|
'data' => array('message' => $l -> t('The selected SQL table '.$_POST['sql_table'].' does not exist!'))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve all column settings
|
||||||
|
$columns = array();
|
||||||
|
foreach($params as $param)
|
||||||
|
{
|
||||||
|
if(strpos($param, 'col_') === 0)
|
||||||
|
{
|
||||||
|
if(isset($_POST[$param]) && $_POST[$param] !== '')
|
||||||
|
$columns[] = $_POST[$param];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the columns exist
|
||||||
|
$status = $helper->verifyColumns($parameters, $_POST['sql_driver'], $_POST['sql_table'], $columns);
|
||||||
|
if($status !== true)
|
||||||
|
{
|
||||||
|
$response->setData(array('status' => 'error',
|
||||||
|
'data' => array('message' => $l -> t('The selected SQL column(s) do(es) not exist: '.$status))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach this point, all settings have been verified
|
||||||
|
foreach($params as $param)
|
||||||
|
{
|
||||||
|
// Special handling for checkbox fields
|
||||||
|
if(isset($_POST[$param]))
|
||||||
|
{
|
||||||
|
if($param === 'set_strip_domain')
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', 'set_strip_domain_'.$domain, 'true');
|
||||||
|
}
|
||||||
|
elseif($param === 'set_allow_pwchange')
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', 'set_allow_pwchange_'.$domain, 'true');
|
||||||
|
}
|
||||||
|
elseif($param === 'set_active_invert')
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', 'set_active_invert_'.$domain, 'true');
|
||||||
|
}
|
||||||
|
elseif($param === 'set_enable_gethome')
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', 'set_enable_gethome_'.$domain, 'true');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', $param.'_'.$domain, $_POST[$param]);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if($param === 'set_strip_domain')
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', 'set_strip_domain_'.$domain, 'false');
|
||||||
|
}
|
||||||
|
elseif($param === 'set_allow_pwchange')
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', 'set_allow_pwchange_'.$domain, 'false');
|
||||||
|
}
|
||||||
|
elseif($param === 'set_active_invert')
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', 'set_active_invert_'.$domain, 'false');
|
||||||
|
}
|
||||||
|
elseif($param === 'set_enable_gethome')
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', 'set_enable_gethome_'.$domain, 'false');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$response->setData(array('status' => 'success',
|
||||||
|
'data' => array('message' => $l -> t('Application settings successfully stored.'))));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Load the settings for a given domain
|
||||||
|
case 'loadSettingsForDomain':
|
||||||
|
$retArr = array();
|
||||||
|
foreach($params as $param)
|
||||||
|
{
|
||||||
|
$retArr[$param] = \OC::$server->getConfig()->getAppValue('user_sql', $param.'_'.$domain, '');
|
||||||
|
}
|
||||||
|
$response->setData(array('status' => 'success',
|
||||||
|
'settings' => $retArr));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Try to verify the database connection settings
|
||||||
|
case 'verifySettings':
|
||||||
|
$cm = new \OC\DB\ConnectionFactory();
|
||||||
|
|
||||||
|
if(!isset($_POST['sql_driver']))
|
||||||
|
{
|
||||||
|
$response->setData(array('status' => 'error',
|
||||||
|
'data' => array('message' => $l -> t('Error connecting to database: No driver specified.'))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(($_POST['sql_hostname'] === '') || ($_POST['sql_database'] === ''))
|
||||||
|
{
|
||||||
|
$response->setData(array('status' => 'error',
|
||||||
|
'data' => array('message' => $l -> t('Error connecting to database: You must specify at least host and database'))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parameters = array('host' => $_POST['sql_hostname'],
|
||||||
|
'password' => $_POST['sql_password'],
|
||||||
|
'user' => $_POST['sql_username'],
|
||||||
|
'dbname' => $_POST['sql_database'],
|
||||||
|
'tablePrefix' => ''
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$conn = $cm -> getConnection($_POST['sql_driver'], $parameters);
|
||||||
|
$response->setData(array('status' => 'success',
|
||||||
|
'data' => array('message' => $l -> t('Successfully connected to database'))));
|
||||||
|
}
|
||||||
|
catch(\Exception $e)
|
||||||
|
{
|
||||||
|
$response->setData(array('status' => 'error',
|
||||||
|
'data' => array('message' => $l -> t('Error connecting to database: ').$e->getMessage())));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Get the autocompletion values for a column
|
||||||
|
case 'getColumnAutocomplete':
|
||||||
|
|
||||||
|
|
||||||
|
$parameters = array('host' => $_POST['sql_hostname'],
|
||||||
|
'password' => $_POST['sql_password'],
|
||||||
|
'user' => $_POST['sql_username'],
|
||||||
|
'dbname' => $_POST['sql_database'],
|
||||||
|
'tablePrefix' => ''
|
||||||
|
);
|
||||||
|
|
||||||
|
if($helper->verifyTable($parameters, $_POST['sql_driver'], $_POST['sql_table']))
|
||||||
|
$columns = $helper->getColumns($parameters, $_POST['sql_driver'], $_POST['sql_table']);
|
||||||
|
else
|
||||||
|
$columns = array();
|
||||||
|
|
||||||
|
$search = $_POST['request'];
|
||||||
|
$ret = array();
|
||||||
|
|
||||||
|
foreach($columns as $name)
|
||||||
|
{
|
||||||
|
if(($search === '') || ($search === 'search') || (strpos($name, $search) === 0))
|
||||||
|
{
|
||||||
|
$ret[] = array('label' => $name,
|
||||||
|
'value' => $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$response -> setData($ret);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Get the autocompletion values for a table
|
||||||
|
case 'getTableAutocomplete':
|
||||||
|
$parameters = array('host' => $_POST['sql_hostname'],
|
||||||
|
'password' => $_POST['sql_password'],
|
||||||
|
'user' => $_POST['sql_username'],
|
||||||
|
'dbname' => $_POST['sql_database'],
|
||||||
|
'tablePrefix' => ''
|
||||||
|
);
|
||||||
|
|
||||||
|
$tables = $helper->getTables($parameters, $_POST['sql_driver']);
|
||||||
|
|
||||||
|
$search = $_POST['request'];
|
||||||
|
$ret = array();
|
||||||
|
foreach($tables as $name)
|
||||||
|
{
|
||||||
|
if(($search === '') || ($search === 'search') || (strpos($name, $search) === 0))
|
||||||
|
{
|
||||||
|
$ret[] = array('label' => $name,
|
||||||
|
'value' => $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$response -> setData($ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// If the request was not for us, set an error message
|
||||||
|
$response->setData(array('status' => 'error',
|
||||||
|
'data' => array('message' => $l -> t('Not submitted for us.'))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the JSON array
|
||||||
|
echo $response->render();
|
||||||
31
appinfo/app.php
Normal file
31
appinfo/app.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - user_sql
|
||||||
|
*
|
||||||
|
* @author Andreas Böhler
|
||||||
|
* @copyright 2012-2015 Andreas Böhler <dev (at) aboehler (dot) at>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('apps/user_sql/user_sql.php');
|
||||||
|
\OCP\App::registerAdmin('user_sql','settings');
|
||||||
|
|
||||||
|
$backend = new \OCA\user_sql\OC_USER_SQL;
|
||||||
|
|
||||||
|
|
||||||
|
// register user backend
|
||||||
|
\OC_User::useBackend($backend);
|
||||||
20
appinfo/info.xml
Normal file
20
appinfo/info.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<info>
|
||||||
|
<id>user_sql</id>
|
||||||
|
<name>SQL user backend</name>
|
||||||
|
<summary>Authenticate Users by SQL</summary>
|
||||||
|
<description>Authenticate Users by SQL</description>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
<licence>agpl</licence>
|
||||||
|
<author>Andreas Boehler <dev (at) aboehler
|
||||||
|
(dot) at ></author>
|
||||||
|
<namespace>user_sql</namespace>
|
||||||
|
<types>
|
||||||
|
<authentication/>
|
||||||
|
</types>
|
||||||
|
<category>auth</category>
|
||||||
|
<dependencies>
|
||||||
|
<owncloud min-version="8.1" max-version="9.1"/>
|
||||||
|
<nextcloud min-version="9" max-version="10"/>
|
||||||
|
</dependencies>
|
||||||
|
</info>
|
||||||
8
appinfo/routes.php
Normal file
8
appinfo/routes.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015, Andreas Böhler <dev@aboehler.at>
|
||||||
|
* This file is licensed under the Affero General Public License version 3 or later.
|
||||||
|
* See the COPYING-README file.
|
||||||
|
*/
|
||||||
|
/** @var $this \OCP\Route\IRouter */
|
||||||
|
$this->create('user_sql_ajax_settings', 'ajax/settings.php')->actionInclude('user_sql/ajax/settings.php');
|
||||||
71
appinfo/update.php
Normal file
71
appinfo/update.php
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - user_sql
|
||||||
|
*
|
||||||
|
* @author Andreas Böhler and contributors
|
||||||
|
* @copyright 2012-2015 Andreas Böhler <dev (at) aboehler (dot) at>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
$installedVersion = \OC::$server->getConfig()->getAppValue('user_sql', 'installed_version');
|
||||||
|
|
||||||
|
$params = array('sql_host' => 'sql_hostname',
|
||||||
|
'sql_user' => 'sql_username',
|
||||||
|
'sql_database' => 'sql_database',
|
||||||
|
'sql_password' => 'sql_password',
|
||||||
|
'sql_table' => 'sql_table',
|
||||||
|
'sql_column_username' => 'col_username',
|
||||||
|
'sql_column_password' => 'col_password',
|
||||||
|
'sql_type' => 'sql_driver',
|
||||||
|
'sql_column_active' => 'col_active',
|
||||||
|
'strip_domain' => 'set_strip_domain',
|
||||||
|
'default_domain' => 'set_default_domain',
|
||||||
|
'crypt_type' => 'set_crypt_type',
|
||||||
|
'sql_column_displayname' => 'col_displayname',
|
||||||
|
'allow_password_change' => 'set_allow_pwchange',
|
||||||
|
'sql_column_active_invert' => 'set_active_invert',
|
||||||
|
'sql_column_email' => 'col_email',
|
||||||
|
'mail_sync_mode' => 'set_mail_sync_mode'
|
||||||
|
);
|
||||||
|
|
||||||
|
$delParams = array('domain_settings',
|
||||||
|
'map_array',
|
||||||
|
'domain_array'
|
||||||
|
);
|
||||||
|
|
||||||
|
if(version_compare($installedVersion, '1.99', '<'))
|
||||||
|
{
|
||||||
|
foreach($params as $oldPar => $newPar)
|
||||||
|
{
|
||||||
|
$val = \OC::$server->getConfig()->getAppValue('user_sql', $oldPar);
|
||||||
|
if(($oldPar === 'strip_domain') || ($oldPar === 'allow_password_change') || ($oldPar === 'sql_column_active_invert'))
|
||||||
|
{
|
||||||
|
if($val)
|
||||||
|
$val = 'true';
|
||||||
|
else
|
||||||
|
$val = 'false';
|
||||||
|
}
|
||||||
|
if($val)
|
||||||
|
\OC::$server->getConfig()->setAppValue('user_sql', $newPar.'_default', $val);
|
||||||
|
\OC::$server->getConfig()->deleteAppValue('user_sql', $oldPar);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($delParams as $param)
|
||||||
|
{
|
||||||
|
\OC::$server->getConfig()->deleteAppValue('user_sql', $param);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
css/settings.css
Normal file
24
css/settings.css
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
.statusmessage {
|
||||||
|
background-color: #DDDDFF;
|
||||||
|
}
|
||||||
|
.errormessage {
|
||||||
|
background-color: #FFDDDD;
|
||||||
|
}
|
||||||
|
.successmessage {
|
||||||
|
background-color: #DDFFDD;
|
||||||
|
}
|
||||||
|
.statusmessage,.errormessage,.successmessage{
|
||||||
|
display:none;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sql-1 p label:first-child,
|
||||||
|
#sql-2 p label:first-child,
|
||||||
|
#sql-3 p label:first-child,
|
||||||
|
#sql-4 p label:first-child,
|
||||||
|
#sql-5 p label:first-child {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: right;
|
||||||
|
width: 300px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
314
js/settings.js
Normal file
314
js/settings.js
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
// settings.js of user_sql
|
||||||
|
|
||||||
|
// declare namespace
|
||||||
|
var user_sql = user_sql ||
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init admin settings view
|
||||||
|
*/
|
||||||
|
user_sql.adminSettingsUI = function()
|
||||||
|
{
|
||||||
|
|
||||||
|
if($('#sqlDiv').length > 0)
|
||||||
|
{
|
||||||
|
// enable tabs on settings page
|
||||||
|
$('#sqlDiv').tabs();
|
||||||
|
|
||||||
|
// Attach auto-completion to all column fields
|
||||||
|
$('#col_username, #col_password, #col_displayname, #col_active, #col_email, #col_gethome').autocomplete({
|
||||||
|
source: function(request, response)
|
||||||
|
{
|
||||||
|
var post = $('#sqlForm').serializeArray();
|
||||||
|
var domain = $('#sql_domain_chooser option:selected').val();
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'function',
|
||||||
|
value: 'getColumnAutocomplete'
|
||||||
|
});
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'domain',
|
||||||
|
value: domain
|
||||||
|
});
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'request',
|
||||||
|
value: request.term
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ajax foobar
|
||||||
|
$.post(OC.filePath('user_sql', 'ajax', 'settings.php'), post, response, 'json');
|
||||||
|
},
|
||||||
|
minLength: 0,
|
||||||
|
open: function() {
|
||||||
|
$(this).attr('state', 'open');
|
||||||
|
},
|
||||||
|
close: function() {
|
||||||
|
$(this).attr('state', 'closed');
|
||||||
|
}
|
||||||
|
}).focus(function() {
|
||||||
|
if($(this).attr('state') != 'open')
|
||||||
|
{
|
||||||
|
$(this).autocomplete("search");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach auto-completion to all table fields
|
||||||
|
$('#sql_table').autocomplete({
|
||||||
|
source: function(request, response)
|
||||||
|
{
|
||||||
|
var post = $('#sqlForm').serializeArray();
|
||||||
|
var domain = $('#sql_domain_chooser option:selected').val();
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'function',
|
||||||
|
value: 'getTableAutocomplete'
|
||||||
|
});
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'domain',
|
||||||
|
value: domain
|
||||||
|
});
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'request',
|
||||||
|
value: request.term
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ajax foobar
|
||||||
|
$.post(OC.filePath('user_sql', 'ajax', 'settings.php'), post, response, 'json');
|
||||||
|
},
|
||||||
|
minLength: 0,
|
||||||
|
open: function() {
|
||||||
|
$(this).attr('state', 'open');
|
||||||
|
},
|
||||||
|
close: function() {
|
||||||
|
$(this).attr('state', 'closed');
|
||||||
|
}
|
||||||
|
}).focus(function() {
|
||||||
|
if($(this).attr('state') != 'open')
|
||||||
|
{
|
||||||
|
$(this).autocomplete("search");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify the SQL database settings
|
||||||
|
$('#sqlVerify').click(function(event)
|
||||||
|
{
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var post = $('#sqlForm').serializeArray();
|
||||||
|
var domain = $('#sql_domain_chooser option:selected').val();
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'function',
|
||||||
|
value: 'verifySettings'
|
||||||
|
});
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'domain',
|
||||||
|
value: domain
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#sql_verify_message').show();
|
||||||
|
$('#sql_success_message').hide();
|
||||||
|
$('#sql_error_message').hide();
|
||||||
|
$('#sql_update_message').hide();
|
||||||
|
// Ajax foobar
|
||||||
|
$.post(OC.filePath('user_sql', 'ajax', 'settings.php'), post, function(data)
|
||||||
|
{
|
||||||
|
$('#sql_verify_message').hide();
|
||||||
|
if(data.status == 'success')
|
||||||
|
{
|
||||||
|
$('#sql_success_message').html(data.data.message);
|
||||||
|
$('#sql_success_message').show();
|
||||||
|
window.setTimeout(function()
|
||||||
|
{
|
||||||
|
$('#sql_success_message').hide();
|
||||||
|
}, 10000);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$('#sql_error_message').html(data.data.message);
|
||||||
|
$('#sql_error_message').show();
|
||||||
|
}
|
||||||
|
}, 'json');
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save the settings for a domain
|
||||||
|
$('#sqlSubmit').click(function(event)
|
||||||
|
{
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var post = $('#sqlForm').serializeArray();
|
||||||
|
var domain = $('#sql_domain_chooser option:selected').val();
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'function',
|
||||||
|
value: 'saveSettings'
|
||||||
|
});
|
||||||
|
|
||||||
|
post.push({
|
||||||
|
name: 'domain',
|
||||||
|
value: domain
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#sql_update_message').show();
|
||||||
|
$('#sql_success_message').hide();
|
||||||
|
$('#sql_verify_message').hide();
|
||||||
|
$('#sql_error_message').hide();
|
||||||
|
// Ajax foobar
|
||||||
|
$.post(OC.filePath('user_sql', 'ajax', 'settings.php'), post, function(data)
|
||||||
|
{
|
||||||
|
$('#sql_update_message').hide();
|
||||||
|
if(data.status == 'success')
|
||||||
|
{
|
||||||
|
$('#sql_success_message').html(data.data.message);
|
||||||
|
$('#sql_success_message').show();
|
||||||
|
window.setTimeout(function()
|
||||||
|
{
|
||||||
|
$('#sql_success_message').hide();
|
||||||
|
}, 10000);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$('#sql_error_message').html(data.data.message);
|
||||||
|
$('#sql_error_message').show();
|
||||||
|
}
|
||||||
|
}, 'json');
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach event handler to the domain chooser
|
||||||
|
$('#sql_domain_chooser').change(function() {
|
||||||
|
user_sql.loadDomainSettings($('#sql_domain_chooser option:selected').val());
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#set_gethome_mode').change(function() {
|
||||||
|
user_sql.setGethomeMode();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#set_enable_gethome').change(function() {
|
||||||
|
user_sql.setGethomeMode();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
user_sql.setGethomeMode = function()
|
||||||
|
{
|
||||||
|
var enabled = $('#set_enable_gethome').prop('checked');
|
||||||
|
if(enabled)
|
||||||
|
{
|
||||||
|
$('#set_gethome_mode').prop('disabled', false);
|
||||||
|
var val = $('#set_gethome_mode option:selected').val();
|
||||||
|
if(val === 'query')
|
||||||
|
{
|
||||||
|
$('#set_gethome').prop('disabled', true);
|
||||||
|
$('#col_gethome').prop('disabled', false);
|
||||||
|
}
|
||||||
|
else if(val === 'static')
|
||||||
|
{
|
||||||
|
$('#set_gethome').prop('disabled', false);
|
||||||
|
$('#col_gethome').prop('disabled', true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#set_gethome').prop('disabled', true);
|
||||||
|
$('#col_gethome').prop('disabled', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#set_gethome_mode').prop('disabled', true);
|
||||||
|
$('#set_gethome').prop('disabled', true);
|
||||||
|
$('#col_gethome').prop('disabled', true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the settings for the selected domain
|
||||||
|
* @param string domain The domain to load
|
||||||
|
*/
|
||||||
|
user_sql.loadDomainSettings = function(domain)
|
||||||
|
{
|
||||||
|
$('#sql_success_message').hide();
|
||||||
|
$('#sql_error_message').hide();
|
||||||
|
$('#sql_verify_message').hide();
|
||||||
|
$('#sql_loading_message').show();
|
||||||
|
var post = [
|
||||||
|
{
|
||||||
|
name: 'appname',
|
||||||
|
value: 'user_sql'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'function',
|
||||||
|
value: 'loadSettingsForDomain'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'domain',
|
||||||
|
value: domain
|
||||||
|
}
|
||||||
|
];
|
||||||
|
$.post(OC.filePath('user_sql', 'ajax', 'settings.php'), post, function(data)
|
||||||
|
{
|
||||||
|
$('#sql_loading_message').hide();
|
||||||
|
if(data.status == 'success')
|
||||||
|
{
|
||||||
|
for(key in data.settings)
|
||||||
|
{
|
||||||
|
if(key == 'set_strip_domain')
|
||||||
|
{
|
||||||
|
if(data.settings[key] == 'true')
|
||||||
|
$('#' + key).prop('checked', true);
|
||||||
|
else
|
||||||
|
$('#' + key).prop('checked', false);
|
||||||
|
}
|
||||||
|
else if(key == 'set_allow_pwchange')
|
||||||
|
{
|
||||||
|
if(data.settings[key] == 'true')
|
||||||
|
$('#' + key).prop('checked', true);
|
||||||
|
else
|
||||||
|
$('#' + key).prop('checked', false);
|
||||||
|
}
|
||||||
|
else if(key == 'set_active_invert')
|
||||||
|
{
|
||||||
|
if(data.settings[key] == 'true')
|
||||||
|
$('#' + key).prop('checked', true);
|
||||||
|
else
|
||||||
|
$('#' + key).prop('checked', false);
|
||||||
|
}
|
||||||
|
else if(key == 'set_enable_gethome')
|
||||||
|
{
|
||||||
|
if(data.settings[key] == 'true')
|
||||||
|
$('#' + key).prop('checked', true);
|
||||||
|
else
|
||||||
|
$('#' + key).prop('checked', false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#' + key).val(data.settings[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#sql_error_message').html(data.data.message);
|
||||||
|
$('#sql_error_message').show();
|
||||||
|
}
|
||||||
|
user_sql.setGethomeMode();
|
||||||
|
}, 'json'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run our JS if the SQL settings are present
|
||||||
|
$(document).ready(function()
|
||||||
|
{
|
||||||
|
if($('#sqlDiv'))
|
||||||
|
{
|
||||||
|
user_sql.adminSettingsUI();
|
||||||
|
user_sql.loadDomainSettings($('#sql_domain_chooser option:selected').val());
|
||||||
|
user_sql.setGethomeMode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
348
lib/helper.php
Normal file
348
lib/helper.php
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - user_sql
|
||||||
|
*
|
||||||
|
* @author Andreas Böhler and contributors
|
||||||
|
* @copyright 2012-2015 Andreas Böhler <dev (at) aboehler (dot) at>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\user_sql\lib;
|
||||||
|
|
||||||
|
class Helper {
|
||||||
|
|
||||||
|
protected $db;
|
||||||
|
protected $db_conn;
|
||||||
|
protected $settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default constructor initializes some parameters
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->db_conn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array with all supported parameters
|
||||||
|
* @return array Containing strings of the parameters
|
||||||
|
*/
|
||||||
|
public function getParameterArray()
|
||||||
|
{
|
||||||
|
$params = array(
|
||||||
|
'sql_hostname',
|
||||||
|
'sql_username',
|
||||||
|
'sql_password',
|
||||||
|
'sql_database',
|
||||||
|
'sql_table',
|
||||||
|
'sql_driver',
|
||||||
|
'col_username',
|
||||||
|
'col_password',
|
||||||
|
'col_active',
|
||||||
|
'col_displayname',
|
||||||
|
'col_email',
|
||||||
|
'col_gethome',
|
||||||
|
'set_active_invert',
|
||||||
|
'set_allow_pwchange',
|
||||||
|
'set_default_domain',
|
||||||
|
'set_strip_domain',
|
||||||
|
'set_crypt_type',
|
||||||
|
'set_mail_sync_mode',
|
||||||
|
'set_enable_gethome',
|
||||||
|
'set_gethome_mode',
|
||||||
|
'set_gethome'
|
||||||
|
);
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the settings for a given domain. If the domain is not found,
|
||||||
|
* the settings for 'default' are returned instead.
|
||||||
|
* @param string $domain The domain name
|
||||||
|
* @return array of settings
|
||||||
|
*/
|
||||||
|
public function loadSettingsForDomain($domain)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Trying to load settings for domain: " . $domain, \OCP\Util::DEBUG);
|
||||||
|
$settings = array();
|
||||||
|
$sql_host = \OC::$server->getConfig()->getAppValue('user_sql', 'sql_hostname_'.$domain, '');
|
||||||
|
if($sql_host === '')
|
||||||
|
{
|
||||||
|
$domain = 'default';
|
||||||
|
}
|
||||||
|
$params = $this -> getParameterArray();
|
||||||
|
foreach($params as $param)
|
||||||
|
{
|
||||||
|
$settings[$param] = \OC::$server->getConfig()->getAppValue('user_sql', $param.'_'.$domain, '');
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Loaded settings for domain: " . $domain, \OCP\Util::DEBUG);
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a given query type and return the results
|
||||||
|
* @param string $type The type of query to run
|
||||||
|
* @param array $params The parameter array of the query (i.e. the values to bind as key-value pairs)
|
||||||
|
* @param bool $execOnly Only execute the query, but don't fetch the results (optional, default = false)
|
||||||
|
* @param bool $fetchArray Fetch an array instead of a single row (optional, default=false)
|
||||||
|
* @param array $limits use the given limits for the query (optional, default = empty)
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function runQuery($type, $params, $execOnly = false, $fetchArray = false, $limits = array())
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering runQuery for type: " . $type, \OCP\Util::DEBUG);
|
||||||
|
if(!$this -> db_conn)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch($type)
|
||||||
|
{
|
||||||
|
case 'getHome':
|
||||||
|
$query = "SELECT ".$this->settings['col_gethome']." FROM ".$this->settings['sql_table']." WHERE ".$this->settings['col_username']." = :uid";
|
||||||
|
break;
|
||||||
|
case 'getMail':
|
||||||
|
$query = "SELECT ".$this->settings['col_email']." FROM ".$this->settings['sql_table']." WHERE ".$this->settings['col_username']." = :uid";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'setMail':
|
||||||
|
$query = "UPDATE ".$this->settings['sql_table']." SET ".$this->settings['col_email']." = :currMail WHERE ".$this->settings['col_username']." = :uid";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getPass':
|
||||||
|
$query = "SELECT ".$this->settings['col_password']." FROM ".$this->settings['sql_table']." WHERE ".$this->settings['col_username']." = :uid";
|
||||||
|
if($this -> settings['col_active'] !== '')
|
||||||
|
$query .= " AND " .($this -> settings['set_active_invert'] === 'true' ? "NOT " : "" ) . $this -> settings['col_active'];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'setPass':
|
||||||
|
$query = "UPDATE ".$this->settings['sql_table']." SET ".$this->settings['col_password']." = :enc_password WHERE ".$this->settings['col_username'] ." = :uid";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getRedmineSalt':
|
||||||
|
$query = "SELECT salt FROM ".$this->settings['sql_table']." WHERE ".$this->settings['col_username'] ." = :uid;";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'countUsers':
|
||||||
|
$query = "SELECT COUNT(*) FROM ".$this->settings['sql_table']." WHERE ".$this->settings['col_username'] ." LIKE :search";
|
||||||
|
if($this -> settings['col_active'] !== '')
|
||||||
|
$query .= " AND " .($this -> settings['set_active_invert'] === 'true' ? "NOT " : "" ) . $this -> settings['col_active'];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getUsers':
|
||||||
|
$query = "SELECT ".$this->settings['col_username']." FROM ".$this->settings['sql_table'];
|
||||||
|
$query .= " WHERE ".$this->settings['col_username']." LIKE :search";
|
||||||
|
if($this -> settings['col_active'] !== '')
|
||||||
|
$query .= " AND " .($this -> settings['set_active_invert'] === 'true' ? "NOT " : "" ) . $this -> settings['col_active'];
|
||||||
|
$query .= " ORDER BY ".$this->settings['col_username'];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'userExists':
|
||||||
|
$query = "SELECT ".$this->settings['col_username']." FROM ".$this->settings['sql_table']." WHERE ".$this->settings['col_username']." = :uid";
|
||||||
|
if($this -> settings['col_active'] !== '')
|
||||||
|
$query .= " AND " .($this -> settings['set_active_invert'] === 'true' ? "NOT " : "" ) . $this -> settings['col_active'];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getDisplayName':
|
||||||
|
$query = "SELECT ".$this->settings['col_displayname']." FROM ".$this->settings['sql_table']." WHERE ".$this->settings['col_username']." = :uid";
|
||||||
|
if($this -> settings['col_active'] !== '')
|
||||||
|
$query .= " AND " .($this -> settings['set_active_invert'] === 'true' ? "NOT " : "" ) . $this -> settings['col_active'];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'mysqlEncryptSalt':
|
||||||
|
$query = "SELECT ENCRYPT(:pw, :salt);";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'mysqlEncrypt':
|
||||||
|
$query = "SELECT ENCRYPT(:pw);";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'mysqlPassword':
|
||||||
|
$query = "SELECT PASSWORD(:pw);";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($limits['limit']) && $limits['limit'] !== null)
|
||||||
|
{
|
||||||
|
$limit = intval($limits['limit']);
|
||||||
|
$query .= " LIMIT ".$limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($limits['offset']) && $limits['offset'] !== null)
|
||||||
|
{
|
||||||
|
$offset = intval($limits['offset']);
|
||||||
|
$query .= " OFFSET ".$offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Preparing query: $query", \OCP\Util::DEBUG);
|
||||||
|
$result = $this -> db -> prepare($query);
|
||||||
|
foreach($params as $param => $value)
|
||||||
|
{
|
||||||
|
$result -> bindValue(":".$param, $value);
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Executing query...", \OCP\Util::DEBUG);
|
||||||
|
if(!$result -> execute())
|
||||||
|
{
|
||||||
|
$err = $result -> errorInfo();
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Query failed: " . $err[2], \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if($execOnly === true)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Fetching result...", \OCP\Util::DEBUG);
|
||||||
|
if($fetchArray === true)
|
||||||
|
$row = $result -> fetchAll();
|
||||||
|
else
|
||||||
|
$row = $result -> fetch();
|
||||||
|
|
||||||
|
if(!$row)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to the database using ownCloud's DBAL
|
||||||
|
* @param array $settings The settings for the connection
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function connectToDb($settings)
|
||||||
|
{
|
||||||
|
$this -> settings = $settings;
|
||||||
|
$cm = new \OC\DB\ConnectionFactory();
|
||||||
|
$parameters = array('host' => $this -> settings['sql_hostname'],
|
||||||
|
'password' => $this -> settings['sql_password'],
|
||||||
|
'user' => $this -> settings['sql_username'],
|
||||||
|
'dbname' => $this -> settings['sql_database'],
|
||||||
|
'tablePrefix' => ''
|
||||||
|
);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$this -> db = $cm -> getConnection($this -> settings['sql_driver'], $parameters);
|
||||||
|
$this -> db -> query("SET NAMES 'UTF8'");
|
||||||
|
$this -> db_conn = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (\Exception $e)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', 'Failed to connect to the database: ' . $e -> getMessage(), \OCP\Util::ERROR);
|
||||||
|
$this -> db_conn = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if all of the given columns exist
|
||||||
|
* @param array $parameters The connection parameters
|
||||||
|
* @param string $sql_driver The SQL driver to use
|
||||||
|
* @param string $table The table name to check
|
||||||
|
* @param array $cols The columns to check
|
||||||
|
* @param array True if found, otherwise false
|
||||||
|
*/
|
||||||
|
public function verifyColumns($parameters, $sql_driver, $table, $cols)
|
||||||
|
{
|
||||||
|
$columns = $this->getColumns($parameters, $sql_driver, $table);
|
||||||
|
$res = true;
|
||||||
|
$err = '';
|
||||||
|
foreach($cols as $col)
|
||||||
|
{
|
||||||
|
if(!in_array($col, $columns, true))
|
||||||
|
{
|
||||||
|
$res = false;
|
||||||
|
$err .= $col.' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($res)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return $err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given table exists
|
||||||
|
* @param array $parameters The connection parameters
|
||||||
|
* @param string $sql_driver The SQL driver to use
|
||||||
|
* @param string $table The table name to check
|
||||||
|
* @param array True if found, otherwise false
|
||||||
|
*/
|
||||||
|
public function verifyTable($parameters, $sql_driver, $table)
|
||||||
|
{
|
||||||
|
$tables = $this->getTables($parameters, $sql_driver);
|
||||||
|
return in_array($table, $tables, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a list of tables for the given connection parameters
|
||||||
|
* @param array $parameters The connection parameters
|
||||||
|
* @param string $sql_driver The SQL driver to use
|
||||||
|
* @return array The found tables, empty if an error occured
|
||||||
|
*/
|
||||||
|
public function getTables($parameters, $sql_driver)
|
||||||
|
{
|
||||||
|
$cm = new \OC\DB\ConnectionFactory();
|
||||||
|
try {
|
||||||
|
$conn = $cm -> getConnection($sql_driver, $parameters);
|
||||||
|
$platform = $conn -> getDatabasePlatform();
|
||||||
|
$query = $platform -> getListTablesSQL();
|
||||||
|
$result = $conn -> executeQuery($query);
|
||||||
|
$ret = array();
|
||||||
|
while($row = $result -> fetch())
|
||||||
|
{
|
||||||
|
$name = $row['Tables_in_'.$parameters['dbname']];
|
||||||
|
$ret[] = $name;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
catch(\Exception $e)
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a list of columns for the given connection parameters
|
||||||
|
* @param array $parameters The connection parameters
|
||||||
|
* @param string $sql_driver The SQL driver to use
|
||||||
|
* @param string $table The SQL table to work with
|
||||||
|
* @return array The found column, empty if an error occured
|
||||||
|
*/
|
||||||
|
public function getColumns($parameters, $sql_driver, $table)
|
||||||
|
{
|
||||||
|
$cm = new \OC\DB\ConnectionFactory();
|
||||||
|
try {
|
||||||
|
$conn = $cm -> getConnection($sql_driver, $parameters);
|
||||||
|
$platform = $conn -> getDatabasePlatform();
|
||||||
|
$query = $platform -> getListTableColumnsSQL($table);
|
||||||
|
$result = $conn -> executeQuery($query);
|
||||||
|
$ret = array();
|
||||||
|
while($row = $result -> fetch())
|
||||||
|
{
|
||||||
|
$name = $row['Field'];
|
||||||
|
$ret[] = $name;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
catch(\Exception $e)
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
52
settings.php
Normal file
52
settings.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - user_sql
|
||||||
|
*
|
||||||
|
* @author Andreas Böhler
|
||||||
|
* @copyright 2012 Andreas Böhler <andreas (at) aboehler (dot) at>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\user_sql;
|
||||||
|
|
||||||
|
use OCA\user_sql\lib\Helper;
|
||||||
|
|
||||||
|
$helper = new \OCA\user_sql\lib\Helper();
|
||||||
|
$params = $helper -> getParameterArray();
|
||||||
|
$settings = $helper -> loadSettingsForDomain('default');
|
||||||
|
|
||||||
|
\OCP\Util::addStyle('user_sql', 'settings');
|
||||||
|
\OCP\Util::addScript('user_sql', 'settings');
|
||||||
|
\OCP\User::checkAdminUser();
|
||||||
|
|
||||||
|
// fill template
|
||||||
|
$tmpl = new \OCP\Template('user_sql', 'settings');
|
||||||
|
foreach($params as $param)
|
||||||
|
{
|
||||||
|
$value = htmlentities($settings[$param]);
|
||||||
|
$tmpl -> assign($param, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$trusted_domains = \OC::$server->getConfig()->getSystemValue('trusted_domains');
|
||||||
|
$inserted = array('default');
|
||||||
|
array_splice($trusted_domains, 0, 0, $inserted);
|
||||||
|
$tmpl -> assign('allowed_domains', array_unique($trusted_domains));
|
||||||
|
// workaround to detect OC version
|
||||||
|
$ocVersion = @reset(\OCP\Util::getVersion());
|
||||||
|
$tmpl -> assign('ocVersion', $ocVersion);
|
||||||
|
|
||||||
|
return $tmpl -> fetchPage();
|
||||||
168
templates/settings.php
Normal file
168
templates/settings.php
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
<?php $ocVersion = $_['ocVersion'];
|
||||||
|
$cfgClass = $ocVersion >= 7 ? 'section' : 'personalblock';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="<?php p($cfgClass); ?>">
|
||||||
|
<h2><?php p($l->t('SQL User Backend')); ?></h2>
|
||||||
|
|
||||||
|
<form id="sqlForm" action="#" method="post" class="<?php p($cfgClass); ?>">
|
||||||
|
|
||||||
|
<div id="sqlDiv" class="<?php p($cfgClass); ?>">
|
||||||
|
<label for="sql_domain_chooser"><?php p($l -> t('Settings for Domain')) ?></label>
|
||||||
|
<select id="sql_domain_chooser" name="sql_domain_chooser">
|
||||||
|
<?php foreach ($_['allowed_domains'] as $domain): ?>
|
||||||
|
<option value="<?php p($domain); ?>"><?php p($domain); ?></option>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</select>
|
||||||
|
<ul>
|
||||||
|
<li><a id="sqlBasicSettings" href="#sql-1"><?php p($l -> t('Connection Settings')); ?></a></li>
|
||||||
|
<li><a id="sqlColSettings" href="#sql-2"><?php p($l -> t('Column Settings')); ?></a></li>
|
||||||
|
<li><a id="sqlEmailSettings" href="#sql-3"><?php p($l -> t('E-Mail Settings')); ?></a></li>
|
||||||
|
<li><a id="sqlDomainSettings" href="#sql-4"><?php p($l -> t('Domain Settings')); ?></a></li>
|
||||||
|
<li><a id="sqlGethomeSettings" href="#sql-5"><?php p($l -> t('getHome Settings')); ?></a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<fieldset id="sql-1">
|
||||||
|
<p><label for="sql_driver"><?php p($l -> t('SQL Driver')); ?></label>
|
||||||
|
<?php $db_driver = array('mysql' => 'MySQL', 'pgsql' => 'PostgreSQL'); ?>
|
||||||
|
<select id="sql_driver" name="sql_driver">
|
||||||
|
<?php
|
||||||
|
foreach ($db_driver as $driver => $name):
|
||||||
|
//echo $_['sql_driver'];
|
||||||
|
if($_['sql_driver'] === $driver): ?>
|
||||||
|
<option selected="selected" value="<?php p($driver); ?>"><?php p($name); ?></option>
|
||||||
|
<?php else: ?>
|
||||||
|
<option value="<?php p($driver); ?>"><?php p($name); ?></option>
|
||||||
|
<?php endif;
|
||||||
|
endforeach;
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><label for="sql_hostname"><?php p($l -> t('Host')); ?></label><input type="text" id="sql_hostname" name="sql_hostname" value="<?php p($_['sql_hostname']); ?>"></p>
|
||||||
|
|
||||||
|
<p><label for="sql_username"><?php p($l -> t('Username')); ?></label><input type="text" id="sql_username" name="sql_username" value="<?php p($_['sql_username']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><label for="sql_database"><?php p($l -> t('Database')); ?></label><input type="text" id="sql_database" name="sql_database" value="<?php p($_['sql_database']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><label for="sql_password"><?php p($l -> t('Password')); ?></label><input type="password" id="sql_password" name="sql_password" value="<?php p($_['sql_password']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><input type="submit" id="sqlVerify" value="<?php p($l -> t('Verify Settings')); ?>"></p>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
<fieldset id="sql-2">
|
||||||
|
<p><label for="sql_table"><?php p($l -> t('Table')); ?></label><input type="text" id="sql_table" name="sql_table" value="<?php p($_['sql_table']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><label for="col_username"><?php p($l -> t('Username Column')); ?></label><input type="text" id="col_username" name="col_username" value="<?php p($_['col_username']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><label for="col_password"><?php p($l -> t('Password Column')); ?></label><input type="text" id="col_password" name="col_password" value="<?php p($_['col_password']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><label for="set_allow_pwchange"><?php p($l -> t('Allow password changing (read README!)')); ?></label><input type="checkbox" id="set_allow_pwchange" name="set_allow_pwchange" value="1"<?php
|
||||||
|
if($_['set_allow_pwchange'])
|
||||||
|
p(' checked');
|
||||||
|
?>><br>
|
||||||
|
<em><?php p($l -> t('Allow changing passwords. Imposes a security risk as password salts are not recreated')); ?></em></p>
|
||||||
|
|
||||||
|
<p><label for="col_displayname"><?php p($l -> t('Real Name Column')); ?></label><input type="text" id="col_displayname" name="col_displayname" value="<?php p($_['col_displayname']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><label for="set_crypt_type"><?php p($l -> t('Encryption Type')); ?></label>
|
||||||
|
<?php $crypt_types = array('md5' => 'MD5', 'md5crypt' => 'MD5 Crypt', 'cleartext' => 'Cleartext', 'mysql_encrypt' => 'mySQL ENCRYPT()', 'system' => 'System (crypt)', 'mysql_password' => 'mySQL PASSWORD()', 'joomla' => 'Joomla MD5 Encryption', 'joomla2' => 'Joomla > 2.5.18 phpass', 'ssha256' => 'Salted SSHA256', 'redmine' => 'Redmine'); ?>
|
||||||
|
<select id="set_crypt_type" name="set_crypt_type">
|
||||||
|
<?php
|
||||||
|
foreach ($crypt_types as $driver => $name):
|
||||||
|
//echo $_['set_crypt_type'];
|
||||||
|
if($_['set_crypt_type'] === $driver): ?>
|
||||||
|
<option selected="selected" value="<?php p($driver); ?>"><?php p($name); ?></option>
|
||||||
|
<?php else: ?>
|
||||||
|
<option value="<?php p($driver); ?>"><?php p($name); ?></option>
|
||||||
|
<?php endif;
|
||||||
|
endforeach;
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><label for="col_active"><?php p($l -> t('User Active Column')); ?></label><input type="text" id="col_active" name="col_active" value="<?php p($_['col_active']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><label for="set_active_invert"><?php p($l -> t('Invert Active Value')); ?></label><input type="checkbox" id="set_active_invert" name="set_active_invert" value="1"<?php
|
||||||
|
if($_['set_active_invert'])
|
||||||
|
p(' checked');
|
||||||
|
?> /><br>
|
||||||
|
<em><?php p($l -> t("Invert the logic of the active column (for blocked users in the SQL DB)")); ?></em></p>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="sql-3">
|
||||||
|
|
||||||
|
<p><label for="col_email"><?php p($l -> t('E-Mail Column')); ?></label><input type="text" id="col_email" name="col_email" value="<?php p($_['col_email']); ?>" /></p>
|
||||||
|
|
||||||
|
<p><label for="set_mail_sync_mode"><?php p($l -> t('E-Mail address sync mode')); ?></label>
|
||||||
|
<?php $mail_modes = array('none' => 'No Synchronisation', 'initial' => 'Synchronise only once', 'forceoc' => 'ownCloud always wins', 'forcesql' => 'SQL always wins'); ?>
|
||||||
|
<select id="set_mail_sync_mode" name="set_mail_sync_mode">
|
||||||
|
<?php
|
||||||
|
foreach ($mail_modes as $mode => $name):
|
||||||
|
//echo $_['set_mail_sync_mode'];
|
||||||
|
if($_['set_mail_sync_mode'] === $mode): ?>
|
||||||
|
<option selected="selected" value="<?php p($mode); ?>"><?php p($name); ?></option>
|
||||||
|
<?php else: ?>
|
||||||
|
<option value="<?php p($mode); ?>"><?php p($name); ?></option>
|
||||||
|
<?php endif;
|
||||||
|
endforeach;
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="sql-4">
|
||||||
|
|
||||||
|
<p><label for="set_default_domain"><?php p($l -> t('Append Default Domain')); ?></label><input type="text" id="set_default_domain", name="set_default_domain" value="<?php p($_['set_default_domain']); ?>" /><br>
|
||||||
|
<em><?php p($l -> t('Append this string, e.g. a domain name, to each user name. The @-sign is automatically inserted.')); ?></em>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><label for="set_strip_domain"><?php p($l -> t('Strip Domain Part from Username')); ?></label><input type="checkbox" id="set_strip_domain" name="set_strip_domain" value="1"<?php
|
||||||
|
if($_['set_strip_domain'])
|
||||||
|
p(' checked');
|
||||||
|
?> /><br>
|
||||||
|
<em><?php p($l -> t("Strip Domain Part including @-sign from Username when logging in and retrieving username lists")); ?></em></p>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="sql-5">
|
||||||
|
<p><label for="set_enable_gethome"><?php p($l -> t('Enable support for getHome()')); ?></label><input type="checkbox" id="set_enable_gethome", name="set_enable_gethome" value="1" <?php
|
||||||
|
if($_['set_enable_gethome'])
|
||||||
|
p(' checked');
|
||||||
|
?>/></p>
|
||||||
|
|
||||||
|
<p><label for="set_gethome_mode"><?php p($l -> t('Method for getHome')); ?></label>
|
||||||
|
<?php $gethome_modes = array('query' => 'SQL Column', 'static' => 'Static (with Variables)'); ?>
|
||||||
|
<select id="set_gethome_mode" name="set_gethome_mode">
|
||||||
|
<?php
|
||||||
|
foreach ($gethome_modes as $mode => $name):
|
||||||
|
//echo $_['set_mail_sync_mode'];
|
||||||
|
if($_['set_gethome_mode'] === $mode): ?>
|
||||||
|
<option selected="selected" value="<?php p($mode); ?>"><?php p($name); ?></option>
|
||||||
|
<?php else: ?>
|
||||||
|
<option value="<?php p($mode); ?>"><?php p($name); ?></option>
|
||||||
|
<?php endif;
|
||||||
|
endforeach;
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><label for="col_gethome"><?php p($l -> t('Home Column')); ?></label><input type="text" id="col_gethome" name="col_gethome" value="<?php p($_['col_gethome']); ?>"></p>
|
||||||
|
|
||||||
|
<p><label for="set_gethome"><?php p($l -> t('Home Dir')); ?></label><input type="text" id="set_gethome" name="set_gethome" value="<?php p($_['set_gethome']); ?>"><br>
|
||||||
|
<em><?php p($l -> t('You can use the placeholders %%u to specify the user ID (before appending the default domain), %%ud to specify the user ID (after appending the default domain) and %%d to specify the default domain')); ?></em></p>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']); ?>" id="requesttoken" />
|
||||||
|
<input type="hidden" name="appname" value="user_sql" />
|
||||||
|
<input id="sqlSubmit" type="submit" value="<?php p($l -> t('Save')); ?>" />
|
||||||
|
<div id="sql_update_message" class="statusmessage"><?php p($l -> t('Saving...')); ?></div>
|
||||||
|
<div id="sql_loading_message" class="statusmessage"><?php p($l -> t('Loading...')); ?></div>
|
||||||
|
<div id="sql_verify_message" class="statusmessage"><?php p($l -> t('Verifying...')); ?></div>
|
||||||
|
<div id="sql_error_message" class="errormessage"></div>
|
||||||
|
<div id="sql_success_message" class="successmessage"></div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
782
user_sql.php
Normal file
782
user_sql.php
Normal file
@@ -0,0 +1,782 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - user_sql
|
||||||
|
*
|
||||||
|
* @author Andreas Böhler and contributors
|
||||||
|
* @copyright 2012-2015 Andreas Böhler <dev (at) aboehler (dot) at>
|
||||||
|
*
|
||||||
|
* credits go to Ed W for several SQL injection fixes and caching support
|
||||||
|
* credits go to Frédéric France for providing Joomla support
|
||||||
|
* credits go to Mark Jansenn for providing Joomla 2.5.18+ / 3.2.1+ support
|
||||||
|
* credits go to Dominik Grothaus for providing SSHA256 support and fixing a few bugs
|
||||||
|
* credits go to Sören Eberhardt-Biermann for providing multi-host support
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OCA\user_sql;
|
||||||
|
|
||||||
|
use \OCA\user_sql\lib\Helper;
|
||||||
|
|
||||||
|
class OC_USER_SQL extends \OC_User_Backend implements \OCP\IUserBackend, \OCP\UserInterface
|
||||||
|
{
|
||||||
|
protected $cache;
|
||||||
|
protected $settings;
|
||||||
|
protected $helper;
|
||||||
|
protected $session_cache_name;
|
||||||
|
protected $ocConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default constructor. It loads the settings for the given domain
|
||||||
|
* and tries to connect to the database.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$memcache = \OC::$server->getMemCacheFactory();
|
||||||
|
if ( $memcache -> isAvailable())
|
||||||
|
{
|
||||||
|
$this -> cache = $memcache -> create();
|
||||||
|
}
|
||||||
|
$this -> helper = new \OCA\user_sql\lib\Helper();
|
||||||
|
$domain = \OC::$server->getRequest()->getServerHost();
|
||||||
|
$this -> settings = $this -> helper -> loadSettingsForDomain($domain);
|
||||||
|
$this -> ocConfig = \OC::$server->getConfig();
|
||||||
|
$this -> helper -> connectToDb($this -> settings);
|
||||||
|
$this -> session_cache_name = 'USER_SQL_CACHE';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync the user's E-Mail address with the address stored by ownCloud.
|
||||||
|
* We have three (four) sync modes:
|
||||||
|
* - none: Does nothing
|
||||||
|
* - initial: Do the sync only once from SQL -> ownCloud
|
||||||
|
* - forcesql: The SQL database always wins and sync to ownCloud
|
||||||
|
* - forceoc: ownCloud always wins and syncs to SQL
|
||||||
|
*
|
||||||
|
* @param string $uid The user's ID to sync
|
||||||
|
* @return bool Success or Fail
|
||||||
|
*/
|
||||||
|
private function doEmailSync($uid)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering doEmailSync for UID: $uid", \OCP\Util::DEBUG);
|
||||||
|
if($this -> settings['col_email'] === '')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if($this -> settings['set_mail_sync_mode'] === 'none')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$ocUid = $uid;
|
||||||
|
$uid = $this -> doUserDomainMapping($uid);
|
||||||
|
|
||||||
|
$row = $this -> helper -> runQuery('getMail', array('uid' => $uid));
|
||||||
|
if($row === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$newMail = $row[$this -> settings['col_email']];
|
||||||
|
$currMail = $this->ocConfig->getUserValue($ocUid, 'settings', 'email', '');
|
||||||
|
|
||||||
|
switch($this -> settings['set_mail_sync_mode'])
|
||||||
|
{
|
||||||
|
case 'initial':
|
||||||
|
if($currMail === '')
|
||||||
|
$this->ocConfig->setUserValue($ocUid, 'settings', 'email', $newMail);
|
||||||
|
break;
|
||||||
|
case 'forcesql':
|
||||||
|
if($currMail !== $newMail)
|
||||||
|
$this->ocConfig->setUserValue($ocUid, 'settings', 'email', $newMail);
|
||||||
|
break;
|
||||||
|
case 'forceoc':
|
||||||
|
if(($currMail !== '') && ($currMail !== $newMail))
|
||||||
|
{
|
||||||
|
$row = $this -> helper -> runQuery('setMail', array('uid' => $uid, 'currMail' => $currMail), true);
|
||||||
|
|
||||||
|
if($row === false)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Could not update E-Mail address in SQL database!", \OCP\Util::ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This maps the username to the specified domain name.
|
||||||
|
* It can only append a default domain name.
|
||||||
|
*
|
||||||
|
* @param string $uid The UID to work with
|
||||||
|
* @return string The mapped UID
|
||||||
|
*/
|
||||||
|
private function doUserDomainMapping($uid)
|
||||||
|
{
|
||||||
|
$uid = trim($uid);
|
||||||
|
|
||||||
|
if($this -> settings['set_default_domain'] !== '')
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Append default domain: ".$this -> settings['set_default_domain'], \OCP\Util::DEBUG);
|
||||||
|
if(strpos($uid, '@') === false)
|
||||||
|
{
|
||||||
|
$uid .= "@" . $this -> settings['set_default_domain'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$uid = strtolower($uid);
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', 'Returning mapped UID: ' . $uid, \OCP\Util::DEBUG);
|
||||||
|
return $uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the actions implemented by this backend
|
||||||
|
* @param $actions
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function implementsAction($actions)
|
||||||
|
{
|
||||||
|
return (bool)((\OC_User_Backend::CHECK_PASSWORD
|
||||||
|
| \OC_User_Backend::GET_DISPLAYNAME
|
||||||
|
| \OC_User_Backend::COUNT_USERS
|
||||||
|
| $this -> settings['set_allow_pwchange'] === 'true' ? \OC_User_Backend::SET_PASSWORD : 0
|
||||||
|
| $this -> settings['set_enable_gethome'] === 'true' ? \OC_User_Backend::GET_HOME : 0
|
||||||
|
) & $actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this backend has user listing support
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasUserListings()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the user's home directory, if enabled
|
||||||
|
* @param string $uid The user's ID to retrieve
|
||||||
|
* @return mixed The user's home directory or false
|
||||||
|
*/
|
||||||
|
public function getHome($uid)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering getHome for UID: $uid", \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
if($this -> settings['set_enable_gethome'] !== 'true')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$uidMapped = $this -> doUserDomainMapping($uid);
|
||||||
|
$home = false;
|
||||||
|
|
||||||
|
switch($this->settings['set_gethome_mode'])
|
||||||
|
{
|
||||||
|
case 'query':
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "getHome with Query selected, running Query...", \OCP\Util::DEBUG);
|
||||||
|
$row = $this -> helper -> runQuery('getHome', array('uid' => $uidMapped));
|
||||||
|
if($row === false)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Got no row, return false", \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$home = $row[$this -> settings['col_gethome']];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'static':
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "getHome with static selected", \OCP\Util::DEBUG);
|
||||||
|
$home = $this -> settings['set_gethome'];
|
||||||
|
$home = str_replace('%ud', $uidMapped, $home);
|
||||||
|
$home = str_replace('%u', $uid, $home);
|
||||||
|
$home = str_replace('%d', $this -> settings['set_default_domain'], $home);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Returning getHome for UID: $uid with Home $home", \OCP\Util::DEBUG);
|
||||||
|
return $home;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new user account using this backend
|
||||||
|
* @return bool always false, as we can't create users
|
||||||
|
*/
|
||||||
|
public function createUser()
|
||||||
|
{
|
||||||
|
// Can't create user
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', 'Not possible to create local users from web frontend using SQL user backend', \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a user account using this backend
|
||||||
|
* @param string $uid The user's ID to delete
|
||||||
|
* @return bool always false, as we can't delete users
|
||||||
|
*/
|
||||||
|
public function deleteUser($uid)
|
||||||
|
{
|
||||||
|
// Can't delete user
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', 'Not possible to delete local users from web frontend using SQL user backend', \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set (change) a user password
|
||||||
|
* This can be enabled/disabled in the settings (set_allow_pwchange)
|
||||||
|
*
|
||||||
|
* @param string $uid The user ID
|
||||||
|
* @param string $password The user's new password
|
||||||
|
* @return bool The return status
|
||||||
|
*/
|
||||||
|
public function setPassword($uid, $password)
|
||||||
|
{
|
||||||
|
// Update the user's password - this might affect other services, that
|
||||||
|
// use the same database, as well
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering setPassword for UID: $uid", \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
if($this -> settings['set_allow_pwchange'] !== 'true')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$uid = $this -> doUserDomainMapping($uid);
|
||||||
|
|
||||||
|
$row = $this -> helper -> runQuery('getPass', array('uid' => $uid));
|
||||||
|
if($row === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$old_password = $row[$this -> settings['col_password']];
|
||||||
|
if($this -> settings['set_crypt_type'] === 'joomla2')
|
||||||
|
{
|
||||||
|
if(!class_exists('\PasswordHash'))
|
||||||
|
require_once('PasswordHash.php');
|
||||||
|
$hasher = new \PasswordHash(10, true);
|
||||||
|
$enc_password = $hasher -> HashPassword($password);
|
||||||
|
}
|
||||||
|
// Redmine stores the salt separatedly, this doesn't play nice with the way
|
||||||
|
// we check passwords
|
||||||
|
elseif($this -> settings['set_crypt_type'] === 'redmine')
|
||||||
|
{
|
||||||
|
$salt = $this -> helper -> runQuery('getRedmineSalt', array('uid' => $uid));
|
||||||
|
if(!$salt)
|
||||||
|
return false;
|
||||||
|
$enc_password = sha1($salt['salt'].sha1($password));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$enc_password = $this -> pacrypt($password, $old_password);
|
||||||
|
}
|
||||||
|
$res = $this -> helper -> runQuery('setPass', array('uid' => $uid, 'enc_password' => $enc_password), true);
|
||||||
|
if($res === false)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Could not update password!", \OCP\Util::ERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Updated password successfully, return true", \OCP\Util::DEBUG);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the password is correct
|
||||||
|
* @param string $uid The username
|
||||||
|
* @param string $password The password
|
||||||
|
* @return bool true/false
|
||||||
|
*
|
||||||
|
* Check if the password is correct without logging in the user
|
||||||
|
*/
|
||||||
|
public function checkPassword($uid, $password)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering checkPassword() for UID: $uid", \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
$uid = $this -> doUserDomainMapping($uid);
|
||||||
|
|
||||||
|
$row = $this -> helper -> runQuery('getPass', array('uid' => $uid));
|
||||||
|
if($row === false)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Got no row, return false", \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$db_pass = $row[$this -> settings['col_password']];
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Encrypting and checking password", \OCP\Util::DEBUG);
|
||||||
|
// Joomla 2.5.18 switched to phPass, which doesn't play nice with the way
|
||||||
|
// we check passwords
|
||||||
|
if($this -> settings['set_crypt_type'] === 'joomla2')
|
||||||
|
{
|
||||||
|
if(!class_exists('\PasswordHash'))
|
||||||
|
require_once('PasswordHash.php');
|
||||||
|
$hasher = new \PasswordHash(10, true);
|
||||||
|
$ret = $hasher -> CheckPassword($password, $db_pass);
|
||||||
|
}
|
||||||
|
// Redmine stores the salt separatedly, this doesn't play nice with the way
|
||||||
|
// we check passwords
|
||||||
|
elseif($this -> settings['set_crypt_type'] === 'redmine')
|
||||||
|
{
|
||||||
|
$salt = $this -> helper -> runQuery('getRedmineSalt', array('uid' => $uid));
|
||||||
|
if(!$salt)
|
||||||
|
return false;
|
||||||
|
$ret = sha1($salt['salt'].sha1($password)) === $db_pass;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$ret = $this -> pacrypt($password, $db_pass) === $db_pass;
|
||||||
|
}
|
||||||
|
if($ret)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Passwords matching, return true", \OCP\Util::DEBUG);
|
||||||
|
if($this -> settings['set_strip_domain'] === 'true')
|
||||||
|
{
|
||||||
|
$uid = explode("@", $uid);
|
||||||
|
$uid = $uid[0];
|
||||||
|
}
|
||||||
|
return $uid;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Passwords do not match, return false", \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of users
|
||||||
|
* @return int The user count
|
||||||
|
*/
|
||||||
|
public function countUsers()
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering countUsers()", \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
$search = "%".$this -> doUserDomainMapping("");
|
||||||
|
$userCount = $this -> helper -> runQuery('countUsers', array('search' => $search));
|
||||||
|
if($userCount === false)
|
||||||
|
{
|
||||||
|
$userCount = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$userCount = reset($userCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Return usercount: ".$userCount, \OCP\Util::DEBUG);
|
||||||
|
return $userCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all users
|
||||||
|
* @param string $search The search term (can be empty)
|
||||||
|
* @param int $limit The search limit (can be null)
|
||||||
|
* @param int $offset The search offset (can be null)
|
||||||
|
* @return array with all uids
|
||||||
|
*/
|
||||||
|
public function getUsers($search = '', $limit = null, $offset = null)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering getUsers() with Search: $search, Limit: $limit, Offset: $offset", \OCP\Util::DEBUG);
|
||||||
|
$users = array();
|
||||||
|
|
||||||
|
if($search !== '')
|
||||||
|
{
|
||||||
|
$search = "%".$this -> doUserDomainMapping($search."%")."%";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$search = "%".$this -> doUserDomainMapping("")."%";
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = $this -> helper -> runQuery('getUsers', array('search' => $search), false, true, array('limit' => $limit, 'offset' => $offset));
|
||||||
|
if($rows === false)
|
||||||
|
return array();
|
||||||
|
|
||||||
|
foreach($rows as $row)
|
||||||
|
{
|
||||||
|
$uid = $row[$this -> settings['col_username']];
|
||||||
|
if($this -> settings['set_strip_domain'] === 'true')
|
||||||
|
{
|
||||||
|
$uid = explode("@", $uid);
|
||||||
|
$uid = $uid[0];
|
||||||
|
}
|
||||||
|
$users[] = strtolower($uid);
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Return list of results", \OCP\Util::DEBUG);
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a user exists
|
||||||
|
* @param string $uid the username
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function userExists($uid)
|
||||||
|
{
|
||||||
|
|
||||||
|
$cacheKey = 'sql_user_exists_' . $uid;
|
||||||
|
$cacheVal = $this -> getCache ($cacheKey);
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "userExists() for UID: $uid cacheVal: $cacheVal", \OCP\Util::DEBUG);
|
||||||
|
if(!is_null($cacheVal))
|
||||||
|
return (bool)$cacheVal;
|
||||||
|
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering userExists() for UID: $uid", \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
// Only if the domain is removed for internal user handling,
|
||||||
|
// we should add the domain back when checking existance
|
||||||
|
if($this -> settings['set_strip_domain'] === 'true')
|
||||||
|
{
|
||||||
|
$uid = $this -> doUserDomainMapping($uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$exists = (bool)$this -> helper -> runQuery('userExists', array('uid' => $uid));;
|
||||||
|
$this -> setCache ($cacheKey, $exists, 60);
|
||||||
|
|
||||||
|
if(!$exists)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Empty row, user does not exists, return false", \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "User exists, return true", \OCP\Util::DEBUG);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display name of the user
|
||||||
|
* @param string $uid The user ID
|
||||||
|
* @return mixed The user's display name or FALSE
|
||||||
|
*/
|
||||||
|
public function getDisplayName($uid)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering getDisplayName() for UID: $uid", \OCP\Util::DEBUG);
|
||||||
|
|
||||||
|
$this -> doEmailSync($uid);
|
||||||
|
$uid = $this -> doUserDomainMapping($uid);
|
||||||
|
|
||||||
|
if(!$this -> userExists($uid))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = $this -> helper -> runQuery('getDisplayName', array('uid' => $uid));
|
||||||
|
|
||||||
|
if(!$row)
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Empty row, user has no display name or does not exist, return false", \OCP\Util::DEBUG);
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "User exists, return true", \OCP\Util::DEBUG);
|
||||||
|
$displayName = $row[$this -> settings['col_displayname']];
|
||||||
|
return $displayName; ;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayNames($search = '', $limit = null, $offset = null)
|
||||||
|
{
|
||||||
|
$uids = $this -> getUsers($search, $limit, $offset);
|
||||||
|
$displayNames = array();
|
||||||
|
foreach($uids as $uid)
|
||||||
|
{
|
||||||
|
$displayNames[$uid] = $this -> getDisplayName($uid);
|
||||||
|
}
|
||||||
|
return $displayNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the backend name
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getBackendName()
|
||||||
|
{
|
||||||
|
return 'SQL';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following functions were directly taken from PostfixAdmin and just
|
||||||
|
* slightly modified
|
||||||
|
* to suit our needs.
|
||||||
|
* Encrypt a password, using the apparopriate hashing mechanism as defined in
|
||||||
|
* config.inc.php ($this->crypt_type).
|
||||||
|
* When wanting to compare one pw to another, it's necessary to provide the
|
||||||
|
* salt used - hence
|
||||||
|
* the second parameter ($pw_db), which is the existing hash from the DB.
|
||||||
|
*
|
||||||
|
* @param string $pw cleartext password
|
||||||
|
* @param string $pw_db encrypted password from database
|
||||||
|
* @return string encrypted password.
|
||||||
|
*/
|
||||||
|
private function pacrypt($pw, $pw_db = "")
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "Entering private pacrypt()", \OCP\Util::DEBUG);
|
||||||
|
$pw = stripslashes($pw);
|
||||||
|
$password = "";
|
||||||
|
$salt = "";
|
||||||
|
|
||||||
|
if($this -> settings['set_crypt_type'] === 'md5crypt')
|
||||||
|
{
|
||||||
|
$split_salt = preg_split('/\$/', $pw_db);
|
||||||
|
if(isset($split_salt[2]))
|
||||||
|
{
|
||||||
|
$salt = $split_salt[2];
|
||||||
|
}
|
||||||
|
$password = $this -> md5crypt($pw, $salt);
|
||||||
|
} elseif($this -> settings['set_crypt_type'] === 'md5')
|
||||||
|
{
|
||||||
|
$password = md5($pw);
|
||||||
|
} elseif($this -> settings['set_crypt_type'] === 'system')
|
||||||
|
{
|
||||||
|
// We never generate salts, as user creation is not allowed here
|
||||||
|
$password = crypt($pw, $pw_db);
|
||||||
|
} elseif($this -> settings['set_crypt_type'] === 'cleartext')
|
||||||
|
{
|
||||||
|
$password = $pw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See
|
||||||
|
// https://sourceforge.net/tracker/?func=detail&atid=937966&aid=1793352&group_id=191583
|
||||||
|
// this is apparently useful for pam_mysql etc.
|
||||||
|
elseif($this -> settings['set_crypt_type'] === 'mysql_encrypt')
|
||||||
|
{
|
||||||
|
if($pw_db !== "")
|
||||||
|
{
|
||||||
|
$salt = substr($pw_db, 0, 2);
|
||||||
|
|
||||||
|
$row = $this -> helper -> runQuery('mysqlEncryptSalt', array('pw' => $pw, 'salt' => $salt));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$row = $this -> helper -> runQuery('mysqlEncrypt', array('pw' => $pw));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($row === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$password = $row[0];
|
||||||
|
} elseif($this -> settings['set_crypt_type'] === 'mysql_password')
|
||||||
|
{
|
||||||
|
$row = $this -> helper -> runQuery('mysqlPassword', array('pw' => $pw));
|
||||||
|
|
||||||
|
if($row === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$password = $row[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following is by Frédéric France
|
||||||
|
elseif($this -> settings['set_crypt_type'] === 'joomla')
|
||||||
|
{
|
||||||
|
$split_salt = preg_split('/:/', $pw_db);
|
||||||
|
if(isset($split_salt[1]))
|
||||||
|
{
|
||||||
|
$salt = $split_salt[1];
|
||||||
|
}
|
||||||
|
$password = ($salt) ? md5($pw . $salt) : md5($pw);
|
||||||
|
$password .= ':' . $salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif($this-> settings['set_crypt_type'] === 'ssha256')
|
||||||
|
{
|
||||||
|
$salted_password = base64_decode(preg_replace('/{SSHA256}/i','',$pw_db));
|
||||||
|
$salt = substr($salted_password,-(strlen($salted_password)-32));
|
||||||
|
$password = $this->ssha256($pw,$salt);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "unknown/invalid crypt_type settings: ".$this->settings['set_crypt_type'], \OCP\Util::ERROR);
|
||||||
|
die('unknown/invalid Encryption type setting: ' . $this -> settings['set_crypt_type']);
|
||||||
|
}
|
||||||
|
\OCP\Util::writeLog('OC_USER_SQL', "pacrypt() done, return", \OCP\Util::DEBUG);
|
||||||
|
return $password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* md5crypt
|
||||||
|
* Creates MD5 encrypted password
|
||||||
|
* @param string $pw The password to encrypt
|
||||||
|
* @param string $salt The salt to use
|
||||||
|
* @param string $magic ?
|
||||||
|
* @return string The encrypted password
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function md5crypt($pw, $salt = "", $magic = "")
|
||||||
|
{
|
||||||
|
$MAGIC = "$1$";
|
||||||
|
|
||||||
|
if($magic === "")
|
||||||
|
$magic = $MAGIC;
|
||||||
|
if($salt === "")
|
||||||
|
$salt = $this -> create_salt();
|
||||||
|
$slist = explode("$", $salt);
|
||||||
|
if($slist[0] === "1")
|
||||||
|
$salt = $slist[1];
|
||||||
|
|
||||||
|
$salt = substr($salt, 0, 8);
|
||||||
|
$ctx = $pw . $magic . $salt;
|
||||||
|
$final = $this -> pahex2bin(md5($pw . $salt . $pw));
|
||||||
|
|
||||||
|
for($i = strlen($pw); $i > 0; $i -= 16)
|
||||||
|
{
|
||||||
|
if($i > 16)
|
||||||
|
{
|
||||||
|
$ctx .= substr($final, 0, 16);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$ctx .= substr($final, 0, $i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$i = strlen($pw);
|
||||||
|
|
||||||
|
while($i > 0)
|
||||||
|
{
|
||||||
|
if($i & 1)
|
||||||
|
$ctx .= chr(0);
|
||||||
|
else
|
||||||
|
$ctx .= $pw[0];
|
||||||
|
$i = $i>>1;
|
||||||
|
}
|
||||||
|
$final = $this -> pahex2bin(md5($ctx));
|
||||||
|
|
||||||
|
for($i = 0; $i < 1000; $i++)
|
||||||
|
{
|
||||||
|
$ctx1 = "";
|
||||||
|
if($i & 1)
|
||||||
|
{
|
||||||
|
$ctx1 .= $pw;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$ctx1 .= substr($final, 0, 16);
|
||||||
|
}
|
||||||
|
if($i % 3)
|
||||||
|
$ctx1 .= $salt;
|
||||||
|
if($i % 7)
|
||||||
|
$ctx1 .= $pw;
|
||||||
|
if($i & 1)
|
||||||
|
{
|
||||||
|
$ctx1 .= substr($final, 0, 16);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$ctx1 .= $pw;
|
||||||
|
}
|
||||||
|
$final = $this -> pahex2bin(md5($ctx1));
|
||||||
|
}
|
||||||
|
$passwd = "";
|
||||||
|
$passwd .= $this -> to64(((ord($final[0])<<16) | (ord($final[6])<<8) | (ord($final[12]))), 4);
|
||||||
|
$passwd .= $this -> to64(((ord($final[1])<<16) | (ord($final[7])<<8) | (ord($final[13]))), 4);
|
||||||
|
$passwd .= $this -> to64(((ord($final[2])<<16) | (ord($final[8])<<8) | (ord($final[14]))), 4);
|
||||||
|
$passwd .= $this -> to64(((ord($final[3])<<16) | (ord($final[9])<<8) | (ord($final[15]))), 4);
|
||||||
|
$passwd .= $this -> to64(((ord($final[4])<<16) | (ord($final[10])<<8) | (ord($final[5]))), 4);
|
||||||
|
$passwd .= $this -> to64(ord($final[11]), 2);
|
||||||
|
return "$magic$salt\$$passwd";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new salte
|
||||||
|
* @return string The salt
|
||||||
|
*/
|
||||||
|
private function create_salt()
|
||||||
|
{
|
||||||
|
srand((double) microtime() * 1000000);
|
||||||
|
$salt = substr(md5(rand(0, 9999999)), 0, 8);
|
||||||
|
return $salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt using SSHA256 algorithm
|
||||||
|
* @param string $pw The password
|
||||||
|
* @param string $salt The salt to use
|
||||||
|
* @return string The hashed password, prefixed by {SSHA256}
|
||||||
|
*/
|
||||||
|
private function ssha256($pw, $salt)
|
||||||
|
{
|
||||||
|
return '{SSHA256}'.base64_encode(hash('sha256',$pw.$salt,true).$salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PostfixAdmin's hex2bin function
|
||||||
|
* @param string $str The string to convert
|
||||||
|
* @return string The converted string
|
||||||
|
*/
|
||||||
|
private function pahex2bin($str)
|
||||||
|
{
|
||||||
|
if(function_exists('hex2bin'))
|
||||||
|
{
|
||||||
|
return hex2bin($str);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$len = strlen($str);
|
||||||
|
$nstr = "";
|
||||||
|
for($i = 0; $i < $len; $i += 2)
|
||||||
|
{
|
||||||
|
$num = sscanf(substr($str, $i, 2), "%x");
|
||||||
|
$nstr .= chr($num[0]);
|
||||||
|
}
|
||||||
|
return $nstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to 64?
|
||||||
|
*/
|
||||||
|
private function to64($v, $n)
|
||||||
|
{
|
||||||
|
$ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
$ret = "";
|
||||||
|
while(($n - 1) >= 0)
|
||||||
|
{
|
||||||
|
$n--;
|
||||||
|
$ret .= $ITOA64[$v & 0x3f];
|
||||||
|
$v = $v>>6;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a value in memcache or the session, if no memcache is available
|
||||||
|
* @param string $key The key
|
||||||
|
* @param mixed $value The value to store
|
||||||
|
* @param int $ttl (optional) defaults to 3600 seconds.
|
||||||
|
*/
|
||||||
|
private function setCache($key, $value, $ttl=3600)
|
||||||
|
{
|
||||||
|
if ($this -> cache === NULL)
|
||||||
|
{
|
||||||
|
$_SESSION[$this -> session_cache_name][$key] = array(
|
||||||
|
'value' => $value,
|
||||||
|
'time' => time(),
|
||||||
|
'ttl' => $ttl,
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$this -> cache -> set($key,$value,$ttl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a value from memcache or session, if memcache is not available.
|
||||||
|
* Returns NULL if there's no value stored or the value expired.
|
||||||
|
* @param string $key
|
||||||
|
* @return mixed|NULL
|
||||||
|
*/
|
||||||
|
private function getCache($key)
|
||||||
|
{
|
||||||
|
$retVal = NULL;
|
||||||
|
if ($this -> cache === NULL)
|
||||||
|
{
|
||||||
|
if (isset($_SESSION[$this -> session_cache_name],$_SESSION[$this -> session_cache_name][$key]))
|
||||||
|
{
|
||||||
|
$value = $_SESSION[$this -> session_cache_name][$key];
|
||||||
|
if (time() < $value['time'] + $value['ttl'])
|
||||||
|
{
|
||||||
|
$retVal = $value['value'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
$retVal = $this -> cache -> get ($key);
|
||||||
|
}
|
||||||
|
return $retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user