summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorMorris Jobke <hey@morrisjobke.de>2016-11-18 15:42:30 +0100
committerGitHub <noreply@github.com>2016-11-18 15:42:30 +0100
commit332eaec4c01356d0b2119d4ec8fe07fa492d031b (patch)
tree3f89772129059801fd6768985aed9f7785a1791c /core
parentfaee255ff47873ed2f8908c7d6b6e603ded11618 (diff)
parent3ffd9a755f60761d6a1f5fa3d02d07b4c2e68972 (diff)
downloadnextcloud-server-332eaec4c01356d0b2119d4ec8fe07fa492d031b.tar.gz
nextcloud-server-332eaec4c01356d0b2119d4ec8fe07fa492d031b.zip
Merge pull request #1447 from nextcloud/password-confirmation-for-some-actions
Password confirmation for some actions
Diffstat (limited to 'core')
-rw-r--r--core/Controller/LoginController.php37
-rw-r--r--core/Controller/OCJSController.php10
-rw-r--r--core/css/jquery.ocdialog.css1
-rw-r--r--core/js/js.js72
-rw-r--r--core/js/public/appconfig.js4
-rw-r--r--core/routes.php1
-rw-r--r--core/templates/layout.user.php8
7 files changed, 129 insertions, 4 deletions
diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php
index 71478470ffe..b1542de5d3c 100644
--- a/core/Controller/LoginController.php
+++ b/core/Controller/LoginController.php
@@ -1,5 +1,6 @@
<?php
/**
+ * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Christoph Wurst <christoph@owncloud.com>
@@ -31,6 +32,8 @@ use OC\User\Session;
use OC_App;
use OC_Util;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Authentication\TwoFactorAuth\IProvider;
@@ -242,6 +245,8 @@ class LoginController extends Controller {
// User has successfully logged in, now remove the password reset link, when it is available
$this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
+ $this->session->set('last-password-confirm', $loginResult->getLastLogin());
+
if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) {
$this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login);
@@ -273,4 +278,36 @@ class LoginController extends Controller {
return $this->generateRedirect($redirect_url);
}
+ /**
+ * @NoAdminRequired
+ * @UseSession
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * @param string $password
+ * @return DataResponse
+ */
+ public function confirmPassword($password) {
+ $currentDelay = $this->throttler->getDelay($this->request->getRemoteAddress());
+ $this->throttler->sleepDelay($this->request->getRemoteAddress());
+
+ $user = $this->userSession->getUser();
+ if (!$user instanceof IUser) {
+ return new DataResponse([], Http::STATUS_UNAUTHORIZED);
+ }
+
+ $loginResult = $this->userManager->checkPassword($user->getUID(), $password);
+ if ($loginResult === false) {
+ $this->throttler->registerAttempt('sudo', $this->request->getRemoteAddress(), ['user' => $user->getUID()]);
+ if ($currentDelay === 0) {
+ $this->throttler->sleepDelay($this->request->getRemoteAddress());
+ }
+
+ return new DataResponse([], Http::STATUS_FORBIDDEN);
+ }
+
+ $confirmTimestamp = time();
+ $this->session->set('last-password-confirm', $confirmTimestamp);
+ return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
+ }
}
diff --git a/core/Controller/OCJSController.php b/core/Controller/OCJSController.php
index b1c2208377e..c2292a6733e 100644
--- a/core/Controller/OCJSController.php
+++ b/core/Controller/OCJSController.php
@@ -32,6 +32,7 @@ use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IRequest;
+use OCP\ISession;
use OCP\IURLGenerator;
use OCP\IUserSession;
@@ -48,7 +49,8 @@ class OCJSController extends Controller {
* @param IL10N $l
* @param \OC_Defaults $defaults
* @param IAppManager $appManager
- * @param IUserSession $session
+ * @param ISession $session
+ * @param IUserSession $userSession
* @param IConfig $config
* @param IGroupManager $groupManager
* @param IniGetWrapper $iniWrapper
@@ -59,7 +61,8 @@ class OCJSController extends Controller {
IL10N $l,
\OC_Defaults $defaults,
IAppManager $appManager,
- IUserSession $session,
+ ISession $session,
+ IUserSession $userSession,
IConfig $config,
IGroupManager $groupManager,
IniGetWrapper $iniWrapper,
@@ -70,7 +73,8 @@ class OCJSController extends Controller {
$l,
$defaults,
$appManager,
- $session->getUser(),
+ $session,
+ $userSession->getUser(),
$config,
$groupManager,
$iniWrapper,
diff --git a/core/css/jquery.ocdialog.css b/core/css/jquery.ocdialog.css
index 0e46ff20152..d1a42694589 100644
--- a/core/css/jquery.ocdialog.css
+++ b/core/css/jquery.ocdialog.css
@@ -22,7 +22,6 @@
.oc-dialog-buttonrow {
display: block;
background: transparent;
- position: absolute;
right: 0;
bottom: 0;
padding: 10px;
diff --git a/core/js/js.js b/core/js/js.js
index 54b103a7b7d..64c7dda31e2 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -1512,8 +1512,80 @@ function initCore() {
$(this).text(OC.Util.relativeModifiedDate(parseInt($(this).attr('data-timestamp'), 10)));
});
}, 30 * 1000);
+
+ OC.PasswordConfirmation.init();
}
+OC.PasswordConfirmation = {
+ callback: null,
+
+ init: function() {
+ $('.password-confirm-required').on('click', _.bind(this.requirePasswordConfirmation, this));
+ },
+
+ requiresPasswordConfirmation: function() {
+ var timeSinceLogin = moment.now() - nc_lastLogin * 1000;
+ return timeSinceLogin > 10 * 1000; // 30 minutes
+ return timeSinceLogin > 30 * 60 * 1000; // 30 minutes
+ },
+
+ /**
+ * @param {function} callback
+ */
+ requirePasswordConfirmation: function(callback) {
+ var self = this;
+
+ if (this.requiresPasswordConfirmation()) {
+ OC.dialogs.prompt(
+ t(
+ 'core',
+ 'This action requires you to confirm your password'
+ ),
+ t('core','Authentication required'),
+ function (result, password) {
+ if (result && password !== '') {
+ self._confirmPassword(password);
+ }
+ },
+ true,
+ t('core','Password'),
+ true
+ ).then(function() {
+ var $dialog = $('.oc-dialog:visible');
+ $dialog.find('.ui-icon').remove();
+
+ var $buttons = $dialog.find('button');
+ $buttons.eq(0).text(t('core', 'Cancel'));
+ $buttons.eq(1).text(t('core', 'Confirm'));
+ });
+ }
+
+ this.callback = callback;
+ },
+
+ _confirmPassword: function(password) {
+ var self = this;
+
+ $.ajax({
+ url: OC.generateUrl('/login/confirm'),
+ data: {
+ password: password
+ },
+ type: 'POST',
+ success: function(response) {
+ nc_lastLogin = response.lastLogin;
+
+ if (_.isFunction(self.callback)) {
+ self.callback();
+ }
+ },
+ error: function() {
+ OC.Notification.showTemporary(t('core', 'Failed to authenticate, try again'));
+ }
+ });
+ }
+};
+
$(document).ready(initCore);
/**
diff --git a/core/js/public/appconfig.js b/core/js/public/appconfig.js
index de04f334ca8..d84ddaab404 100644
--- a/core/js/public/appconfig.js
+++ b/core/js/public/appconfig.js
@@ -33,6 +33,10 @@ OCP.AppConfig = {
* @internal
*/
_call: function(method, endpoint, options) {
+ if ((method === 'post' || method === 'delete') && OC.PasswordConfirmation.requiresPasswordConfirmation()) {
+ OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this._call, this, method, endpoint, options));
+ return;
+ }
$.ajax({
type: method.toUpperCase(),
diff --git a/core/routes.php b/core/routes.php
index 2ddd77c1445..e5636ff6c00 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -46,6 +46,7 @@ $application->registerRoutes($this, [
['name' => 'avatar#getTmpAvatar', 'url' => '/avatar/tmp', 'verb' => 'GET'],
['name' => 'avatar#postAvatar', 'url' => '/avatar/', 'verb' => 'POST'],
['name' => 'login#tryLogin', 'url' => '/login', 'verb' => 'POST'],
+ ['name' => 'login#confirmPassword', 'url' => '/login/confirm', 'verb' => 'POST'],
['name' => 'login#showLoginForm', 'url' => '/login', 'verb' => 'GET'],
['name' => 'login#logout', 'url' => '/logout', 'verb' => 'GET'],
['name' => 'TwoFactorChallenge#selectChallenge', 'url' => '/login/selectchallenge', 'verb' => 'GET'],
diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php
index bc8edf085d0..1d0ac5fa146 100644
--- a/core/templates/layout.user.php
+++ b/core/templates/layout.user.php
@@ -146,6 +146,14 @@
</div>
</div></nav>
+ <div id="sudo-login-background" class="hidden"></div>
+ <div id="sudo-login-form" class="hidden">
+ <?php p($l->t('This action requires you to confirm your password:')); ?><br>
+ <input type="password" class="question" autocomplete="off" name="question" value=" <?php /* Hack against firefox ignoring autocomplete="off" */ ?>"
+ placeholder="<?php p($l->t('Confirm your password')); ?>" />
+ <input class="confirm icon-confirm" title="<?php p($l->t('Confirm')); ?>" value="" type="submit">
+ </div>
+
<div id="content-wrapper">
<div id="content" class="app-<?php p($_['appid']) ?>" role="main">
<?php print_unescaped($_['content']); ?>