* [ADD] Improved tracking handling.

* [MOD] Improved login process workflow.
This commit is contained in:
nuxsmin
2018-02-26 14:07:14 +01:00
committed by Rubén Domínguez
parent 94f9929be0
commit ed0d95b774
13 changed files with 581 additions and 120 deletions

View File

@@ -40,4 +40,3 @@ Telepítés és gyakran feltett kérdésekre https://doc.syspass.org
Installation et Foire aux questions du https://doc.syspass.org
---

View File

@@ -29,10 +29,11 @@ use SP\Core\Events\EventMessage;
use SP\Core\SessionFactory;
use SP\Core\SessionUtil;
use SP\Html\Html;
use SP\Http\Request;
use SP\Http\Response;
use SP\Modules\Web\Controllers\Helpers\LayoutHelper;
use SP\Modules\Web\Controllers\Traits\JsonTrait;
use SP\Services\Auth\LoginService;
use SP\Util\Json;
/**
* Class LoginController
@@ -41,17 +42,37 @@ use SP\Util\Json;
*/
class LoginController extends ControllerBase
{
use JsonTrait;
/**
* Login action
*
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
public function loginAction()
{
$loginService = $this->dic->get(LoginService::class);
Json::returnJson($loginService->doLogin());
try {
$loginService = $this->dic->get(LoginService::class);
$loginResponmse = $loginService->doLogin();
$forward = Request::getRequestHeaders('X-Forwarded-For');
if ($forward) {
$this->eventDispatcher->notifyEvent('login.info',
new Event($this, EventMessage::factory()
->addDetail('X-Forwarded-For', $this->configData->isDemoEnabled() ? '***' : $forward))
);
}
$this->returnJsonResponseData(['url' => $loginResponmse->getRedirect()]);
} catch (\Exception $e) {
processException($e);
$this->eventDispatcher->notifyEvent('exception', new Event($e));
$this->returnJsonResponse($e->getCode(), $e->getMessage());
}
}
/**

View File

@@ -38,9 +38,9 @@ trait JsonTrait
/**
* Returns JSON response
*
* @param int $status Status code
* @param string $description Untranslated description string
* @param array|null $messages Untranslated massages array of strings
* @param int $status Status code
* @param string $description Untranslated description string
* @param array|null $messages Untranslated massages array of strings
*/
protected function returnJsonResponse($status, $description, array $messages = null)
{
@@ -59,10 +59,10 @@ trait JsonTrait
* Returns JSON response
*
* @param mixed $data
* @param int $status Status code
* @param null $description Untranslated description string
* @param int $status Status code
* @param null $description Untranslated description string
*/
protected function returnJsonResponseData($data, $status = 0, $description = null)
protected function returnJsonResponseData($data, $status = JsonResponse::JSON_SUCCESS, $description = null)
{
$jsonResponse = new JsonResponse();
$jsonResponse->setStatus($status);
@@ -80,7 +80,7 @@ trait JsonTrait
* Returns JSON response
*
* @param \Exception $exception
* @param int $status Status code
* @param int $status Status code
*/
protected function returnJsonResponseException(\Exception $exception, $status = JsonResponse::JSON_ERROR)
{
@@ -88,7 +88,7 @@ trait JsonTrait
$jsonResponse->setStatus($status);
$jsonResponse->setDescription($exception->getMessage());
if ($exception instanceof SPException && $exception->getHint() !== null ) {
if ($exception instanceof SPException && $exception->getHint() !== null) {
$jsonResponse->setMessages([$exception->getHint()]);
}

View File

@@ -25,7 +25,6 @@
namespace SP\DataModel;
use SP\Core\Exceptions\InvalidArgumentException;
use SP\Core\Exceptions\SPException;
/**
* Class TrackData
@@ -152,9 +151,9 @@ class TrackData extends DataModelBase
} elseif (strlen($ip) > 4) {
$this->ipv6 = $ip;
} elseif ($ip === false) {
debugLog(sprintf('%s : %s', __('IP inválida', true), $track_ip));
debugLog(sprintf('%s : %s', __('IP inválida'), $track_ip));
throw new InvalidArgumentException(SPException::ERROR, __('IP inválida'), $track_ip);
throw new InvalidArgumentException(__u('IP inválida'), InvalidArgumentException::ERROR, $track_ip);
}
}

View File

@@ -0,0 +1,164 @@
<?php
namespace SP\Repositories\Track;
use SP\DataModel\TrackData;
use SP\Repositories\Repository;
use SP\Storage\DbWrapper;
use SP\Storage\QueryData;
/**
* Class TrackRepository
* @package SP\Repositories\Track
*/
class TrackRepository extends Repository
{
/**
* @param TrackRequest $trackRequest
* @return mixed
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function add(TrackRequest $trackRequest)
{
$query = /** @lang SQL */
'INSERT INTO Track SET
userId = ?,
source = ?,
time = UNIX_TIMESTAMP(),
ipv4 = ?,
ipv6 = ?';
$queryData = new QueryData();
$queryData->setQuery($query);
$queryData->addParam($trackRequest->userId);
$queryData->addParam($trackRequest->source);
$queryData->addParam($trackRequest->getIpv4());
$queryData->addParam($trackRequest->getIpv6());
$queryData->setOnErrorMessage(__u('Error al crear track'));
DbWrapper::getQuery($queryData, $this->db);
return $this->db->getLastId();
}
/**
* @param $id int|array
* @return mixed
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\ConstraintException
*/
public function delete($id)
{
$queryData = new QueryData();
$queryData->setQuery('DELETE FROM Track WHERE id = ? LIMIT 1');
$queryData->addParam($id);
$queryData->setOnErrorMessage(__u('Error al eliminar track'));
DbWrapper::getQuery($queryData, $this->db);
return $this->db->getNumRows();
}
/**
* @param TrackData $itemData
* @return bool
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function update(TrackData $itemData)
{
$query = /** @lang SQL */
'UPDATE Track SET
track_userId = ?,
source = ?,
time = UNIX_TIMESTAMP(),
ipv4 = ?,
ipv6 = ?
WHERE id = ? LIMIT 1';
$queryData = new QueryData();
$queryData->setQuery($query);
$queryData->addParam($itemData->getUserId());
$queryData->addParam($itemData->getSource());
$queryData->addParam($itemData->getTrackIpv4Bin());
$queryData->addParam($itemData->getTrackIpv6Bin());
$queryData->addParam($itemData->getId());
$queryData->setOnErrorMessage(__u('Error al actualizar track'));
return DbWrapper::getQuery($queryData, $this->db);
}
/**
* @param $id int
* @return TrackData
*/
public function getById($id)
{
$query = /** @lang SQL */
'SELECT id,
userId,
source,
time,
ipv4,
ipv6
FROM Track
WHERE id = ? LIMIT 1';
$queryData = new QueryData();
$queryData->setQuery($query);
$queryData->addParam($id);
$queryData->setMapClassName(TrackData::class);
$queryData->setOnErrorMessage(__u('Error al obtener track'));
return DbWrapper::getResults($queryData, $this->db);
}
/**
* @return TrackData[]
*/
public function getAll()
{
$query = /** @lang SQL */
'SELECT id,
userId,
source,
time,
ipv4,
ipv6 FROM Track';
$queryData = new QueryData();
$queryData->setQuery($query);
$queryData->setMapClassName(TrackData::class);
$queryData->setOnErrorMessage(__u('Error al obtener tracks'));
return DbWrapper::getResultsArray($queryData);
}
/**
* Devuelve los tracks de un cliente desde un tiempo y origen determinados
*
* @param TrackRequest $trackRequest
* @return array
*/
public function getTracksForClientFromTime(TrackRequest $trackRequest)
{
$query = /** @lang SQL */
'SELECT id, userId
FROM Track
WHERE `time` >= ?
AND (ipv4 = ? OR ipv6 = ?)
AND `source` = ?';
$queryData = new QueryData();
$queryData->setQuery($query);
$queryData->addParam($trackRequest->time);
$queryData->addParam($trackRequest->getIpv4());
$queryData->addParam($trackRequest->getIpv6());
$queryData->addParam($trackRequest->source);
$queryData->setMapClassName(TrackData::class);
$queryData->setOnErrorMessage(__u('Error al obtener tracks'));
return DbWrapper::getResultsArray($queryData, $this->db);
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace SP\Repositories\Track;
use SP\Core\Exceptions\InvalidArgumentException;
/**
* Class TrackRequest
* @package SP\Repositories\Track
*/
class TrackRequest
{
public $time;
public $source;
public $userId;
protected $ipv6;
protected $ipv4;
/**
* @param string $address
* @throws InvalidArgumentException
*/
public function setTrackIp($address)
{
$ip = @inet_pton($address);
if (strlen($ip) === 4) {
$this->ipv4 = $ip;
} elseif (strlen($ip) > 4) {
$this->ipv6 = $ip;
} elseif ($ip === false) {
debugLog(sprintf('%s : %s', __('IP inválida'), $address));
throw new InvalidArgumentException(__u('IP inválida'), InvalidArgumentException::ERROR, $address);
}
}
/**
* @return string
*/
public function getIpv6()
{
return $this->ipv6;
}
/**
* @return string
*/
public function getIpv4()
{
return $this->ipv4;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace SP\Services\Auth;
/**
* Class LoginResponse
*
* @package SP\Services\Auth
*/
class LoginResponse
{
/**
* @var int
*/
private $status;
/**
* @var string
*/
private $redirect;
/**
* LoginResponse constructor.
* @param int $status
* @param string $redirect
*/
public function __construct($status, $redirect = null)
{
$this->status = $status;
$this->redirect = $redirect;
}
/**
* @return int
*/
public function getStatus()
{
return $this->status;
}
/**
* @return string
*/
public function getRedirect()
{
return $this->redirect;
}
}

View File

@@ -27,34 +27,31 @@ namespace SP\Services\Auth;
defined('APP_ROOT') || die();
use Defuse\Crypto\Exception\CryptoException;
use SP\Bootstrap;
use SP\Config\ConfigData;
use SP\Core\Events\Event;
use SP\Core\Events\EventMessage;
use SP\Core\Exceptions\SPException;
use SP\Core\Language;
use SP\Core\UI\Theme;
use SP\DataModel\TrackData;
use SP\DataModel\UserLoginData;
use SP\DataModel\UserPreferencesData;
use SP\Http\JsonResponse;
use SP\Http\Request;
use SP\Mgmt\Tracks\Track;
use SP\Providers\Auth\Auth;
use SP\Providers\Auth\AuthResult;
use SP\Providers\Auth\AuthUtil;
use SP\Providers\Auth\Browser\BrowserAuthData;
use SP\Providers\Auth\Database\DatabaseAuthData;
use SP\Providers\Auth\Ldap\LdapAuthData;
use SP\Repositories\Track\TrackRequest;
use SP\Services\Crypt\TemporaryMasterPassService;
use SP\Services\Service;
use SP\Services\Track\TrackService;
use SP\Services\User\UserLoginRequest;
use SP\Services\User\UserPassService;
use SP\Services\User\UserService;
use SP\Services\UserPassRecover\UserPassRecoverService;
use SP\Services\UserProfile\UserProfileService;
use SP\Util\HttpUtil;
use SP\Util\Json;
use SP\Util\Util;
/**
@@ -72,17 +69,10 @@ class LoginService extends Service
const STATUS_USER_DISABLED = 3;
const STATUS_NEED_OLD_PASS = 5;
const STATUS_MAX_ATTEMPTS_EXCEEDED = 6;
const STATUS_PASS_RESET = 7;
const STATUS_PASS = 0;
const STATUS_NONE = 100;
/**
* Tiempo para contador de intentos
*/
const TIME_TRACKING = 600;
const TIME_TRACKING_MAX_ATTEMPTS = 5;
/**
* @var JsonResponse
*/
protected $jsonResponse;
/**
* @var UserLoginData
*/
@@ -103,10 +93,19 @@ class LoginService extends Service
* @var Language
*/
protected $language;
/**
* @var TrackService
*/
protected $trackService;
/**
* @var TrackRequest
*/
protected $trackRequest;
/**
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \SP\Core\Exceptions\InvalidArgumentException
*/
public function initialize()
{
@@ -114,132 +113,125 @@ class LoginService extends Service
$this->theme = $this->dic->get(Theme::class);
$this->userService = $this->dic->get(UserService::class);
$this->language = $this->dic->get(Language::class);
$this->trackService = $this->dic->get(TrackService::class);
$this->jsonResponse = new JsonResponse();
$this->userLoginData = new UserLoginData();
$this->trackRequest = TrackService::getTrackRequest('login');
}
/**
* Ejecutar las acciones de login
*
* @return JsonResponse
* @return LoginResponse
* @throws AuthException
* @throws SPException
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function doLogin()
{
$this->userLoginData->setLoginUser(Request::analyze('user'));
$this->userLoginData->setLoginPass(Request::analyzeEncrypted('pass'));
try {
// FIXME: add service
// $this->checkTracking();
$this->trackRequest->userId = $this->userLoginData->getLoginUser();
$auth = new Auth($this->userLoginData, $this->configData);
$this->checkTracking();
if (($result = $auth->doAuth()) !== false) {
// Ejecutar la acción asociada al tipo de autentificación
$auth = new Auth($this->userLoginData, $this->configData);
if (($result = $auth->doAuth()) !== false) {
// Ejecutar la acción asociada al tipo de autentificación
foreach ($result as $authResult) {
/** @var AuthResult $authResult */
foreach ($result as $authResult) {
if ($authResult->isAuthGranted() === true
&& $this->{$authResult->getAuth()}($authResult->getData()) === true) {
break;
}
if ($authResult->isAuthGranted() === true
&& $this->{$authResult->getAuth()}($authResult->getData()) === true) {
break;
}
} else {
$this->addTracking();
throw new AuthException(__u('Login incorrecto'), AuthException::INFO, null, self::STATUS_INVALID_LOGIN);
}
} else {
$this->addTracking();
$this->checkUser();
$this->loadMasterPass();
$this->setUserSession();
$this->loadUserPreferences();
$this->cleanUserData();
} catch (SPException $e) {
processException($e);
$this->eventDispatcher->notifyEvent('exception', new Event($e));
$this->jsonResponse->setDescription($e->getMessage());
$this->jsonResponse->setStatus($e->getCode());
Json::returnJson($this->jsonResponse);
}
$forward = Request::getRequestHeaders('X-Forwarded-For');
if ($forward) {
$this->eventDispatcher->notifyEvent('login.info',
new Event($this, EventMessage::factory()
->addDetail('X-Forwarded-For', $this->configData->isDemoEnabled() ? '***' : $forward))
throw new AuthException(
__u('Login incorrecto'),
AuthException::INFO,
__FUNCTION__,
self::STATUS_INVALID_LOGIN
);
}
// $data = ['url' => 'index.php' . Request::importUrlParamsToGet()];
$data = ['url' => 'index.php?r=index'];
$this->jsonResponse->setStatus(JsonResponse::JSON_SUCCESS);
$this->jsonResponse->setData($data);
if (($loginResponse = $this->checkUser())->getStatus() !== self::STATUS_NONE) {
return $loginResponse;
}
return $this->jsonResponse;
$this->loadMasterPass();
$this->setUserSession();
$this->loadUserPreferences();
$this->cleanUserData();
return new LoginResponse(self::STATUS_PASS, 'index.php?r=index');
}
/**
* Comprobar los intentos de login
*
* @throws \SP\Services\Auth\AuthException
* @throws AuthException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
private function checkTracking()
{
try {
$TrackData = new TrackData();
$TrackData->setSource('Login');
$TrackData->setTrackIp(HttpUtil::getClientAddress());
$attempts = count(Track::getItem($TrackData)->getTracksForClientFromTime(time() - self::TIME_TRACKING));
} catch (SPException $e) {
$attempts = count($this->trackService->getTracksForClientFromTime($this->trackRequest));
} catch (\Exception $e) {
processException($e);
throw new AuthException(__u('Error interno'), AuthException::ERROR, null, Service::STATUS_INTERNAL_ERROR);
}
if ($attempts >= self::TIME_TRACKING_MAX_ATTEMPTS) {
if ($attempts >= TrackService::TIME_TRACKING_MAX_ATTEMPTS) {
$this->addTracking();
$this->eventDispatcher->notifyEvent('login.track.delay',
new Event($this, EventMessage::factory()
->addDescription(sprintf(__('Intentos excedidos (%d/%d)'), $attempts, self::TIME_TRACKING_MAX_ATTEMPTS))
->addDescription(sprintf(__('Intentos excedidos (%d/%d)'), $attempts, TrackService::TIME_TRACKING_MAX_ATTEMPTS))
->addDetail(__u('Segundos'), 0.3 * $attempts))
);
sleep(0.3 * $attempts);
sleep(TrackService::TIME_SLEEP * $attempts);
throw new AuthException(__u('Intentos excedidos'), AuthException::INFO, null, self::STATUS_MAX_ATTEMPTS_EXCEEDED);
throw new AuthException(
__u('Intentos excedidos'),
AuthException::INFO,
null,
self::STATUS_MAX_ATTEMPTS_EXCEEDED
);
}
}
/**
* Añadir un seguimiento
*
* @throws \SP\Services\Auth\AuthException
* @throws AuthException
*/
private function addTracking()
{
try {
$TrackData = new TrackData();
$TrackData->setSource('Login');
$TrackData->setTrackIp(HttpUtil::getClientAddress());
Track::getItem($TrackData)->add();
$this->trackService->add($this->trackRequest);
$this->eventDispatcher->notifyEvent('login.track.add',
new Event($this, EventMessage::factory()->addDescription(HttpUtil::getClientAddress(true)))
new Event($this, EventMessage::factory()
->addDescription(HttpUtil::getClientAddress(true)))
);
} catch (\Exception $e) {
throw new AuthException(
__u('Error interno'),
AuthException::ERROR,
null,
Service::STATUS_INTERNAL_ERROR
);
} catch (SPException $e) {
throw new AuthException(__u('Error interno'), AuthException::ERROR, null, Service::STATUS_INTERNAL_ERROR);
}
}
@@ -252,6 +244,7 @@ class LoginService extends Service
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @return LoginResponse
*/
protected function checkUser()
{
@@ -268,7 +261,12 @@ class LoginService extends Service
$this->addTracking();
throw new AuthException(__u('Usuario deshabilitado'), AuthException::INFO, null, self::STATUS_USER_DISABLED);
throw new AuthException(
__u('Usuario deshabilitado'),
AuthException::INFO,
null,
self::STATUS_USER_DISABLED
);
}
// Comprobar si se ha forzado un cambio de clave
@@ -283,11 +281,10 @@ class LoginService extends Service
$this->dic->get(UserPassRecoverService::class)->add($userLoginResponse->getId(), $hash);
$this->jsonResponse->setData(['url' => Bootstrap::$WEBURI . '/index.php?u=userPassReset/change/' . $hash]);
$this->jsonResponse->setStatus(0);
Json::returnJson($this->jsonResponse);
return new LoginResponse(self::STATUS_PASS_RESET, 'index.php?r=userPassReset/change/' . $hash);
}
return new LoginResponse(self::STATUS_NONE);
}
/**
@@ -323,7 +320,12 @@ class LoginService extends Service
$this->addTracking();
throw new AuthException(__u('Clave maestra incorrecta'), AuthException::INFO, null, self::STATUS_INVALID_MASTER_PASS);
throw new AuthException(
__u('Clave maestra incorrecta'),
AuthException::INFO,
null,
self::STATUS_INVALID_MASTER_PASS
);
}
$this->eventDispatcher->notifyEvent('login.masterPass',
@@ -337,7 +339,12 @@ class LoginService extends Service
$this->addTracking();
throw new AuthException(__u('Clave maestra incorrecta'), AuthException::INFO, null, self::STATUS_INVALID_MASTER_PASS);
throw new AuthException(
__u('Clave maestra incorrecta'),
AuthException::INFO,
null,
self::STATUS_INVALID_MASTER_PASS
);
}
$this->eventDispatcher->notifyEvent('login.masterPass',
@@ -346,21 +353,37 @@ class LoginService extends Service
} else {
switch ($userPassService->loadUserMPass($this->userLoginData)->getStatus()) {
case UserPassService::MPASS_CHECKOLD:
throw new AuthException(__u('Es necesaria su clave anterior'), AuthException::INFO, null, self::STATUS_NEED_OLD_PASS);
throw new AuthException(
__u('Es necesaria su clave anterior'),
AuthException::INFO,
null,
self::STATUS_NEED_OLD_PASS
);
break;
case UserPassService::MPASS_NOTSET:
case UserPassService::MPASS_CHANGED:
case UserPassService::MPASS_WRONG:
$this->addTracking();
throw new AuthException(__u('La clave maestra no ha sido guardada o es incorrecta'), AuthException::INFO, null, self::STATUS_INVALID_MASTER_PASS);
throw new AuthException(
__u('La clave maestra no ha sido guardada o es incorrecta'),
AuthException::INFO,
null,
self::STATUS_INVALID_MASTER_PASS
);
break;
}
}
} catch (CryptoException $e) {
$this->eventDispatcher->notifyEvent('exception', new Event($e));
throw new AuthException(__u('Error interno'), AuthException::ERROR, $e->getMessage(), Service::STATUS_INTERNAL_ERROR);
throw new AuthException(
__u('Error interno'),
AuthException::ERROR,
$e->getMessage(),
Service::STATUS_INTERNAL_ERROR,
$e
);
}
}
@@ -437,7 +460,12 @@ class LoginService extends Service
$this->eventDispatcher->notifyEvent('login.auth.ldap', new Event($this, $eventMessage));
throw new AuthException(__u('Login incorrecto'), AuthException::INFO, null, self::STATUS_INVALID_LOGIN);
throw new AuthException(
__u('Login incorrecto'),
AuthException::INFO,
__FUNCTION__,
self::STATUS_INVALID_LOGIN
);
}
if ($authData->getStatusCode() === 701) {
@@ -445,7 +473,12 @@ class LoginService extends Service
$this->eventDispatcher->notifyEvent('login.auth.ldap', new Event($this, $eventMessage));
throw new AuthException(__u('Cuenta expirada'), AuthException::INFO, null, self::STATUS_USER_DISABLED);
throw new AuthException(
__u('Cuenta expirada'),
AuthException::INFO,
__FUNCTION__,
self::STATUS_USER_DISABLED
);
}
if ($authData->getStatusCode() === 702) {
@@ -453,7 +486,12 @@ class LoginService extends Service
$this->eventDispatcher->notifyEvent('login.auth.ldap', new Event($this, $eventMessage));
throw new AuthException(__u('El usuario no tiene grupos asociados'), AuthException::INFO, null, self::STATUS_USER_DISABLED);
throw new AuthException(
__u('El usuario no tiene grupos asociados'),
AuthException::INFO,
__FUNCTION__,
self::STATUS_USER_DISABLED
);
}
if ($authData->isAuthGranted() === false) {
@@ -464,7 +502,12 @@ class LoginService extends Service
$this->eventDispatcher->notifyEvent('login.auth.ldap', new Event($this, $eventMessage));
throw new AuthException(__u('Error interno'), AuthException::INFO, null, Service::STATUS_INTERNAL_ERROR);
throw new AuthException(
__u('Error interno'),
AuthException::INFO,
__FUNCTION__,
Service::STATUS_INTERNAL_ERROR
);
}
$this->eventDispatcher->notifyEvent('login.auth.ldap',
@@ -492,7 +535,13 @@ class LoginService extends Service
$this->userService->createOnLogin($userLoginRequest);
}
} catch (\Exception $e) {
throw new AuthException(__u('Error interno'), AuthException::ERROR, null, Service::STATUS_INTERNAL_ERROR, $e);
throw new AuthException(
__u('Error interno'),
AuthException::ERROR,
__FUNCTION__,
Service::STATUS_INTERNAL_ERROR,
$e
);
}
return true;
@@ -524,7 +573,12 @@ class LoginService extends Service
$this->eventDispatcher->notifyEvent('login.auth.database', new Event($this, $eventMessage));
throw new AuthException(__u('Login incorrecto'), AuthException::INFO, null, self::STATUS_INVALID_LOGIN);
throw new AuthException(
__u('Login incorrecto'),
AuthException::INFO,
__FUNCTION__,
self::STATUS_INVALID_LOGIN
);
}
if ($authData->getAuthenticated() === 1) {
@@ -560,7 +614,12 @@ class LoginService extends Service
$this->eventDispatcher->notifyEvent('login.auth.browser', new Event($this, $eventMessage));
throw new AuthException(__u('Login incorrecto'), AuthException::INFO, null, self::STATUS_INVALID_LOGIN);
throw new AuthException(
__u('Login incorrecto'),
AuthException::INFO,
__FUNCTION__,
self::STATUS_INVALID_LOGIN
);
}
if ($authData->getAuthenticated() === 1 && $this->configData->isAuthBasicAutoLoginEnabled()) {
@@ -579,7 +638,13 @@ class LoginService extends Service
return true;
} catch (\Exception $e) {
throw new AuthException(__u('Error interno'), AuthException::ERROR, null, Service::STATUS_INTERNAL_ERROR, $e);
throw new AuthException(
__u('Error interno'),
AuthException::ERROR,
__FUNCTION__,
Service::STATUS_INTERNAL_ERROR,
$e
);
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace SP\Services\Track;
use SP\DataModel\TrackData;
use SP\Repositories\Track\TrackRepository;
use SP\Repositories\Track\TrackRequest;
use SP\Services\Service;
use SP\Util\HttpUtil;
/**
* Class TrackService
* @package SP\Services
*/
class TrackService extends Service
{
/**
* Tiempo para contador de intentos
*/
const TIME_TRACKING = 600;
const TIME_TRACKING_MAX_ATTEMPTS = 5;
const TIME_SLEEP = 0.3;
/**
* @var TrackRepository
*/
protected $trackRepository;
/**
* @param TrackRequest $trackRequest
* @return mixed
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function add(TrackRequest $trackRequest)
{
return $this->trackRepository->add($trackRequest);
}
/**
* @param $id int|array
* @return mixed
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\ConstraintException
*/
public function delete($id)
{
return $this->trackRepository->delete($id);
}
/**
* @param TrackData $itemData
* @return bool
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function update(TrackData $itemData)
{
return $this->trackRepository->update($itemData);
}
/**
* @param $id int
* @return TrackData
*/
public function getById($id)
{
return $this->trackRepository->getById($id);
}
/**
* @return TrackData[]
*/
public function getAll()
{
return $this->trackRepository->getAll();
}
/**
* Devuelve los tracks de un cliente desde un tiempo y origen determinados
*
* @param TrackRequest $trackRequest
* @return array
*/
public function getTracksForClientFromTime(TrackRequest $trackRequest)
{
return $this->trackRepository->getTracksForClientFromTime($trackRequest);
}
/**
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
public function initialize()
{
$this->trackRepository = $this->dic->get(TrackRepository::class);
}
/**
* @param $source
* @return TrackRequest
* @throws \SP\Core\Exceptions\InvalidArgumentException
*/
public static function getTrackRequest($source)
{
$trackRequest = new TrackRequest();
$trackRequest->time = time() - self::TIME_TRACKING;
$trackRequest->setTrackIp(HttpUtil::getClientAddress());
$trackRequest->source = $source;
return $trackRequest;
}
}

View File

@@ -1559,7 +1559,7 @@ sysPass.Actions = function (Common) {
const grid = {
search: function ($obj) {
log.info("appMgmt:search");
log.info("grid:search");
const $target = $($obj.data("target"));
const opts = Common.appRequests().getRequestOpts();
@@ -1589,7 +1589,7 @@ sysPass.Actions = function (Common) {
if (typeof callback === "function") {
callback($form);
} else {
grid.search($obj);
grid.search($form);
}
},
delete: function ($obj, onAccept) {

View File

@@ -1,5 +1,5 @@
var $jscomp={scope:{},findInternal:function(c,e,l){c instanceof String&&(c=String(c));for(var f=c.length,g=0;g<f;g++){var n=c[g];if(e.call(l,n,g,c))return{i:g,v:n}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(c,e,l){if(l.get||l.set)throw new TypeError("ES3 does not support getters and setters.");c!=Array.prototype&&c!=Object.prototype&&(c[e]=l.value)};
$jscomp.getGlobal=function(c){return"undefined"!=typeof window&&window===c?c:"undefined"!=typeof global?global:c};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(c,e,l,f){if(e){l=$jscomp.global;c=c.split(".");for(f=0;f<c.length-1;f++){var g=c[f];g in l||(l[g]={});l=l[g]}c=c[c.length-1];f=l[c];e=e(f);e!=f&&null!=e&&$jscomp.defineProperty(l,c,{configurable:!0,writable:!0,value:e})}};
$jscomp.getGlobal=function(c){return"undefined"!=typeof window&&window===c?c:"undefined"!=typeof global&&null!=global?global:c};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(c,e,l,f){if(e){l=$jscomp.global;c=c.split(".");for(f=0;f<c.length-1;f++){var g=c[f];g in l||(l[g]={});l=l[g]}c=c[c.length-1];f=l[c];e=e(f);e!=f&&null!=e&&$jscomp.defineProperty(l,c,{configurable:!0,writable:!0,value:e})}};
$jscomp.polyfill("Array.prototype.find",function(c){return c?c:function(c,l){return $jscomp.findInternal(this,c,l).v}},"es6-impl","es3");
sysPass.Actions=function(c){var e=c.log,l=0,f={entrypoint:"/index.php",doAction:"/index.php",updateItems:"/index.php",user:{savePreferences:"/ajax/ajax_userPrefsSave.php",password:"/ajax/ajax_usrpass.php",passreset:"/ajax/ajax_passReset.php"},main:{login:"/index.php?r=login/login",install:"/ajax/ajax_install.php",upgrade:"/ajax/ajax_upgrade.php",getUpdates:"/index.php?r=index/checkUpdates",task:"/ajax/ajax_task.php"},checks:"/ajax/ajax_checkConnection.php",config:{save:"/ajax/ajax_configSave.php",
"export":"/ajax/ajax_configSave.php","import":"/ajax/ajax_configSave.php"},file:"/ajax/ajax_filesMgmt.php",link:"/index.php",plugin:"/ajax/ajax_itemSave.php",account:{save:"/index.php",saveFavorite:"/ajax/ajax_itemSave.php",request:"/ajax/ajax_itemSave.php",getFiles:"/index.php",search:"/index.php?r=account/search"},appMgmt:{show:"/index.php",save:"/index.php",search:"/index.php"},eventlog:"/ajax/ajax_eventlog.php",wiki:{show:"/ajax/ajax_wiki.php"},notice:{show:"/ajax/ajax_noticeShow.php",search:"/ajax/ajax_noticeSearch.php"}};
@@ -24,8 +24,8 @@ h={state:{tab:{index:0,refresh:!0,route:""},itemId:0,update:function(a){var c=$(
c.appRequests().getActionCall(b,function(b){if(0!==b.status)c.msg.out(b);else{var d=a.data("item-dst");n(b.data.html,{open:function(){d&&(h.state.tab.refresh=!1)},close:function(){d&&r.update(a)}})}})},"delete":function(a){e.info("appMgmt:delete");h.state.update(a);m["delete"](a,function(b){var d=a.data("item-id"),e=c.appRequests().getRequestOpts();e.url=f.entrypoint;e.method="get";e.data={r:a.data("action-route")+(d?"/"+d:""),items:b,sk:c.sk.get(),isAjax:1};c.appRequests().getActionCall(e,function(a){c.msg.out(a);
g({r:h.state.tab.route,tabIndex:h.state.tab.index})})})},save:function(a){e.info("appMgmt:save");var b=c.appRequests().getRequestOpts();b.url=f.entrypoint+"?r="+a.data("route");b.data=a.serialize();c.appRequests().getActionCall(b,function(a){c.msg.out(a);0===a.status&&(!0===h.state.tab.refresh&&g({r:h.state.tab.route,tabIndex:h.state.tab.index}),$.magnificPopup.close())})},search:function(a){e.info("appMgmt:search");m.search(a)},nav:function(a){e.info("appMgmt:nav");m.nav(a)},ldapSync:function(a){e.info("appMgmt:ldapSync");
var b='<div id="alert"><p id="alert-text">'+c.config().LANG[57]+"</p></div>";mdlDialog().show({text:b,negative:{title:c.config().LANG[44],onClick:function(a){a.preventDefault();c.msg.error(c.config().LANG[44])}},positive:{title:c.config().LANG[43],onClick:function(b){b=c.appRequests().getRequestOpts();b.url=f.appMgmt.save;b.data={actionId:a.data("action-id"),sk:c.sk.get(),isAjax:1,ldap_loginattribute:$("#ldap_loginattribute").val(),ldap_nameattribute:$("#ldap_nameattribute").val(),ldap_ads:$("#ldap_ads").prop("checked")};
c.appRequests().getActionCall(b,function(a){c.msg.out(a)})}}})}},m={search:function(a){e.info("appMgmt:search");var b=$(a.data("target")),d=c.appRequests().getRequestOpts();d.url=f.entrypoint+"?r="+a.data("action-route");d.method="get";d.data=a.serialize();c.appRequests().getActionCall(d,function(a){0===a.status?b.html(a.data.html):b.html(c.msg.html.error(a.description));c.sk.set(a.csrf)})},nav:function(a,b){e.info("grid:nav");var d=$("#"+a.data("action-form"));d.find("[name='start']").val(a.data("start"));
d.find("[name='count']").val(a.data("count"));d.find("[name='sk']").val(c.sk.get());"function"===typeof b?b(d):m.search(a)},"delete":function(a,b){var d='<div id="alert"><p id="alert-text">'+c.config().LANG[12]+"</p></div>",e=a.data("selection"),f=[];if(e&&($(e).find(".is-selected").each(function(){f.push($(this).data("item-id"))}),0===f.length))return;mdlDialog().show({text:d,negative:{title:c.config().LANG[44],onClick:function(a){a.preventDefault();c.msg.error(c.config().LANG[44])}},positive:{title:c.config().LANG[43],
c.appRequests().getActionCall(b,function(a){c.msg.out(a)})}}})}},m={search:function(a){e.info("grid:search");var b=$(a.data("target")),d=c.appRequests().getRequestOpts();d.url=f.entrypoint+"?r="+a.data("action-route");d.method="get";d.data=a.serialize();c.appRequests().getActionCall(d,function(a){0===a.status?b.html(a.data.html):b.html(c.msg.html.error(a.description));c.sk.set(a.csrf)})},nav:function(a,b){e.info("grid:nav");var d=$("#"+a.data("action-form"));d.find("[name='start']").val(a.data("start"));
d.find("[name='count']").val(a.data("count"));d.find("[name='sk']").val(c.sk.get());"function"===typeof b?b(d):m.search(d)},"delete":function(a,b){var d='<div id="alert"><p id="alert-text">'+c.config().LANG[12]+"</p></div>",e=a.data("selection"),f=[];if(e&&($(e).find(".is-selected").each(function(){f.push($(this).data("item-id"))}),0===f.length))return;mdlDialog().show({text:d,negative:{title:c.config().LANG[44],onClick:function(a){a.preventDefault();c.msg.error(c.config().LANG[44])}},positive:{title:c.config().LANG[43],
onClick:function(a){a.preventDefault();"function"===typeof b&&b(f)}}})}};return{doAction:function(a,b){var d={r:a.r+(void 0!==a.itemId?"/"+a.itemId:""),isAjax:1},e=c.appRequests().getRequestOpts();e.url=f.doAction;e.method="get";e.type="html";e.addHistory=!0;e.data=d;c.appRequests().getActionCall(e,function(a){var d=$("#content");d.empty().html(a);a=c.triggers().views;a.common(d);if(void 0!==b&&"function"===typeof a[b])a[b]();d=$(".mdl-layout__content");0<d.scrollTop()&&d.animate({scrollTop:0},1E3)})},
appMgmt:u,account:p,file:{view:function(a){e.info("file:view");var b=c.appRequests().getRequestOpts();b.url=f.entrypoint;b.method="get";b.data={r:a.data("action-route")+"/"+a.data("item-id"),sk:c.sk.get()};c.appRequests().getActionCall(b,function(b){if(1===b.status)return c.msg.out(b);v(a,b.data.html)})},download:function(a){e.info("file:download");a={r:a.data("action-route")+"/"+a.data("item-id"),sk:c.sk.get()};$.fileDownload(f.entrypoint,{httpMethod:"GET",data:a})},"delete":function(a){e.info("file:delete");
var b='<div id="alert"><p id="alert-text">'+c.config().LANG[15]+"</p></div>";mdlDialog().show({text:b,negative:{title:c.config().LANG[44],onClick:function(a){a.preventDefault();c.msg.error(c.config().LANG[44])}},positive:{title:c.config().LANG[43],onClick:function(b){b=c.appRequests().getRequestOpts();b.url=f.entrypoint;b.method="get";b.data={r:a.data("action-route")+"/"+a.data("item-id"),sk:c.sk.get()};c.appRequests().getActionCall(b,function(a){c.msg.out(a);0===a.status&&p.listFiles($("#list-account-files"))})}}})}},

View File

@@ -1,5 +1,5 @@
var $jscomp={scope:{},findInternal:function(b,l,h){b instanceof String&&(b=String(b));for(var m=b.length,n=0;n<m;n++){var w=b[n];if(l.call(h,w,n,b))return{i:n,v:w}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(b,l,h){if(h.get||h.set)throw new TypeError("ES3 does not support getters and setters.");b!=Array.prototype&&b!=Object.prototype&&(b[l]=h.value)};
$jscomp.getGlobal=function(b){return"undefined"!=typeof window&&window===b?b:"undefined"!=typeof global?global:b};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(b,l,h,m){if(l){h=$jscomp.global;b=b.split(".");for(m=0;m<b.length-1;m++){var n=b[m];n in h||(h[n]={});h=h[n]}b=b[b.length-1];m=h[b];l=l(m);l!=m&&null!=l&&$jscomp.defineProperty(h,b,{configurable:!0,writable:!0,value:l})}};
$jscomp.getGlobal=function(b){return"undefined"!=typeof window&&window===b?b:"undefined"!=typeof global&&null!=global?global:b};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(b,l,h,m){if(l){h=$jscomp.global;b=b.split(".");for(m=0;m<b.length-1;m++){var n=b[m];n in h||(h[n]={});h=h[n]}b=b[b.length-1];m=h[b];l=l(m);l!=m&&null!=l&&$jscomp.defineProperty(h,b,{configurable:!0,writable:!0,value:l})}};
$jscomp.polyfill("Array.prototype.find",function(b){return b?b:function(b,h){return $jscomp.findInternal(this,b,h).v}},"es6-impl","es3");$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.symbolCounter_=0;$jscomp.Symbol=function(b){return $jscomp.SYMBOL_PREFIX+(b||"")+$jscomp.symbolCounter_++};
$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var b=$jscomp.global.Symbol.iterator;b||(b=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[b]&&$jscomp.defineProperty(Array.prototype,b,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}};$jscomp.arrayIterator=function(b){var l=0;return $jscomp.iteratorPrototype(function(){return l<b.length?{done:!1,value:b[l++]}:{done:!0}})};
$jscomp.iteratorPrototype=function(b){$jscomp.initSymbolIterator();b={next:b};b[$jscomp.global.Symbol.iterator]=function(){return this};return b};$jscomp.array=$jscomp.array||{};$jscomp.iteratorFromArray=function(b,l){$jscomp.initSymbolIterator();b instanceof String&&(b+="");var h=0,m={next:function(){if(h<b.length){var n=h++;return{value:l(n,b[n]),done:!1}}m.next=function(){return{done:!0,value:void 0}};return m.next()}};m[Symbol.iterator]=function(){return m};return m};

View File

@@ -1,5 +1,5 @@
var $jscomp={scope:{},findInternal:function(b,d,f){b instanceof String&&(b=String(b));for(var a=b.length,c=0;c<a;c++){var e=b[c];if(d.call(f,e,c,b))return{i:c,v:e}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(b,d,f){if(f.get||f.set)throw new TypeError("ES3 does not support getters and setters.");b!=Array.prototype&&b!=Object.prototype&&(b[d]=f.value)};
$jscomp.getGlobal=function(b){return"undefined"!=typeof window&&window===b?b:"undefined"!=typeof global?global:b};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(b,d,f,a){if(d){f=$jscomp.global;b=b.split(".");for(a=0;a<b.length-1;a++){var c=b[a];c in f||(f[c]={});f=f[c]}b=b[b.length-1];a=f[b];d=d(a);d!=a&&null!=d&&$jscomp.defineProperty(f,b,{configurable:!0,writable:!0,value:d})}};
$jscomp.getGlobal=function(b){return"undefined"!=typeof window&&window===b?b:"undefined"!=typeof global&&null!=global?global:b};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(b,d,f,a){if(d){f=$jscomp.global;b=b.split(".");for(a=0;a<b.length-1;a++){var c=b[a];c in f||(f[c]={});f=f[c]}b=b[b.length-1];a=f[b];d=d(a);d!=a&&null!=d&&$jscomp.defineProperty(f,b,{configurable:!0,writable:!0,value:d})}};
$jscomp.polyfill("Array.prototype.find",function(b){return b?b:function(b,f){return $jscomp.findInternal(this,b,f).v}},"es6-impl","es3");
sysPass.Triggers=function(b){var d=b.log,f=function(a){var c={valueField:"id",labelField:"name",searchField:["name"]};a.find(".select-box").each(function(a){var d=$(this);c.plugins=d.hasClass("select-box-deselect")?{clear_selection:{title:b.config().LANG[51]}}:{};if(d.data("onchange")){var e=d.data("onchange").split("/");c.onChange=function(a){if(0<a)if(2===e.length)sysPassApp.actions()[e[0]][e[1]](d);else sysPassApp.actions()[e[0]](d)}}d.selectize(c)});a.find("#allowed_exts").selectize({create:function(a){return{value:a.toUpperCase(),
text:a.toUpperCase()}},createFilter:/^[a-z0-9]{1,4}$/i,plugins:["remove_button"]});a.find("#wikifilter").selectize({create:!0,createFilter:/^[a-z0-9:._-]+$/i,plugins:["remove_button"]})};return{views:{main:function(){d.info("views:main");clipboard.isSupported()||b.msg.info(b.config().LANG[65]);$(".btn-menu").click(function(){var a=$(this);"1"===a.attr("data-history-reset")&&b.appRequests().history.reset();b.appActions().doAction({r:a.data("route")},a.data("view"))});$("#btnLogout").click(function(a){b.appActions().main.logout()});