From 104e409e83a2d230fc37cb88a6202ceb3478b73b Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 10 Feb 2019 11:24:02 +0100 Subject: [PATCH] Add Prosody XMPP MySQL authentication Signed-off-by: Sebastian Change class name Signed-off-by: Sebastian add prosody to title name Signed-off-by: Sebastian integrate nextcloud code style guidelines Signed-off-by: Sebastian clean up Signed-off-by: Sebastian Applied nc code style Signed-off-by: Sebastian --- README.md | 24 +++++++++++ appinfo/app.php | 1 + appinfo/info.xml | 4 +- lib/xmpp.php | 102 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 lib/xmpp.php diff --git a/README.md b/README.md index 1489c46..86813a5 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,30 @@ Add the following to your `config.php`: [BasicAuth_0]: https://en.wikipedia.org/wiki/Basic_access_authentication + +XMPP (Prosody) +---- +Authenticate Nextcloud users against a Prosody XMPP MySQL database. +Prosody user and password need to be given for the Nextcloud login + + +### Configuration +Add the following to your `config.php`: + + 'user_backends' => array ( + 0 => array ( + 'class' => 'OC_User_XMPP', + 'arguments' => array ( + 0 => 'dbhost', + 1 => 'prosodydb', + 2 => 'dbuser', + 3 => 'dbuserpassword', + 4 => 'xmppdomain', + ), + ), + ), + + Alternatives ------------ Other extensions allow connecting to external user databases directly via SQL, which may be faster: diff --git a/appinfo/app.php b/appinfo/app.php index f503578..c5b2519 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -3,3 +3,4 @@ OC::$CLASSPATH['OC_User_IMAP']='user_external/lib/imap.php'; OC::$CLASSPATH['OC_User_SMB']='user_external/lib/smb.php'; OC::$CLASSPATH['OC_User_FTP']='user_external/lib/ftp.php'; OC::$CLASSPATH['OC_User_BasicAuth']='user_external/lib/basicauth.php'; +OC::$CLASSPATH['OC_User_XMPP']='user_external/lib/xmpp.php'; diff --git a/appinfo/info.xml b/appinfo/info.xml index b5c5f90..f6bfa1d 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -3,8 +3,8 @@ xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd"> user_external External user support - Use external user authentication methods like IMAP, SMB and FTP - Use external user authentication methods like IMAP, SMB and FTP + Use external user authentication methods like IMAP, SMB, FTP, WebDAV, HTTP BasicAuth and XMPP + Use external user authentication methods like IMAP, SMB, FTP, WebDAV, HTTP BasicAuth and XMPP 0.6.0 agpl Robin Appelman diff --git a/lib/xmpp.php b/lib/xmpp.php new file mode 100644 index 0000000..4bfe92c --- /dev/null +++ b/lib/xmpp.php @@ -0,0 +1,102 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * User authentication against a XMPP Prosody MySQL database + * + * @category Apps + * @package UserExternal + * @author Sebastian Sterk https://wiuwiu.de/Imprint + * @license http://www.gnu.org/licenses/agpl AGPL + */ +class OC_User_XMPP extends \OCA\user_external\Base { + private $host; + private $xmppDb; + private $xmppDbUser; + private $xmppDbPassword; + private $xmppDomain; + + public function __construct($host, $xmppDb, $xmppDbUser, $xmppDbPassword, $xmppDomain) { + parent::__construct($host); + $this->host = $host; + $this->xmppDb = $xmppDb; + $this->xmppDbUser = $xmppDbUser; + $this->xmppDbPassword = $xmppDbPassword; + $this->xmppDomain = $xmppDomain; + } + + public function hmacSha1($key, $data) { + if (strlen($key) > 64) { + $key = str_pad(sha1($key, true), 64, chr(0)); + } + if (strlen($key) < 64) { + $key = str_pad($key, 64, chr(0)); + } + + $oPad = str_repeat(chr(0x5C), 64); + $iPad = str_repeat(chr(0x36), 64); + + for ($i = 0; $i < strlen($key); $i++) { + $oPad[$i] = $oPad[$i] ^ $key[$i]; + $iPad[$i] = $iPad[$i] ^ $key[$i]; + } + return sha1($oPad.sha1($iPad.$data, true)); + } + + public function checkPassword($uid, $password){ + $pdo = new PDO("mysql:host=$this->host;dbname=$this->xmppDb", $this->xmppDbUser, $this->xmppDbPassword); + if(isset($uid) + && isset($password)) { + if(!filter_var($uid, FILTER_VALIDATE_EMAIL) + || !strpos($uid, $this->xmppDomain) + || substr($uid, -strlen($this->xmppDomain)) !== $this->xmppDomain + ) { + return false; + } + $user = explode("@", $uid); + $userName = strtolower($user[0]); + $submittedPassword = $password; + $statement = $pdo->prepare("SELECT * FROM prosody WHERE user = :user AND host = :xmppDomain AND store = 'accounts'"); + $result = $statement->execute(array( + 'user' => $userName, + 'xmppDomain' => $this->xmppDomain + )); + $user = $statement->fetchAll(); + if(empty($user)) { + return false; + } + foreach ($user as $key){ + if($key[3] === "salt") { + $internalSalt = $key['value']; + } + if($key[3] === "server_key") { + $internalServerKey = $key['value']; + } + if($key[3] === "stored_key") { + $internalStoredKey = $key['value']; + } + } + unset($user); + $internalIteration = '4096'; + + $newSaltedPassword = hash_pbkdf2('sha1', $submittedPassword, $internalSalt, $internalIteration, 0, true); + $newServerKey = $this->hmacSha1($newSaltedPassword, 'Server Key'); + $newClientKey = $this->hmacSha1($newSaltedPassword, 'Client Key'); + $newStoredKey = sha1(hex2bin($newClientKey)); + + if ($newServerKey === $internalServerKey + && $newStoredKey === $internalStoredKey) { + $uid = mb_strtolower($uid); + $this->storeUser($uid); + return $uid; + } else { + return false; + } + } + } +}