* [ADD] Unit testing. Work in progress

* [MOD] Code refactoring
This commit is contained in:
nuxsmin
2018-07-15 20:39:11 +02:00
parent 9d42c23873
commit cfa2b20e8b
11 changed files with 192 additions and 25 deletions

View File

@@ -182,4 +182,11 @@ interface ContextInterface
* @return mixed
*/
public function getTrasientKey(string $key, $default = null);
/**
* Sets a temporary master password
*
* @param string $password
*/
public function setTemporaryMasterPass(string $password);
}

View File

@@ -268,11 +268,11 @@ class SessionContext extends ContextBase
}
/**
* Establece la clave maestra temporal
* Sets a temporary master password
*
* @param string $password
*/
public function setTemporaryMasterPass($password)
public function setTemporaryMasterPass(string $password)
{
$this->setContextKey('tempmasterpass', $password);
}

View File

@@ -257,4 +257,16 @@ class StatelessContext extends ContextBase
{
return null;
}
/**
* Sets a temporary master password
*
* @param string $password
*
* @throws ContextException
*/
public function setTemporaryMasterPass(string $password)
{
$this->setTrasientKey('_tempmasterpass', $password);
}
}

View File

@@ -28,9 +28,7 @@ use Defuse\Crypto\Exception\CryptoException;
use SP\Account\AccountRequest;
use SP\Account\AccountSearchFilter;
use SP\Account\AccountUtil;
use SP\Core\Context\SessionContext;
use SP\Core\Crypt\Crypt;
use SP\Core\Crypt\Session as CryptSession;
use SP\Core\Exceptions\QueryException;
use SP\Core\Exceptions\SPException;
use SP\DataModel\AccountData;
@@ -220,11 +218,7 @@ class AccountService extends Service implements AccountServiceInterface
{
try {
if ($masterPass === null) {
if ($this->context instanceof SessionContext) {
$masterPass = CryptSession::getSessionKey($this->context);
} else {
$masterPass = $this->context->getTrasientKey('_masterpass');
}
$masterPass = $this->getMasterKeyFromContext();
}
if (empty($masterPass)) {

View File

@@ -393,10 +393,11 @@ class ApiService extends Service
/**
* @return string
* @throws ServiceException
*/
public function getMasterPass()
{
return $this->context->getTrasientKey('_masterpass');
return $this->getMasterKeyFromContext();
}
/**

View File

@@ -27,7 +27,6 @@ namespace SP\Services\AuthToken;
use SP\Core\Acl\Acl;
use SP\Core\Acl\ActionsInterface;
use SP\Core\Crypt\Hash;
use SP\Core\Crypt\Session as CryptSession;
use SP\Core\Crypt\Vault;
use SP\Core\Exceptions\SPException;
use SP\DataModel\AuthTokenData;
@@ -217,17 +216,12 @@ class AuthTokenService extends Service
* @param string $key
*
* @return Vault
* @throws ServiceException
* @throws \Defuse\Crypto\Exception\CryptoException
*/
private function getSecureData($token, $key)
{
if (($mKey = $this->context->getTrasientKey('_masterpass')) !== null) {
return (new Vault())
->saveData($mKey, $key . $token);
}
return (new Vault())
->saveData(CryptSession::getSessionKey($this->context), $key . $token);
return (new Vault())->saveData($this->getMasterKeyFromContext(), $key . $token);
}
/**

View File

@@ -26,7 +26,6 @@ namespace SP\Services\Crypt;
use SP\Core\Crypt\Crypt;
use SP\Core\Crypt\Hash;
use SP\Core\Crypt\Session;
use SP\Core\Events\Event;
use SP\Core\Events\EventMessage;
use SP\Core\Messages\MailMessage;
@@ -86,7 +85,7 @@ class TemporaryMasterPassService extends Service
$secureKey = Crypt::makeSecuredKey($randomKey);
$configRequest = new ConfigRequest();
$configRequest->add(self::PARAM_PASS, Crypt::encrypt(Session::getSessionKey($this->context), $secureKey, $randomKey));
$configRequest->add(self::PARAM_PASS, Crypt::encrypt($this->getMasterKeyFromContext(), $secureKey, $randomKey));
$configRequest->add(self::PARAM_KEY, $secureKey);
$configRequest->add(self::PARAM_HASH, Hash::hashKey($randomKey));
$configRequest->add(self::PARAM_TIME, time());
@@ -123,9 +122,7 @@ class TemporaryMasterPassService extends Service
{
try {
$isValid = false;
$passTime = (int)$this->configService->getByParam(self::PARAM_TIME);
$passMaxTime = (int)$this->configService->getByParam(self::PARAM_MAX_TIME);
$attempts = (int)$this->configService->getByParam(self::PARAM_ATTEMPTS);
// Comprobar si el tiempo de validez o los intentos se han superado
if ($passMaxTime === 0) {
@@ -136,6 +133,9 @@ class TemporaryMasterPassService extends Service
return $isValid;
}
$passTime = (int)$this->configService->getByParam(self::PARAM_TIME);
$attempts = (int)$this->configService->getByParam(self::PARAM_ATTEMPTS);
if ((!empty($passTime) && time() > $passMaxTime)
|| $attempts >= self::MAX_ATTEMPTS
) {
@@ -197,7 +197,8 @@ class TemporaryMasterPassService extends Service
return $value->email;
}, $this->dic->get(UserService::class)->getUserEmailForGroup($groupId));
$this->dic->get(MailService::class)->sendBatch($mailMessage->getTitle(), $emails, $mailMessage);
$this->dic->get(MailService::class)
->sendBatch($mailMessage->getTitle(), $emails, $mailMessage);
}
/**

View File

@@ -56,6 +56,7 @@ class MailService extends Service
*
* @param MailParams $mailParams
* @param string $to
*
* @throws ServiceException
*/
public function check(MailParams $mailParams, $to)
@@ -104,6 +105,7 @@ class MailService extends Service
/**
* @param $action
*
* @return string
*/
protected function getSubjectForAction($action)
@@ -115,6 +117,7 @@ class MailService extends Service
* @param string $subject
* @param string $to
* @param MailMessage $mailMessage
*
* @throws ServiceException
*/
public function send($subject, $to, MailMessage $mailMessage)
@@ -134,7 +137,7 @@ class MailService extends Service
{
try {
$this->mailer->send();
$this->eventDispatcher->notifyEvent('send.mail',
new Event($this, EventMessage::factory()
->addDescription(__u('Correo enviado'))
@@ -155,6 +158,7 @@ class MailService extends Service
* @param string $subject
* @param array $to
* @param MailMessage $mailMessage
*
* @throws ServiceException
*/
public function sendBatch($subject, array $to, MailMessage $mailMessage)

View File

@@ -24,10 +24,13 @@
namespace SP\Services;
use Defuse\Crypto\Exception\CryptoException;
use DI\Container;
use Psr\Container\ContainerInterface;
use SP\Config\Config;
use SP\Core\Context\ContextInterface;
use SP\Core\Context\SessionContext;
use SP\Core\Crypt\Session;
use SP\Core\Events\Event;
use SP\Core\Events\EventDispatcher;
use SP\Core\Events\EventMessage;
@@ -115,4 +118,29 @@ abstract class Service
throw new ServiceException(__u('No es posible iniciar una transacción'));
}
}
/**
* @return string
* @throws ServiceException
*/
protected final function getMasterKeyFromContext(): String
{
try {
if ($this->context instanceof SessionContext) {
$key = Session::getSessionKey($this->context);
} else {
$key = $this->context->getTrasientKey('_masterpass');
}
if (empty($key)) {
throw new ServiceException(__u('Error ol obtener la clave maestra del contexto'));
}
return $key;
} catch (CryptoException $e) {
debugLog($e->getMessage());
throw new ServiceException(__u('Error ol obtener la clave maestra del contexto'));
}
}
}

View File

@@ -72,7 +72,6 @@ class MasterPassServiceTest extends DatabaseTestCase
self::$service = $dic->get(MasterPassService::class);
self::$accountService = $dic->get(AccountService::class);
self::$customFieldService = $dic->get(CustomFieldService::class);
}
/**

View File

@@ -0,0 +1,127 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Tests\Services\Crypt;
use Defuse\Crypto\Exception\CryptoException;
use PHPUnit\Framework\TestCase;
use SP\Core\Context\ContextInterface;
use SP\Services\Crypt\TemporaryMasterPassService;
use function SP\Tests\setupContext;
/**
* Class TemporaryMasterPassServiceTest
*
* @package SP\Tests\Services\Crypt
*/
class TemporaryMasterPassServiceTest extends TestCase
{
/**
* @var ContextInterface
*/
private $context;
/**
* @var TemporaryMasterPassService
*/
private $service;
/**
* @throws \DI\NotFoundException
* @throws \SP\Core\Context\ContextException
* @throws \DI\DependencyException
*/
public function setUp()
{
$dic = setupContext();
// Inicializar el repositorio
$this->service = $dic->get(TemporaryMasterPassService::class);
$this->context = $dic->get(ContextInterface::class);
}
/**
* @throws \SP\Services\ServiceException
*/
public function testCreate()
{
$key = $this->service->create();
$this->assertNotEmpty($key);
$this->assertEquals($this->context->getTrasientKey('_tempmasterpass'), $key);
return $key;
}
/**
* @depends testCreate
*
* @param $key
*
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \SP\Repositories\NoSuchItemException
* @throws \SP\Services\ServiceException
*/
public function testGetUsingKey($key)
{
$this->assertEquals('12345678900', $this->service->getUsingKey($key));
$this->expectException(CryptoException::class);
$this->service->getUsingKey('test123');
}
/**
* @depends testCreate
*
* @param $key
*
* @throws \SP\Services\ServiceException
*/
public function testCheckTempMasterPass($key)
{
$this->assertTrue($this->service->checkTempMasterPass($key));
for ($i = 1; $i <= 50; $i++) {
$this->assertFalse($this->service->checkTempMasterPass('test123'));
}
// The 50's attempt should fails
$this->assertFalse($this->service->checkTempMasterPass($key));
}
/**
* @throws \SP\Services\ServiceException
*/
public function testExpiredKey()
{
$key = $this->service->create(10);
print 'Sleeping for 12 seconds';
sleep(12);
$this->assertFalse($this->service->checkTempMasterPass($key));
}
}