Skip to content

Commit

Permalink
Merge pull request #96 from nextcloud/issue-93
Browse files Browse the repository at this point in the history
Add plaintext password authentication for prosody xmpp
  • Loading branch information
violoncelloCH authored Aug 2, 2019
2 parents 6cf5a55 + 5dc9b1d commit 316e57c
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 27 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Requires the php-ssh2 PECL module installed.
XMPP (Prosody)
----
Authenticate Nextcloud users against a Prosody XMPP MySQL database.
Prosody user and password need to be given for the Nextcloud login
Prosody user and password need to be given for the Nextcloud login.


### Configuration
Expand All @@ -195,10 +195,20 @@ Add the following to your `config.php`:
2 => 'dbuser',
3 => 'dbuserpassword',
4 => 'xmppdomain',
5 => true,
),
),
),

0 - Database Host
1 - Prosody Database Name
2 - Database User
3 - Database User Password
4 - XMPP Domain
5 - Hashed Passwords in Database (true) / Plaintext Passwords in Database (false)

**⚠⚠ Warning:** If you need to set *5 (Hashed Password in Database)* to false, your Prosody Instance is storing passwords in plaintext. This is insecure and not recommended. We highly recommend that you change your Prosody configuration to protect the passwords of your Prosody users. ⚠⚠


Alternatives
------------
Expand Down
78 changes: 52 additions & 26 deletions lib/xmpp.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ class OC_User_XMPP extends \OCA\user_external\Base {
private $xmppDbUser;
private $xmppDbPassword;
private $xmppDomain;
private $passwordHashed;

public function __construct($host, $xmppDb, $xmppDbUser, $xmppDbPassword, $xmppDomain) {
public function __construct($host, $xmppDb, $xmppDbUser, $xmppDbPassword, $xmppDomain, $passwordHashed = true) {
parent::__construct($host);
$this->host = $host;
$this->xmppDb = $xmppDb;
$this->xmppDbUser = $xmppDbUser;
$this->xmppDbPassword = $xmppDbPassword;
$this->xmppDomain = $xmppDomain;
$this->passwordHashed = $passwordHashed;
}

public function hmacSha1($key, $data) {
Expand All @@ -48,6 +50,51 @@ public function hmacSha1($key, $data) {
return sha1($oPad.sha1($iPad.$data, true));
}

public function validateHashedPassword($user, $uid, $submittedPassword){
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;
}
}

public function validatePlainPassword($user, $uid, $submittedPassword) {
foreach ($user as $key) {
if($key[3] === "password") {
$internalPlainPassword = $key['value'];
}
}
unset($user);
if ($submittedPassword === $internalPlainPassword) {
$uid = mb_strtolower($uid);
$this->storeUser($uid);
return $uid;
} else {
return false;
}
}

public function checkPassword($uid, $password){
$pdo = new PDO("mysql:host=$this->host;dbname=$this->xmppDb", $this->xmppDbUser, $this->xmppDbPassword);
if(isset($uid)
Expand All @@ -70,32 +117,11 @@ public function checkPassword($uid, $password){
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;

if ($this->passwordHashed === true) {
return $this->validateHashedPassword($user, $uid, $submittedPassword);
} else {
return false;
return $this->validatePlainPassword($user, $uid, $submittedPassword);
}
}
}
Expand Down

0 comments on commit 316e57c

Please sign in to comment.