
refactored db transactions to allow IOC that would make easier unit testing Change-Id: Ifbaa14e8b8025c3a68b4eddd794c92f389087a94 Implements: blueprint openid-oauth2-integration-testing
140 lines
7.1 KiB
PHP
140 lines
7.1 KiB
PHP
<?php
|
|
|
|
namespace services;
|
|
|
|
use BannedIP;
|
|
use DateTime;
|
|
use DB;
|
|
use Exception;
|
|
use Log;
|
|
use UserExceptionTrail;
|
|
use utils\exceptions\UnacquiredLockException;
|
|
use utils\services\ICacheService;
|
|
use utils\services\ILockManagerService;
|
|
use utils\services\IServerConfigurationService;
|
|
use utils\IPHelper;
|
|
use utils\db\ITransactionService;
|
|
/**
|
|
* Class BlacklistSecurityPolicy
|
|
* implements check point security pattern
|
|
* @package services
|
|
*/
|
|
class BlacklistSecurityPolicy extends AbstractBlacklistSecurityPolicy
|
|
{
|
|
|
|
private $exception_dictionary = array();
|
|
|
|
/**
|
|
* @param IServerConfigurationService $server_configuration_service
|
|
* @param ILockManagerService $lock_manager_service
|
|
* @param ICacheService $cache_service
|
|
* @param ITransactionService $tx_service
|
|
*/
|
|
public function __construct(IServerConfigurationService $server_configuration_service, ILockManagerService $lock_manager_service, ICacheService $cache_service,ITransactionService $tx_service)
|
|
{
|
|
parent::__construct($server_configuration_service, $lock_manager_service, $cache_service,$tx_service);
|
|
// here we configure on which exceptions are we interested and the max occurrence attempts and initial delay on tar pit for
|
|
// offending IP address
|
|
$this->exception_dictionary = array(
|
|
'openid\exceptions\ReplayAttackException' => array(null,'BlacklistSecurityPolicy.ReplayAttackExceptionInitialDelay'),
|
|
'openid\exceptions\InvalidNonce' => array('BlacklistSecurityPolicy.MaxInvalidNonceAttempts','BlacklistSecurityPolicy.InvalidNonceInitialDelay'),
|
|
'openid\exceptions\InvalidOpenIdMessageException' => array('BlacklistSecurityPolicy.MaxInvalidOpenIdMessageExceptionAttempts','BlacklistSecurityPolicy.InvalidOpenIdMessageExceptionInitialDelay'),
|
|
'openid\exceptions\OpenIdInvalidRealmException' => array('BlacklistSecurityPolicy.MaxOpenIdInvalidRealmExceptionAttempts','BlacklistSecurityPolicy.OpenIdInvalidRealmExceptionInitialDelay'),
|
|
'openid\exceptions\InvalidOpenIdMessageMode' => array('BlacklistSecurityPolicy.MaxInvalidOpenIdMessageModeAttempts','BlacklistSecurityPolicy.InvalidOpenIdMessageModeInitialDelay'),
|
|
'openid\exceptions\InvalidOpenIdAuthenticationRequestMode' => array('BlacklistSecurityPolicy.MaxInvalidOpenIdAuthenticationRequestModeAttempts','BlacklistSecurityPolicy.InvalidOpenIdAuthenticationRequestModeInitialDelay'),
|
|
'openid\exceptions\InvalidAssociation' => array('BlacklistSecurityPolicy.MaxInvalidAssociationAttempts','BlacklistSecurityPolicy.InvalidAssociationInitialDelay'),
|
|
'auth\exceptions\AuthenticationException' => array('BlacklistSecurityPolicy.MaxAuthenticationExceptionAttempts','BlacklistSecurityPolicy.AuthenticationExceptionInitialDelay'),
|
|
'oauth2\exceptions\ReplayAttackException' => array(null,'BlacklistSecurityPolicy.OAuth2.AuthCodeReplayAttackInitialDelay'),
|
|
'oauth2\exceptions\InvalidAuthorizationCodeException' => array('BlacklistSecurityPolicy.OAuth2.MaxInvalidAuthorizationCodeAttempts','BlacklistSecurityPolicy.OAuth2.InvalidAuthorizationCodeInitialDelay'),
|
|
'oauth2\exceptions\BearerTokenDisclosureAttemptException' => array('BlacklistSecurityPolicy.OAuth2.MaxInvalidBearerTokenDisclosureAttempt','BlacklistSecurityPolicy.OAuth2.BearerTokenDisclosureAttemptInitialDelay'),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check policy
|
|
* @return bool
|
|
*/
|
|
public function check()
|
|
{
|
|
$res = true;
|
|
$remote_address = IPHelper::getUserIp();
|
|
try {
|
|
//check if banned ip is on cache ...
|
|
if ($this->cache_service->incCounterIfExists($remote_address)){
|
|
$this->counter_measure->trigger();
|
|
return false;
|
|
}
|
|
//check on db
|
|
if (!is_null($banned_ip = BannedIP::where("ip", "=", $remote_address)->first())) {
|
|
// banned ip exists on DB, set lock
|
|
$this->lock_manager_service->acquireLock("lock.ip." . $remote_address);
|
|
try {
|
|
//check lifetime
|
|
$issued = $banned_ip->created_at;
|
|
$utc_now = gmdate("Y-m-d H:i:s", time());
|
|
$utc_now = DateTime::createFromFormat("Y-m-d H:i:s", $utc_now);
|
|
//get time lived on seconds
|
|
$time_lived_seconds = abs($utc_now->getTimestamp() - $issued->getTimestamp());
|
|
if ($time_lived_seconds >= intval($this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.BannedIpLifeTimeSeconds"))) {
|
|
//void banned ip
|
|
$banned_ip->delete();
|
|
return true;
|
|
}
|
|
|
|
$banned_ip->hits = $banned_ip->hits + 1;
|
|
$banned_ip->Save();
|
|
//save ip on cache
|
|
$this->cache_service->addSingleValue($banned_ip->ip, $banned_ip->hits,intval($this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.BannedIpLifeTimeSeconds") - $time_lived_seconds));
|
|
}
|
|
catch (Exception $ex) {
|
|
Log::error($ex);
|
|
}
|
|
//release lock
|
|
$this->lock_manager_service->releaseLock("lock.ip." . $remote_address);
|
|
$this->counter_measure->trigger();
|
|
return false;
|
|
}
|
|
}
|
|
catch (UnacquiredLockException $ex1) {
|
|
Log::error($ex1);
|
|
$res = false;
|
|
} catch (Exception $ex) {
|
|
Log::error($ex);
|
|
$res = false;
|
|
}
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Apply security policy
|
|
* @param Exception $ex
|
|
* @return mixed|void
|
|
*/
|
|
public function apply(Exception $ex)
|
|
{
|
|
try {
|
|
$remote_ip = IPHelper::getUserIp();
|
|
$exception_class = get_class($ex);
|
|
//check exception count by type on last "MinutesWithoutExceptions" minutes...
|
|
$exception_count = intval(UserExceptionTrail::where('from_ip', '=', $remote_ip)
|
|
->where('exception_type', '=', $exception_class)
|
|
->where('created_at', '>', DB::raw('( UTC_TIMESTAMP() - INTERVAL ' . $this->server_configuration_service->getConfigValue("BlacklistSecurityPolicy.MinutesWithoutExceptions") . ' MINUTE )'))
|
|
->count());
|
|
if(array_key_exists($exception_class,$this->exception_dictionary)){
|
|
$params = $this->exception_dictionary[$exception_class];
|
|
$max_attempts = !is_null($params[0]) && !empty($params[0])? intval($this->server_configuration_service->getConfigValue($params[0])):0;
|
|
$initial_delay_on_tar_pit = intval($this->server_configuration_service->getConfigValue($params[1]));
|
|
if ($exception_count >= $max_attempts)
|
|
$this->createBannedIP($initial_delay_on_tar_pit, $exception_class);
|
|
}
|
|
} catch (Exception $ex) {
|
|
Log::error($ex);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|