Merge pull request #24935 from owncloud/2fa-block-dav

block DAV if 2FA challenge needs to be solved first
This commit is contained in:
Vincent Petry 2016-06-02 15:31:18 +02:00
commit 3ff2bec5fa
6 changed files with 80 additions and 6 deletions

View File

@ -34,6 +34,7 @@ $authBackend = new Auth(
\OC::$server->getSession(), \OC::$server->getSession(),
\OC::$server->getUserSession(), \OC::$server->getUserSession(),
\OC::$server->getRequest(), \OC::$server->getRequest(),
\OC::$server->getTwoFactorAuthManager(),
'principals/' 'principals/'
); );
$principalBackend = new Principal( $principalBackend = new Principal(

View File

@ -35,6 +35,7 @@ $authBackend = new Auth(
\OC::$server->getSession(), \OC::$server->getSession(),
\OC::$server->getUserSession(), \OC::$server->getUserSession(),
\OC::$server->getRequest(), \OC::$server->getRequest(),
\OC::$server->getTwoFactorAuthManager(),
'principals/' 'principals/'
); );
$principalBackend = new Principal( $principalBackend = new Principal(

View File

@ -42,6 +42,7 @@ $authBackend = new \OCA\DAV\Connector\Sabre\Auth(
\OC::$server->getSession(), \OC::$server->getSession(),
\OC::$server->getUserSession(), \OC::$server->getUserSession(),
\OC::$server->getRequest(), \OC::$server->getRequest(),
\OC::$server->getTwoFactorAuthManager(),
'principals/' 'principals/'
); );
$requestUri = \OC::$server->getRequest()->getRequestUri(); $requestUri = \OC::$server->getRequest()->getRequestUri();

View File

@ -31,9 +31,10 @@ namespace OCA\DAV\Connector\Sabre;
use Exception; use Exception;
use OC\AppFramework\Http\Request; use OC\AppFramework\Http\Request;
use OC\Authentication\TwoFactorAuth\Manager;
use OC\User\Session;
use OCP\IRequest; use OCP\IRequest;
use OCP\ISession; use OCP\ISession;
use OC\User\Session;
use Sabre\DAV\Auth\Backend\AbstractBasic; use Sabre\DAV\Auth\Backend\AbstractBasic;
use Sabre\DAV\Exception\NotAuthenticated; use Sabre\DAV\Exception\NotAuthenticated;
use Sabre\DAV\Exception\ServiceUnavailable; use Sabre\DAV\Exception\ServiceUnavailable;
@ -41,6 +42,8 @@ use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface; use Sabre\HTTP\ResponseInterface;
class Auth extends AbstractBasic { class Auth extends AbstractBasic {
const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND'; const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND';
/** @var ISession */ /** @var ISession */
@ -51,19 +54,24 @@ class Auth extends AbstractBasic {
private $request; private $request;
/** @var string */ /** @var string */
private $currentUser; private $currentUser;
/** @var Manager */
private $twoFactorManager;
/** /**
* @param ISession $session * @param ISession $session
* @param Session $userSession * @param Session $userSession
* @param IRequest $request * @param IRequest $request
* @param Manager $twoFactorManager
* @param string $principalPrefix * @param string $principalPrefix
*/ */
public function __construct(ISession $session, public function __construct(ISession $session,
Session $userSession, Session $userSession,
IRequest $request, IRequest $request,
Manager $twoFactorManager,
$principalPrefix = 'principals/users/') { $principalPrefix = 'principals/users/') {
$this->session = $session; $this->session = $session;
$this->userSession = $userSession; $this->userSession = $userSession;
$this->twoFactorManager = $twoFactorManager;
$this->request = $request; $this->request = $request;
$this->principalPrefix = $principalPrefix; $this->principalPrefix = $principalPrefix;
} }
@ -197,6 +205,9 @@ class Auth extends AbstractBasic {
if($forcedLogout) { if($forcedLogout) {
$this->userSession->logout(); $this->userSession->logout();
} else { } else {
if ($this->twoFactorManager->needsSecondFactor()) {
throw new \Sabre\DAV\Exception\NotAuthenticated('2FA challenge not passed.');
}
if (\OC_User::handleApacheAuth() || if (\OC_User::handleApacheAuth() ||
//Fix for broken webdav clients //Fix for broken webdav clients
($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED))) || ($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED))) ||

View File

@ -25,7 +25,6 @@
namespace OCA\DAV; namespace OCA\DAV;
use OCA\DAV\CalDAV\Schedule\IMipPlugin; use OCA\DAV\CalDAV\Schedule\IMipPlugin;
use OCA\DAV\Connector\FedAuth;
use OCA\DAV\Connector\Sabre\Auth; use OCA\DAV\Connector\Sabre\Auth;
use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin; use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin;
use OCA\DAV\Connector\Sabre\DavAclPlugin; use OCA\DAV\Connector\Sabre\DavAclPlugin;
@ -57,7 +56,8 @@ class Server {
$authBackend = new Auth( $authBackend = new Auth(
\OC::$server->getSession(), \OC::$server->getSession(),
\OC::$server->getUserSession(), \OC::$server->getUserSession(),
\OC::$server->getRequest() \OC::$server->getRequest(),
\OC::$server->getTwoFactorAuthManager()
); );
// Set URL explicitly due to reverse-proxy situations // Set URL explicitly due to reverse-proxy situations

View File

@ -27,11 +27,12 @@
namespace OCA\DAV\Tests\unit\Connector\Sabre; namespace OCA\DAV\Tests\unit\Connector\Sabre;
use OC\Authentication\TwoFactorAuth\Manager;
use OC\User\Session;
use OCP\IRequest; use OCP\IRequest;
use OCP\ISession;
use OCP\IUser; use OCP\IUser;
use Test\TestCase; use Test\TestCase;
use OCP\ISession;
use OC\User\Session;
/** /**
* Class AuthTest * Class AuthTest
@ -48,6 +49,8 @@ class AuthTest extends TestCase {
private $userSession; private $userSession;
/** @var IRequest */ /** @var IRequest */
private $request; private $request;
/** @var Manager */
private $twoFactorManager;
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
@ -57,10 +60,14 @@ class AuthTest extends TestCase {
->disableOriginalConstructor()->getMock(); ->disableOriginalConstructor()->getMock();
$this->request = $this->getMockBuilder('\OCP\IRequest') $this->request = $this->getMockBuilder('\OCP\IRequest')
->disableOriginalConstructor()->getMock(); ->disableOriginalConstructor()->getMock();
$this->twoFactorManager = $this->getMockBuilder('\OC\Authentication\TwoFactorAuth\Manager')
->disableOriginalConstructor()
->getMock();
$this->auth = new \OCA\DAV\Connector\Sabre\Auth( $this->auth = new \OCA\DAV\Connector\Sabre\Auth(
$this->session, $this->session,
$this->userSession, $this->userSession,
$this->request $this->request,
$this->twoFactorManager
); );
} }
@ -295,6 +302,59 @@ class AuthTest extends TestCase {
$this->auth->check($request, $response); $this->auth->check($request, $response);
} }
/**
* @expectedException \Sabre\DAV\Exception\NotAuthenticated
* @expectedExceptionMessage 2FA challenge not passed.
*/
public function testAuthenticateAlreadyLoggedInWithoutTwoFactorChallengePassed() {
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
->disableOriginalConstructor()
->getMock();
$response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
->disableOriginalConstructor()
->getMock();
$this->userSession
->expects($this->any())
->method('isLoggedIn')
->willReturn(true);
$this->request
->expects($this->any())
->method('getMethod')
->willReturn('PROPFIND');
$this->request
->expects($this->any())
->method('isUserAgent')
->with([
'/^Mozilla\/5\.0 \([A-Za-z ]+\) (mirall|csyncoC)\/.*$/',
'/^Mozilla\/5\.0 \(Android\) ownCloud\-android.*$/',
'/^Mozilla\/5\.0 \(iOS\) ownCloud\-iOS.*$/',
])
->willReturn(false);
$this->session
->expects($this->any())
->method('get')
->with('AUTHENTICATED_TO_DAV_BACKEND')
->will($this->returnValue('LoggedInUser'));
$user = $this->getMockBuilder('\OCP\IUser')
->disableOriginalConstructor()
->getMock();
$user->expects($this->any())
->method('getUID')
->will($this->returnValue('LoggedInUser'));
$this->userSession
->expects($this->any())
->method('getUser')
->will($this->returnValue($user));
$this->request
->expects($this->once())
->method('passesCSRFCheck')
->willReturn(true);
$this->twoFactorManager->expects($this->once())
->method('needsSecondFactor')
->will($this->returnValue(true));
$this->auth->check($request, $response);
}
/** /**
* @expectedException \Sabre\DAV\Exception\NotAuthenticated * @expectedException \Sabre\DAV\Exception\NotAuthenticated
* @expectedExceptionMessage CSRF check not passed. * @expectedExceptionMessage CSRF check not passed.