add PasswordLoginForbiddenException
This commit is contained in:
parent
cc532bb14a
commit
82b50d126c
|
@ -31,6 +31,7 @@ namespace OCA\DAV\Connector\Sabre;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use OC\AppFramework\Http\Request;
|
use OC\AppFramework\Http\Request;
|
||||||
|
use OC\Authentication\Exceptions\PasswordLoginForbiddenException;
|
||||||
use OC\Authentication\TwoFactorAuth\Manager;
|
use OC\Authentication\TwoFactorAuth\Manager;
|
||||||
use OC\User\Session;
|
use OC\User\Session;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
|
@ -115,7 +116,8 @@ class Auth extends AbstractBasic {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
\OC_Util::setupFS(); //login hooks may need early access to the filesystem
|
\OC_Util::setupFS(); //login hooks may need early access to the filesystem
|
||||||
if($this->userSession->logClientIn($username, $password, $this->request)) {
|
try {
|
||||||
|
if ($this->userSession->logClientIn($username, $password, $this->request)) {
|
||||||
\OC_Util::setupFS($this->userSession->getUser()->getUID());
|
\OC_Util::setupFS($this->userSession->getUser()->getUID());
|
||||||
$this->session->set(self::DAV_AUTHENTICATED, $this->userSession->getUser()->getUID());
|
$this->session->set(self::DAV_AUTHENTICATED, $this->userSession->getUser()->getUID());
|
||||||
$this->session->close();
|
$this->session->close();
|
||||||
|
@ -124,6 +126,11 @@ class Auth extends AbstractBasic {
|
||||||
$this->session->close();
|
$this->session->close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} catch (PasswordLoginForbiddenException $ex) {
|
||||||
|
// TODO: throw sabre exception
|
||||||
|
$this->session->close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,6 +208,22 @@ class AuthTest extends TestCase {
|
||||||
$this->assertFalse($this->invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
|
$this->assertFalse($this->invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testValidateUserPassWithPasswordLoginForbidden() {
|
||||||
|
$this->userSession
|
||||||
|
->expects($this->once())
|
||||||
|
->method('isLoggedIn')
|
||||||
|
->will($this->returnValue(false));
|
||||||
|
$this->userSession
|
||||||
|
->expects($this->once())
|
||||||
|
->method('logClientIn')
|
||||||
|
->with('MyTestUser', 'MyTestPassword')
|
||||||
|
->will($this->throwException(new \OC\Authentication\Exceptions\PasswordLoginForbiddenException()));
|
||||||
|
$this->session
|
||||||
|
->expects($this->once())
|
||||||
|
->method('close');
|
||||||
|
|
||||||
|
$this->assertFalse($this->invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
|
||||||
|
}
|
||||||
|
|
||||||
public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGet() {
|
public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGet() {
|
||||||
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
|
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace OC\AppFramework\Middleware\Security;
|
||||||
|
|
||||||
use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
|
use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
|
||||||
use OC\AppFramework\Utility\ControllerMethodReflector;
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
|
use OC\Authentication\Exceptions\PasswordLoginForbiddenException;
|
||||||
use OC\User\Session;
|
use OC\User\Session;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
use OCP\AppFramework\Http;
|
use OCP\AppFramework\Http;
|
||||||
|
@ -89,9 +90,13 @@ class CORSMiddleware extends Middleware {
|
||||||
$pass = $this->request->server['PHP_AUTH_PW'];
|
$pass = $this->request->server['PHP_AUTH_PW'];
|
||||||
|
|
||||||
$this->session->logout();
|
$this->session->logout();
|
||||||
if(!$this->session->logClientIn($user, $pass, $this->request)) {
|
try {
|
||||||
|
if (!$this->session->logClientIn($user, $pass, $this->request)) {
|
||||||
throw new SecurityException('CORS requires basic auth', Http::STATUS_UNAUTHORIZED);
|
throw new SecurityException('CORS requires basic auth', Http::STATUS_UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
} catch (PasswordLoginForbiddenException $ex) {
|
||||||
|
throw new SecurityException('Password login forbidden, use token instead', Http::STATUS_UNAUTHORIZED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christoph Wurst <christoph@owncloud.com>
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||||
|
* @license AGPL-3.0
|
||||||
|
*
|
||||||
|
* This code is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace OC\Authentication\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class PasswordLoginForbiddenException extends Exception {
|
||||||
|
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ namespace OC\User;
|
||||||
use OC;
|
use OC;
|
||||||
use OC\Authentication\Exceptions\InvalidTokenException;
|
use OC\Authentication\Exceptions\InvalidTokenException;
|
||||||
use OC\Authentication\Exceptions\PasswordlessTokenException;
|
use OC\Authentication\Exceptions\PasswordlessTokenException;
|
||||||
|
use OC\Authentication\Exceptions\PasswordLoginForbiddenException;
|
||||||
use OC\Authentication\Token\IProvider;
|
use OC\Authentication\Token\IProvider;
|
||||||
use OC\Authentication\Token\IToken;
|
use OC\Authentication\Token\IToken;
|
||||||
use OC\Hooks\Emitter;
|
use OC\Hooks\Emitter;
|
||||||
|
@ -350,17 +351,16 @@ class Session implements IUserSession, Emitter {
|
||||||
* @param string $password
|
* @param string $password
|
||||||
* @param IRequest $request
|
* @param IRequest $request
|
||||||
* @throws LoginException
|
* @throws LoginException
|
||||||
|
* @throws PasswordLoginForbiddenException
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function logClientIn($user, $password, IRequest $request) {
|
public function logClientIn($user, $password, IRequest $request) {
|
||||||
$isTokenPassword = $this->isTokenPassword($password);
|
$isTokenPassword = $this->isTokenPassword($password);
|
||||||
if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
|
if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
|
||||||
// TODO: throw LoginException instead (https://github.com/owncloud/core/pull/24616)
|
throw new PasswordLoginForbiddenException();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
|
if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
|
||||||
// TODO: throw LoginException instead (https://github.com/owncloud/core/pull/24616)
|
throw new PasswordLoginForbiddenException();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (!$this->login($user, $password) ) {
|
if (!$this->login($user, $password) ) {
|
||||||
$users = $this->manager->getByEmail($user);
|
$users = $this->manager->getByEmail($user);
|
||||||
|
@ -442,8 +442,8 @@ class Session implements IUserSession, Emitter {
|
||||||
*/
|
*/
|
||||||
public function tryBasicAuthLogin(IRequest $request) {
|
public function tryBasicAuthLogin(IRequest $request) {
|
||||||
if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
|
if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
|
||||||
$result = $this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request);
|
try {
|
||||||
if ($result === true) {
|
if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request)) {
|
||||||
/**
|
/**
|
||||||
* Add DAV authenticated. This should in an ideal world not be
|
* Add DAV authenticated. This should in an ideal world not be
|
||||||
* necessary but the iOS App reads cookies from anywhere instead
|
* necessary but the iOS App reads cookies from anywhere instead
|
||||||
|
@ -456,6 +456,9 @@ class Session implements IUserSession, Emitter {
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} catch (PasswordLoginForbiddenException $ex) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,31 @@ class CORSMiddlewareTest extends \Test\TestCase {
|
||||||
$middleware->beforeController($this, __FUNCTION__, new Response());
|
$middleware->beforeController($this, __FUNCTION__, new Response());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @CORS
|
||||||
|
* @expectedException \OC\AppFramework\Middleware\Security\Exceptions\SecurityException
|
||||||
|
*/
|
||||||
|
public function testCORSShouldFailIfPasswordLoginIsForbidden() {
|
||||||
|
$request = new Request(
|
||||||
|
['server' => [
|
||||||
|
'PHP_AUTH_USER' => 'user',
|
||||||
|
'PHP_AUTH_PW' => 'pass'
|
||||||
|
]],
|
||||||
|
$this->getMock('\OCP\Security\ISecureRandom'),
|
||||||
|
$this->getMock('\OCP\IConfig')
|
||||||
|
);
|
||||||
|
$this->session->expects($this->once())
|
||||||
|
->method('logout');
|
||||||
|
$this->session->expects($this->once())
|
||||||
|
->method('logClientIn')
|
||||||
|
->with($this->equalTo('user'), $this->equalTo('pass'))
|
||||||
|
->will($this->throwException(new \OC\Authentication\Exceptions\PasswordLoginForbiddenException));
|
||||||
|
$this->reflector->reflect($this, __FUNCTION__);
|
||||||
|
$middleware = new CORSMiddleware($request, $this->reflector, $this->session);
|
||||||
|
|
||||||
|
$middleware->beforeController($this, __FUNCTION__, new Response());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @CORS
|
* @CORS
|
||||||
* @expectedException \OC\AppFramework\Middleware\Security\Exceptions\SecurityException
|
* @expectedException \OC\AppFramework\Middleware\Security\Exceptions\SecurityException
|
||||||
|
|
|
@ -306,6 +306,9 @@ class SessionTest extends \Test\TestCase {
|
||||||
$userSession->login('foo', 'bar');
|
$userSession->login('foo', 'bar');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OC\Authentication\Exceptions\PasswordLoginForbiddenException
|
||||||
|
*/
|
||||||
public function testLogClientInNoTokenPasswordWith2fa() {
|
public function testLogClientInNoTokenPasswordWith2fa() {
|
||||||
$manager = $this->getMockBuilder('\OC\User\Manager')
|
$manager = $this->getMockBuilder('\OC\User\Manager')
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
|
@ -329,7 +332,7 @@ class SessionTest extends \Test\TestCase {
|
||||||
->with('token_auth_enforced', false)
|
->with('token_auth_enforced', false)
|
||||||
->will($this->returnValue(true));
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
$this->assertFalse($userSession->logClientIn('john', 'doe', $request));
|
$userSession->logClientIn('john', 'doe', $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLogClientInWithTokenPassword() {
|
public function testLogClientInWithTokenPassword() {
|
||||||
|
@ -371,6 +374,9 @@ class SessionTest extends \Test\TestCase {
|
||||||
$this->assertTrue($userSession->logClientIn('john', 'doe', $request));
|
$this->assertTrue($userSession->logClientIn('john', 'doe', $request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \OC\Authentication\Exceptions\PasswordLoginForbiddenException
|
||||||
|
*/
|
||||||
public function testLogClientInNoTokenPasswordNo2fa() {
|
public function testLogClientInNoTokenPasswordNo2fa() {
|
||||||
$manager = $this->getMockBuilder('\OC\User\Manager')
|
$manager = $this->getMockBuilder('\OC\User\Manager')
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
|
@ -399,7 +405,7 @@ class SessionTest extends \Test\TestCase {
|
||||||
->with('john')
|
->with('john')
|
||||||
->will($this->returnValue(true));
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
$this->assertFalse($userSession->logClientIn('john', 'doe', $request));
|
$userSession->logClientIn('john', 'doe', $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRememberLoginValidToken() {
|
public function testRememberLoginValidToken() {
|
||||||
|
|
Loading…
Reference in New Issue