feat(): add postfixadmin-change-password plugin #3
This commit is contained in:
		| @@ -3,6 +3,14 @@ | ||||
| # Set attachment size limit | ||||
| sed -i "s/<UPLOAD_MAX_SIZE>/$UPLOAD_MAX_SIZE/g" /etc/php7/php-fpm.conf /etc/nginx/nginx.conf | ||||
|  | ||||
| # Remove postfixadmin-change-password plugin if exist | ||||
| if [ -d "/rainloop/data/_data_/_default_/plugins/postfixadmin-change-password" ]; then | ||||
|   rm -rf /rainloop/data/_data_/_default_/plugins/postfixadmin-change-password | ||||
| fi | ||||
|  | ||||
| # Add postfixadmin-change-password plugin | ||||
| cp -r /usr/local/include/postfixadmin-change-password /rainloop/data/_data_/_default_/plugins/ | ||||
|  | ||||
| # Fix permissions | ||||
| chown -R $UID:$GID /rainloop/data /services /var/log /var/lib/nginx | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,301 @@ | ||||
| <?php | ||||
|  | ||||
| class ChangePasswordPostfixAdminDriver implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface | ||||
| { | ||||
| 	/** | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	private $sHost = '127.0.0.1'; | ||||
|  | ||||
| 	/** | ||||
| 	 * @var int | ||||
| 	 */ | ||||
| 	private $iPort = 3306; | ||||
|  | ||||
| 	/** | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	private $sDatabase = 'postfixadmin'; | ||||
|  | ||||
| 	/** | ||||
| 	* @var string | ||||
| 	*/ | ||||
| 	private $sTable = 'mailbox'; | ||||
|  | ||||
| 	/** | ||||
| 	* @var string | ||||
| 	*/ | ||||
| 	private $sUsercol = 'username'; | ||||
|  | ||||
| 	/** | ||||
| 	* @var string | ||||
| 	*/ | ||||
| 	private $sPasscol = 'password'; | ||||
|  | ||||
| 	/** | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	private $sUser = 'postfixadmin'; | ||||
|  | ||||
| 	/** | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	private $sPassword = ''; | ||||
|  | ||||
| 	/** | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	private $sEncrypt = ''; | ||||
|  | ||||
| 	/** | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	private $sAllowedEmails = ''; | ||||
|  | ||||
| 	/** | ||||
| 	 * @var \MailSo\Log\Logger | ||||
| 	 */ | ||||
| 	private $oLogger = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * @param string $sHost | ||||
| 	 * | ||||
| 	 * @return \ChangePasswordPostfixAdminDriver | ||||
| 	 */ | ||||
| 	public function SetHost($sHost) | ||||
| 	{ | ||||
| 		$this->sHost = $sHost; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param int $iPort | ||||
| 	 * | ||||
| 	 * @return \ChangePasswordPostfixAdminDriver | ||||
| 	 */ | ||||
| 	public function SetPort($iPort) | ||||
| 	{ | ||||
| 		$this->iPort = (int) $iPort; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param string $sDatabase | ||||
| 	 * | ||||
| 	 * @return \ChangePasswordPostfixAdminDriver | ||||
| 	 */ | ||||
| 	public function SetDatabase($sDatabase) | ||||
| 	{ | ||||
| 		$this->sDatabase = $sDatabase; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	* @param string $sTable | ||||
| 	* | ||||
| 	* @return \ChangePasswordPostfixAdminDriver | ||||
| 	*/ | ||||
| 	public function SetTable($sTable) | ||||
| 	{ | ||||
| 		$this->sTable = $sTable; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	* @param string $sUsercol | ||||
| 	* | ||||
| 	* @return \ChangePasswordPostfixAdminDriver | ||||
| 	*/ | ||||
| 	public function SetUserColumn($sUsercol) | ||||
| 	{ | ||||
| 		$this->sUsercol = $sUsercol; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	* @param string $sPasscol | ||||
| 	* | ||||
| 	* @return \ChangePasswordPostfixAdminDriver | ||||
| 	*/ | ||||
| 	public function SetPasswordColumn($sPasscol) | ||||
| 	{ | ||||
| 		$this->sPasscol = $sPasscol; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param string $sUser | ||||
| 	 * | ||||
| 	 * @return \ChangePasswordPostfixAdminDriver | ||||
| 	 */ | ||||
| 	public function SetUser($sUser) | ||||
| 	{ | ||||
| 		$this->sUser = $sUser; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param string $sPassword | ||||
| 	 * | ||||
| 	 * @return \ChangePasswordPostfixAdminDriver | ||||
| 	 */ | ||||
| 	public function SetPassword($sPassword) | ||||
| 	{ | ||||
| 		$this->sPassword = $sPassword; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param string $sEncrypt | ||||
| 	 * | ||||
| 	 * @return \ChangePasswordPostfixAdminDriver | ||||
| 	 */ | ||||
| 	public function SetEncrypt($sEncrypt) | ||||
| 	{ | ||||
| 		$this->sEncrypt = $sEncrypt; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param string $sAllowedEmails | ||||
| 	 * | ||||
| 	 * @return \ChangePasswordPostfixAdminDriver | ||||
| 	 */ | ||||
| 	public function SetAllowedEmails($sAllowedEmails) | ||||
| 	{ | ||||
| 		$this->sAllowedEmails = $sAllowedEmails; | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param \MailSo\Log\Logger $oLogger | ||||
| 	 * | ||||
| 	 * @return \ChangePasswordPostfixAdminDriver | ||||
| 	 */ | ||||
| 	public function SetLogger($oLogger) | ||||
| 	{ | ||||
| 		if ($oLogger instanceof \MailSo\Log\Logger) | ||||
| 		{ | ||||
| 			$this->oLogger = $oLogger; | ||||
| 		} | ||||
|  | ||||
| 		return $this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param \RainLoop\Model\Account $oAccount | ||||
| 	 * | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function PasswordChangePossibility($oAccount) | ||||
| 	{ | ||||
| 		return $oAccount && $oAccount->Email() && | ||||
| 			\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param \RainLoop\Model\Account $oAccount | ||||
| 	 * @param string $sPrevPassword | ||||
| 	 * @param string $sNewPassword | ||||
| 	 * | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword) | ||||
| 	{ | ||||
| 		if ($this->oLogger) | ||||
| 		{ | ||||
| 			$this->oLogger->Write('Postfix: Try to change password for '.$oAccount->Email()); | ||||
| 		} | ||||
|  | ||||
| 		unset($sPrevPassword); | ||||
|  | ||||
| 		$bResult = false; | ||||
|  | ||||
| 		if (0 < \strlen($sNewPassword)) | ||||
| 		{ | ||||
| 			try | ||||
| 			{ | ||||
| 				$sDsn = 'mysql:host='.$this->sHost.';port='.$this->iPort.';dbname='.$this->sDatabase; | ||||
|  | ||||
| 				$oPdo = new \PDO($sDsn, $this->sUser, $this->sPassword); | ||||
| 				$oPdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); | ||||
|  | ||||
| 				$sUpdatePassword = $this->cryptPassword($sNewPassword, $oPdo); | ||||
| 				if (0 < \strlen($sUpdatePassword)) | ||||
| 				{ | ||||
| 					$oStmt = $oPdo->prepare("UPDATE {$this->sTable} SET {$this->sPasscol} = ? WHERE {$this->sUsercol} = ?"); | ||||
| 					$bResult = (bool) $oStmt->execute(array($sUpdatePassword, $oAccount->Email())); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					if ($this->oLogger) | ||||
| 					{ | ||||
| 						$this->oLogger->Write('Postfix: Encrypted password is empty', | ||||
| 							\MailSo\Log\Enumerations\Type::ERROR); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				$oPdo = null; | ||||
| 			} | ||||
| 			catch (\Exception $oException) | ||||
| 			{ | ||||
| 				if ($this->oLogger) | ||||
| 				{ | ||||
| 					$this->oLogger->WriteException($oException); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return $bResult; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param string $sPassword | ||||
| 	 * @param \PDO $oPdo | ||||
| 	 * | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	private function cryptPassword($sPassword, $oPdo) | ||||
| 	{ | ||||
| 		$sResult = ''; | ||||
| 		$sSalt = substr(str_shuffle('./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), 0, 16); | ||||
| 		switch (strtolower($this->sEncrypt)) | ||||
| 		{ | ||||
| 			default: | ||||
| 			case 'plain': | ||||
| 			case 'cleartext': | ||||
| 				$sResult = '{PLAIN}' . $sPassword; | ||||
| 				break; | ||||
|  | ||||
| 			case 'md5': | ||||
| 				$sResult = '{PLAIN-MD5}' . md5($sPassword); | ||||
| 				break; | ||||
|  | ||||
| 			case 'system': | ||||
| 				$sResult = '{CRYPT}' . crypt($sPassword); | ||||
| 				break; | ||||
|  | ||||
| 			case 'sha256-crypt': | ||||
| 				$sResult = '{SHA256-CRYPT}' . crypt($sPassword,'$5$'.$sSalt); | ||||
| 				break; | ||||
|  | ||||
| 			case 'sha512-crypt': | ||||
| 				$sResult = '{SHA512-CRYPT}' . crypt($sPassword,'$6$'.$sSalt); | ||||
| 				break; | ||||
|  | ||||
| 			case 'mysql_encrypt': | ||||
| 				$oStmt = $oPdo->prepare('SELECT ENCRYPT(?) AS encpass'); | ||||
| 				if ($oStmt->execute(array($sPassword))) | ||||
| 				{ | ||||
| 					$aFetchResult = $oStmt->fetchAll(\PDO::FETCH_ASSOC); | ||||
| 					if (\is_array($aFetchResult) && isset($aFetchResult[0]['encpass'])) | ||||
| 					{ | ||||
| 						$sResult = $aFetchResult[0]['encpass']; | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 		} | ||||
|  | ||||
| 		return $sResult; | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,95 @@ | ||||
| <?php | ||||
|  | ||||
| class PostfixadminChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin | ||||
| { | ||||
| 	public function Init() | ||||
| 	{ | ||||
| 		$this->addHook('main.fabrica', 'MainFabrica'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return string | ||||
| 	 */ | ||||
| 	public function Supported() | ||||
| 	{ | ||||
| 		if (!extension_loaded('pdo') || !class_exists('PDO')) | ||||
| 		{ | ||||
| 			return 'The PHP exention PDO (mysql) must be installed to use this plugin'; | ||||
| 		} | ||||
|  | ||||
| 		$aDrivers = \PDO::getAvailableDrivers(); | ||||
| 		if (!is_array($aDrivers) || !in_array('mysql', $aDrivers)) | ||||
| 		{ | ||||
| 			return 'The PHP exention PDO (mysql) must be installed to use this plugin'; | ||||
| 		} | ||||
|  | ||||
| 		return ''; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param string $sName | ||||
| 	 * @param mixed $oProvider | ||||
| 	 */ | ||||
| 	public function MainFabrica($sName, &$oProvider) | ||||
| 	{ | ||||
| 		switch ($sName) | ||||
| 		{ | ||||
| 			case 'change-password': | ||||
|  | ||||
| 				include_once __DIR__.'/ChangePasswordPostfixAdminDriver.php'; | ||||
|  | ||||
| 				$oProvider = new ChangePasswordPostfixAdminDriver(); | ||||
|  | ||||
| 				$oProvider | ||||
| 					->SetHost($this->Config()->Get('plugin', 'host', '')) | ||||
| 					->SetPort((int) $this->Config()->Get('plugin', 'port', 3306)) | ||||
| 					->SetDatabase($this->Config()->Get('plugin', 'database', '')) | ||||
| 					->SetTable($this->Config()->Get('plugin', 'table', '')) | ||||
| 					->SetUserColumn($this->Config()->Get('plugin', 'usercol', '')) | ||||
| 					->SetPasswordColumn($this->Config()->Get('plugin', 'passcol', '')) | ||||
| 					->SetUser($this->Config()->Get('plugin', 'user', '')) | ||||
| 					->SetPassword($this->Config()->Get('plugin', 'password', '')) | ||||
| 					->SetEncrypt($this->Config()->Get('plugin', 'encrypt', '')) | ||||
| 					->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', '')))) | ||||
| 					->SetLogger($this->Manager()->Actions()->Logger()) | ||||
| 				; | ||||
|  | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return array | ||||
| 	 */ | ||||
| 	public function configMapping() | ||||
| 	{ | ||||
| 		return array( | ||||
| 			\RainLoop\Plugins\Property::NewInstance('host')->SetLabel('MySQL Host') | ||||
| 				->SetDefaultValue('mariadb'), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('port')->SetLabel('MySQL Port') | ||||
| 				->SetType(\RainLoop\Enumerations\PluginPropertyType::INT) | ||||
| 				->SetDefaultValue(3306), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('database')->SetLabel('MySQL Database') | ||||
| 				->SetDefaultValue('postfix'), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('table')->SetLabel('MySQL table') | ||||
| 				->SetDefaultValue('mailbox'), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('usercol')->SetLabel('MySQL username column') | ||||
| 				->SetDefaultValue('username'), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('passcol')->SetLabel('MySQL password column') | ||||
| 				->SetDefaultValue('password'), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('MySQL User') | ||||
| 				->SetDefaultValue('postfix'), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('MySQL Password') | ||||
| 				->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD) | ||||
| 				->SetDefaultValue(''), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('encrypt')->SetLabel('Encrypt') | ||||
| 				->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) | ||||
| 				->SetDefaultValue(array('SHA512-CRYPT','SHA256-CRYPT','md5', 'system', 'cleartext', 'mysql_encrypt')) | ||||
| 				->SetDescription('In what way do you want the passwords to be crypted ?'), | ||||
| 			\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails') | ||||
| 				->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT) | ||||
| 				->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net') | ||||
| 				->SetDefaultValue('*') | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Hardware
					Hardware