Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protect public links password page #90

Merged
merged 5 commits into from
Jun 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .drone.star
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ config = {
'suites': {
'webUIBruteForceProtection': 'webUIBruteForce',
},
'servers': [
'daily-master-qa'
],
'browsers': [
'chrome',
'firefox'
Expand Down
56 changes: 56 additions & 0 deletions appinfo/Migrations/Version20191109111104.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
karakayasemi marked this conversation as resolved.
Show resolved Hide resolved
/**
* @author Semih Serhat Karakaya <karakayasemi@itu.edu.tr>
*
* @copyright Copyright (c) 2020, ownCloud GmbH
* @license GPL-2.0
*
* This program 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 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
namespace OCA\brute_force_protection\Migrations;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why brute_force_protection is not in CamelCase?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MigrationService cannot find migration classes that has '_' character in app name, it may indicate a bug on core. Because of that, I have been followed same syntax with previous migration class of this app.


use Doctrine\DBAL\Schema\Schema;
use OCP\Migration\ISchemaMigration;

class Version20191109111104 implements ISchemaMigration {
public function changeSchema(Schema $schema, array $options) {
$prefix = $options['tablePrefix'];
if (!$schema->hasTable("{$prefix}bfp_link_accesses")) {
$table = $schema->createTable("{$prefix}bfp_link_accesses");
$table->addColumn('id', 'integer', [
'autoincrement' => true,
'unsigned' => true,
'notnull' => true,
'length' => 11,
]);
$table->addColumn('ip', 'string', [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('link_token', 'string', [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('attempted_at', 'integer', [
'notnull' => true,
]);

$table->setPrimaryKey(['id']);
$table->addIndex(['ip'], 'bfp_link_accesses_ip');
jvillafanez marked this conversation as resolved.
Show resolved Hide resolved
$table->addIndex(['attempted_at'], 'bfp_link_accesses_at');
}
}
}
4 changes: 2 additions & 2 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ See the [2-Factor Authentication](https://marketplace.owncloud.com/apps/twofacto
<summary>Prevent attackers from guessing user passwords</summary>
<licence>GPLv2</licence>
<author>Semih Serhat Karakaya</author>
<version>1.0.1</version>
<version>1.1.0</version>
<namespace>BruteForceProtection</namespace>
<use-migrations>true</use-migrations>
<dependencies>
<owncloud min-version="10.2" max-version="10" />
<owncloud min-version="10.5" max-version="10" />
</dependencies>
<types>
<prelogin/>
Expand Down
2 changes: 1 addition & 1 deletion lib/BruteForceProtectionConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public function getBruteForceProtectionFailTolerance() {
}

/**
* Count failed login attempts over how many seconds
* Count failed attempts over how many seconds
*
* @return int
*/
Expand Down
48 changes: 48 additions & 0 deletions lib/Db/FailedLinkAccess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
/**
* @author Semih Serhat Karakaya <karakayasemi@itu.edu.tr>
*
* @copyright Copyright (c) 2020, ownCloud GmbH
* @license GPL-2.0
*
* This program 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 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

namespace OCA\BruteForceProtection\Db;

use OCP\AppFramework\Db\Entity;

/**
* @method int getId()
* @method void setId(\int $id)
* @method string getIp()
* @method void setIp(string $ip)
* @method string getLinkToken()
* @method void setLinkToken(string $linkToken)
* @method int getAttemptedAt()
* @method void setAttemptedAt(int $attemptedAt)
*/
class FailedLinkAccess extends Entity {

/** @var string $ip */
protected $ip;

/** @var string $linkToken */
protected $linkToken;

/** @var int $attemptedAt */
protected $attemptedAt;
}
120 changes: 120 additions & 0 deletions lib/Db/FailedLinkAccessMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
/**
* @author Semih Serhat Karakaya <karakayasemi@itu.edu.tr>
*
* @copyright Copyright (c) 2020 ownCloud GmbH
* @license GPL-2.0
*
* This program 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 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

namespace OCA\BruteForceProtection\Db;

use OCP\AppFramework\Db\Mapper;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IDBConnection;

/**
* Class FailedLinkAccessMapper
* @package OCA\BruteForceProtection\Db
*/
class FailedLinkAccessMapper extends Mapper {

/**
* @var ITimeFactory $timeFactory
*/
protected $timeFactory;

/**
* @var string $tableName
*/
protected $tableName = 'bfp_link_accesses';

/**
* FailedLinkAccessMapper constructor.
*
* @param IDBConnection $db
* @param ITimeFactory $timeFactory
*/
public function __construct(
IDBConnection $db,
ITimeFactory $timeFactory
) {
parent::__construct($db, $this->tableName);
$this->timeFactory = $timeFactory;
}

/**
* @param string $token
* @param string $ip
* @param int $thresholdTime the timestamp where attempts will start counting
* @return int
*/
public function getFailedAccessCountForTokenIpCombination($token, $ip, $thresholdTime) {
$builder = $this->db->getQueryBuilder();
$attempts = $builder->selectAlias($builder->createFunction('COUNT(*)'), 'count')
->from($this->tableName)
->where($builder->expr()->gt('attempted_at', $builder->createNamedParameter($thresholdTime)))
->andWhere($builder->expr()->eq('link_token', $builder->createNamedParameter($token)))
->andWhere($builder->expr()->eq('ip', $builder->createNamedParameter($ip)))
->execute()
->fetch();
return \intval($attempts['count']);
}

/**
* @param string $token
* @param string $ip
* @return int|null unix timestamp of the last attempt or null if no prior attempt
*/
public function getLastFailedAccessTimeForTokenIpCombination($token, $ip) {
$builder = $this->db->getQueryBuilder();
$lastAttempt = $builder->select('attempted_at')
->from($this->tableName)
->where($builder->expr()->eq('link_token', $builder->createNamedParameter($token)))
->andWhere($builder->expr()->eq('ip', $builder->createNamedParameter($ip)))
->orderBy('attempted_at', 'DESC')
->setMaxResults(1)
->execute()
->fetch();
return ($lastAttempt === false) ? null : \intval($lastAttempt['attempted_at']);
}

/**
* @param string $token
* @param string $ip
*/
public function deleteFailedAccessForTokenIpCombination($token, $ip) {
$builder = $this->db->getQueryBuilder();
$builder->delete($this->tableName)
->where($builder->expr()->eq('link_token', $builder->createNamedParameter($token)))
->andWhere($builder->expr()->eq('ip', $builder->createNamedParameter($ip)))
->execute();
}

/**
* It removes entries that were created before the specified threshold seconds.
*
* @param int $threshold the amount of threshold seconds
*/
public function deleteOldFailedAccesses($threshold) {
$builder = $this->db->getQueryBuilder();
$thresholdTime = $this->timeFactory->getTime() - $threshold;
$builder->delete($this->tableName)
->where($builder->expr()->lt('attempted_at', $builder->createNamedParameter($thresholdTime)))
->execute();
}
}
25 changes: 7 additions & 18 deletions lib/Db/FailedLoginAttemptMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
namespace OCA\BruteForceProtection\Db;

use OCP\AppFramework\Db\Mapper;
use OCA\BruteForceProtection\BruteForceProtectionConfig;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IDBConnection;

Expand All @@ -35,11 +34,6 @@
*/
class FailedLoginAttemptMapper extends Mapper {

/**
* @var BruteForceProtectionConfig $config
*/
protected $config;

/**
* @var ITimeFactory $timeFactory
*/
Expand All @@ -54,27 +48,24 @@ class FailedLoginAttemptMapper extends Mapper {
* FailedLoginAttemptMapper constructor.
*
* @param IDBConnection $db
* @param BruteForceProtectionConfig $config
* @param ITimeFactory $timeFactory
*/
public function __construct(
IDBConnection $db,
BruteForceProtectionConfig $config,
ITimeFactory $timeFactory
) {
parent::__construct($db, $this->tableName);
$this->config = $config;
$this->timeFactory = $timeFactory;
}

/**
* @param string $uid
* @param string $ip
* @param int $thresholdTime the timestamp where attempts will start counting
* @return int
*/
public function getSuspiciousActivityCountForUidIpCombination($uid, $ip) {
public function getFailedLoginCountForUidIpCombination($uid, $ip, $thresholdTime) {
$builder = $this->db->getQueryBuilder();
$thresholdTime = $this->getLastFailedLoginAttemptTimeForUidIpCombination($uid, $ip) - $this->config->getBruteForceProtectionTimeThreshold();
$attempts = $builder->selectAlias($builder->createFunction('COUNT(*)'), 'count')
->from($this->tableName)
->where($builder->expr()->gt('attempted_at', $builder->createNamedParameter($thresholdTime)))
Expand All @@ -88,28 +79,26 @@ public function getSuspiciousActivityCountForUidIpCombination($uid, $ip) {
/**
* @param string $uid
* @param string $ip
* @return int
* @return int|null unix timestamp of the last attempt or null if no prior attempt
*/
public function getLastFailedLoginAttemptTimeForUidIpCombination($uid, $ip) {
$builder = $this->db->getQueryBuilder();
$thresholdTime = $this->timeFactory->getTime() - $this->config->getBruteForceProtectionBanPeriod();
$lastAttempt = $builder->select('attempted_at')
->from($this->tableName)
->where($builder->expr()->gt('attempted_at', $builder->createNamedParameter($thresholdTime)))
->andWhere($builder->expr()->eq('uid', $builder->createNamedParameter($uid)))
->where($builder->expr()->eq('uid', $builder->createNamedParameter($uid)))
->andWhere($builder->expr()->eq('ip', $builder->createNamedParameter($ip)))
->orderBy('attempted_at', 'DESC')
->setMaxResults(1)
->execute()
->fetch();
return ($lastAttempt === false) ? 0 : \intval($lastAttempt['attempted_at']);
return ($lastAttempt === false) ? null : \intval($lastAttempt['attempted_at']);
}

/**
* @param string $uid
* @param string $ip
*/
public function deleteSuspiciousAttemptsForUidIpCombination($uid, $ip) {
public function deleteFailedLoginAttemptsForUidIpCombination($uid, $ip) {
$builder = $this->db->getQueryBuilder();
$builder->delete($this->tableName)
->where($builder->expr()->eq('uid', $builder->createNamedParameter($uid)))
Expand All @@ -118,7 +107,7 @@ public function deleteSuspiciousAttemptsForUidIpCombination($uid, $ip) {
}

/**
* It removes entries that created before the specified threshold seconds.
* It removes entries that were created before the specified threshold seconds.
*
* @param int $threshold the amount of threshold seconds
*/
Expand Down
27 changes: 27 additions & 0 deletions lib/Exceptions/LinkAuthException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
/**
* @author Semih Serhat Karakaya <karakayasemi@itu.edu.tr>
*
* @copyright Copyright (c) 2020, ownCloud GmbH
* @license GPL-2.0
*
* This program 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 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

namespace OCA\BruteForceProtection\Exceptions;

class LinkAuthException extends \Exception {
}
Loading