From 8f073a202df6ff0c0ebdb8342c5819b0fad0bbc8 Mon Sep 17 00:00:00 2001 From: Lukas Reschke Date: Wed, 10 Dec 2014 13:18:33 +0100 Subject: [PATCH] Store user_webdavauth users in DB + code cleanup This commit introduces the storing of user_webdavauth users in the database which is a pre-requisite of https://github.com/owncloud/core/issues/12620. Furthermore, I refactored the code and removed deprecated code, as a little gimmick I added unit tests for the backend. --- apps/user_webdavauth/appinfo/app.php | 54 +-- apps/user_webdavauth/appinfo/database.xml | 41 ++ apps/user_webdavauth/appinfo/info.xml | 6 +- apps/user_webdavauth/appinfo/version | 2 +- apps/user_webdavauth/settings.php | 23 +- apps/user_webdavauth/templates/settings.php | 16 +- .../tests/user_webdavauthtest.php | 458 ++++++++++++++++++ apps/user_webdavauth/user_webdavauth.php | 281 +++++++++-- lib/base.php | 2 +- lib/private/httphelper.php | 2 +- lib/private/server.php | 15 +- lib/public/iservercontainer.php | 7 + 12 files changed, 793 insertions(+), 114 deletions(-) create mode 100644 apps/user_webdavauth/appinfo/database.xml create mode 100644 apps/user_webdavauth/tests/user_webdavauthtest.php diff --git a/apps/user_webdavauth/appinfo/app.php b/apps/user_webdavauth/appinfo/app.php index 125f5f406547..04d829c30c2f 100644 --- a/apps/user_webdavauth/appinfo/app.php +++ b/apps/user_webdavauth/appinfo/app.php @@ -1,39 +1,27 @@ . -* -*/ - -require_once OC_App::getAppPath('user_webdavauth').'/user_webdavauth.php'; + * @author Frank Karlitschek + * @copyright 2012 Frank Karlitschek frank@owncloud.org + * @copyright 2014 Lukas Reschke lukas@owncloud.com + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ -OC_APP::registerAdmin('user_webdavauth', 'settings'); +namespace OCA\user_webdavauth\AppInfo; -OC_User::registerBackend("WEBDAVAUTH"); -OC_User::useBackend( "WEBDAVAUTH" ); +use OCA\user_webdavauth\USER_WEBDAVAUTH; +use OCP\Util; -OCP\Util::addTranslations('user_webdavauth'); - -// add settings page to navigation -$entry = array( - 'id' => "user_webdavauth_settings", - 'order'=>1, - 'href' => OC_Helper::linkTo( "user_webdavauth", "settings.php" ), - 'name' => 'WEBDAVAUTH' +$userBackend = new USER_WEBDAVAUTH( + \OC::$server->getConfig(), + \OC::$server->getDb(), + \OC::$server->getHTTPHelper(), + \OC::$server->getLogger(), + \OC::$server->getServerRoot() ); +\OC_User::useBackend($userBackend); + +Util::addTranslations('user_webdavauth'); +\OC_APP::registerAdmin('user_webdavauth', 'settings'); diff --git a/apps/user_webdavauth/appinfo/database.xml b/apps/user_webdavauth/appinfo/database.xml new file mode 100644 index 000000000000..d862fdb545e6 --- /dev/null +++ b/apps/user_webdavauth/appinfo/database.xml @@ -0,0 +1,41 @@ + + + + *dbname* + true + false + utf8 + + + + *dbprefix*webdav_user_mapping + + + + + uid + text + true + 255 + + + + displayname + text + false + 255 + + + + webdav_uid + true + + uid + + + + + +
+ +
diff --git a/apps/user_webdavauth/appinfo/info.xml b/apps/user_webdavauth/appinfo/info.xml index abbf79131b5a..249286dbdffd 100644 --- a/apps/user_webdavauth/appinfo/info.xml +++ b/apps/user_webdavauth/appinfo/info.xml @@ -2,12 +2,12 @@ user_webdavauth WebDAV user backend - Authenticate users by a WebDAV call. You can use any WebDAV server, ownCloud server or other webserver to authenticate. It should return http 200 for right credentials and http 401 for wrong ones. + Authenticate users by a WebDAV call. You can use any WebDAV server, ownCloud server or other web server to authenticate. It should return a HTTP 2xx status code for correct credentials and a 4xx or 5xx for invalid ones. - Attention: This app is not compatible with the LDAP user and group backend. This app is not the webdav interface of ownCloud, if you don't understand what it does then do not enable it. + Attention: This app is not the WebDAV interface of ownCloud, if you don't understand what it does then do not enable it. AGPL Frank Karlitschek - 4.93 + 7.0 true diff --git a/apps/user_webdavauth/appinfo/version b/apps/user_webdavauth/appinfo/version index 238afc2b2796..4e0321ef5823 100644 --- a/apps/user_webdavauth/appinfo/version +++ b/apps/user_webdavauth/appinfo/version @@ -1 +1 @@ -1.1.0.1 +1.2.0.0 \ No newline at end of file diff --git a/apps/user_webdavauth/settings.php b/apps/user_webdavauth/settings.php index ae9cb7e4c921..900fbf687e23 100644 --- a/apps/user_webdavauth/settings.php +++ b/apps/user_webdavauth/settings.php @@ -1,24 +1,13 @@ . - * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ OC_Util::checkAdminUser(); @@ -28,12 +17,12 @@ OCP\JSON::callCheck(); if(isset($_POST['webdav_url'])) { - OC_CONFIG::setValue('user_webdavauth_url', strip_tags($_POST['webdav_url'])); + \OC::$server->getConfig()->setSystemValue('user_webdavauth_url', $_POST['webdav_url']); } } // fill template -$tmpl = new OC_Template( 'user_webdavauth', 'settings'); -$tmpl->assign( 'webdav_url', OC_Config::getValue( "user_webdavauth_url" )); +$tmpl = new OC_Template('user_webdavauth', 'settings'); +$tmpl->assign('webdav_url', \OC::$server->getConfig()->getSystemValue('user_webdavauth_url')); return $tmpl->fetchPage(); diff --git a/apps/user_webdavauth/templates/settings.php b/apps/user_webdavauth/templates/settings.php index a87c0ad159a8..181b2e42320b 100644 --- a/apps/user_webdavauth/templates/settings.php +++ b/apps/user_webdavauth/templates/settings.php @@ -1,7 +1,15 @@ +

t('WebDAV Authentication'));?>

-

- - -
t('The user credentials will be sent to this address. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials.')); ?> +

+ + + +
+ t('The user credentials will be sent to this address. This plugin checks the response and will interpret the HTTP status codes 2xx and 403 as valid credentials, and all other responses as invalid credentials.')); ?> +

diff --git a/apps/user_webdavauth/tests/user_webdavauthtest.php b/apps/user_webdavauth/tests/user_webdavauthtest.php new file mode 100644 index 000000000000..6839f3628c3c --- /dev/null +++ b/apps/user_webdavauth/tests/user_webdavauthtest.php @@ -0,0 +1,458 @@ +config = $this->getMockBuilder('\OCP\IConfig') + ->disableOriginalConstructor()->getMock(); + $this->db = $this->getMockBuilder('\OCP\IDb') + ->disableOriginalConstructor()->getMock(); + $this->httpHelper = $this->getMockBuilder('\OC\HTTPHelper') + ->disableOriginalConstructor()->getMock(); + $this->logger = $this->getMockBuilder('\OCP\ILogger') + ->disableOriginalConstructor()->getMock(); + + $this->userWebDavAuth = new USER_WEBDAVAUTH( + $this->config, + $this->db, + $this->httpHelper, + $this->logger, + '/var/www/owncloud' + ); + } + + public function urlProvider() + { + return array( + array(false, 'file://fo', 'user', 'password'), + array('http://lukas:test@dav.owncloud.org/testpoint/', 'http://dav.owncloud.org/testpoint/', 'lukas', 'test'), + array('https://lukas:test@dav.owncloud.org/testpoint/', 'HTTPS://DAV.OWNCLOUD.org/testpoint/', 'lukas', 'test'), + array('https://CrazyUserN%40me%2F%2A%2A%2A%2A%2F_%C3%A0a%C2%A3:CrazyP%40ssword%2F%2A%2A%2A%2A%2F_%C3%A0a%C2%A3@dav.owncloud.org/testpoint/', 'HTTPS://DAV.OWNCLOUD.org/testpoint/', 'CrazyUserN@me/****/_àa£', 'CrazyP@ssword/****/_àa£'), + ); + } + + /** + * @dataProvider urlProvider + * @param string $expected + * @param string $endpointUrl + * @param string $uid + * @param string $password + */ + public function testCreateAuthUrl($expected, $endpointUrl, $uid, $password) { + $this->assertSame($expected, \Test_Helper::invokePrivate($this->userWebDavAuth, 'createAuthUrl', [$endpointUrl, $uid, $password])); + } + + public function testCheckPasswordNotExistingUser() { + /** @var USER_WEBDAVAUTH $webDavAuth */ + $webDavAuth = $this->getMockBuilder('\OCA\user_webdavauth\USER_WEBDAVAUTH') + ->setConstructorArgs([ + $this->config, + $this->db, + $this->httpHelper, + $this->logger, + '/var/www/owncloud'] + ) + ->setMethods(['userExists']) + ->getMock(); + $webDavAuth->expects($this->once()) + ->method('userExists') + ->with('lukas') + ->will($this->returnValue(false)); + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('user_webdavauth_url') + ->will($this->returnValue('http://dav.owncloud.org/testpoint/')); + $this->httpHelper->expects($this->once()) + ->method('getHeaders') + ->with('http://lukas:test1234@dav.owncloud.org/testpoint/') + ->will($this->returnValue(['HTTP/1.1 200 OK'])); + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with('INSERT INTO `*PREFIX*webdav_user_mapping` (`uid`) VALUES (?)') + ->will($this->returnValue($this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock())); + + $this->assertEquals('lukas', $webDavAuth->checkPassword('lukas', 'test1234')); + } + + public function testCheckPasswordCorrectExistingUser() { + /** @var USER_WEBDAVAUTH $webDavAuth */ + $webDavAuth = $this->getMockBuilder('\OCA\user_webdavauth\USER_WEBDAVAUTH') + ->setConstructorArgs([ + $this->config, + $this->db, + $this->httpHelper, + $this->logger, + '/var/www/owncloud'] + ) + ->setMethods(['userExists']) + ->getMock(); + $webDavAuth->expects($this->once()) + ->method('userExists') + ->with('lukas') + ->will($this->returnValue(true)); + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('user_webdavauth_url') + ->will($this->returnValue('http://dav.owncloud.org/testpoint/')); + $this->httpHelper->expects($this->once()) + ->method('getHeaders') + ->with('http://lukas:test1234@dav.owncloud.org/testpoint/') + ->will($this->returnValue(['HTTP/1.1 200 OK'])); + + $this->assertEquals('lukas', $webDavAuth->checkPassword('lukas', 'test1234')); + } + + public function testCheckPasswordIncorrect() { + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('user_webdavauth_url') + ->will($this->returnValue('http://dav.owncloud.org/testpoint/')); + $this->httpHelper->expects($this->once()) + ->method('getHeaders') + ->with('http://User%40Foobar.com%2F..%2F:%2F..%2FMy%40Password123%2F._%C3%A5%C3%A9@dav.owncloud.org/testpoint/') + ->will($this->returnValue(['HTTP/1.1 403 Forbidden'])); + + $this->assertEquals(false, $this->userWebDavAuth->checkPassword('User@Foobar.com/../', '/../My@Password123/._åé')); + } + + public function testGetHomeExistingUser() { + /** @var USER_WEBDAVAUTH $webDavAuth */ + $webDavAuth = $this->getMockBuilder('\OCA\user_webdavauth\USER_WEBDAVAUTH') + ->setConstructorArgs([ + $this->config, $this->db, + $this->httpHelper, + $this->logger, + '/var/www/owncloud'] + ) + ->setMethods(['userExists']) + ->getMock(); + $webDavAuth->expects($this->once()) + ->method('userExists') + ->with('lukas') + ->will($this->returnValue(true)); + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('datadirectory', '/var/www/owncloud/data') + ->will($this->returnArgument(1)); + + $this->assertSame('/var/www/owncloud/data/lukas', $webDavAuth->getHome('lukas')); + } + + public function testGetHomeNotExistingUser() { + /** @var USER_WEBDAVAUTH $webDavAuth */ + $webDavAuth = $this->getMockBuilder('\OCA\user_webdavauth\USER_WEBDAVAUTH') + ->setConstructorArgs([ + $this->config, $this->db, + $this->httpHelper, + $this->logger, + '/var/www/owncloud'] + ) + ->setMethods(['userExists']) + ->getMock(); + $webDavAuth->expects($this->once()) + ->method('userExists') + ->with('NotExisting') + ->will($this->returnValue(false)); + + $this->assertSame(false, $webDavAuth->getHome('NotExisting')); + } + + public function testSetDisplayNameExistingUser() { + /** @var USER_WEBDAVAUTH $webDavAuth */ + $webDavAuth = $this->getMockBuilder('\OCA\user_webdavauth\USER_WEBDAVAUTH') + ->setConstructorArgs([ + $this->config, $this->db, + $this->httpHelper, + $this->logger, + '/var/www/owncloud'] + ) + ->setMethods(['userExists']) + ->getMock(); + $webDavAuth->expects($this->once()) + ->method('userExists') + ->with('lukas') + ->will($this->returnValue(true)); + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->once()) + ->method('execute'); + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with('UPDATE `*PREFIX*webdav_user_mapping` SET `displayname` = ? WHERE LOWER(`uid`) = LOWER(?)') + ->will($this->returnValue($query)); + + $this->assertSame(true, $webDavAuth->setDisplayName('lukas', 'Lukas Reschke')); + } + + public function testSetDisplayNameNotExistingUser() { + /** @var USER_WEBDAVAUTH $webDavAuth */ + $webDavAuth = $this->getMockBuilder('\OCA\user_webdavauth\USER_WEBDAVAUTH') + ->setConstructorArgs([ + $this->config, $this->db, + $this->httpHelper, + $this->logger, + '/var/www/owncloud'] + ) + ->setMethods(['userExists']) + ->getMock(); + $webDavAuth->expects($this->once()) + ->method('userExists') + ->with('NotExisting') + ->will($this->returnValue(false)); + + $this->assertSame(false, $webDavAuth->setDisplayName('NotExisting', 'DisplaynameToSet')); + } + + public function testCountUsers() { + $execute = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $execute->expects($this->once()) + ->method('fetchOne') + ->will($this->returnValue(5)); + + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->once()) + ->method('execute') + ->will($this->returnValue($execute)); + + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with('SELECT COUNT(*) FROM `*PREFIX*webdav_user_mapping`') + ->will($this->returnValue($query)); + + $this->assertSame(5, $this->userWebDavAuth->countUsers()); + } + + public function testDeleteUser() { + $this->assertSame(false, $this->userWebDavAuth->deleteUser('')); + } + + public function testGetUsersWithParameter() { + $execute = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $execute->expects($this->exactly(3)) + ->method('fetchRow') + ->will( + $this->onConsecutiveCalls( + ['uid' => 'frank'], + ['uid' => 'lukas'] + ) + ); + + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->once()) + ->method('execute') + ->will($this->returnValue($execute)); + + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with( + $this->equalTo( + 'SELECT `uid` FROM `*PREFIX*webdav_user_mapping`' + . ' WHERE LOWER(`uid`) LIKE LOWER(?) ORDER BY `uid` ASC' + ), + 10, + 500 + ) + ->will($this->returnValue($query)); + + $this->assertSame(['frank', 'lukas'], $this->userWebDavAuth->getUsers('foo', 10, 500)); + } + + public function testGetUsersWithoutParameter() { + $execute = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $execute->expects($this->exactly(3)) + ->method('fetchRow') + ->will( + $this->onConsecutiveCalls( + ['uid' => 'frank'], + ['uid' => 'lukas'] + ) + ); + + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->once()) + ->method('execute') + ->will($this->returnValue($execute)); + + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with( + $this->equalTo( + 'SELECT `uid` FROM `*PREFIX*webdav_user_mapping`' + . ' WHERE LOWER(`uid`) LIKE LOWER(?) ORDER BY `uid` ASC' + ) + ) + ->will($this->returnValue($query)); + + $this->assertSame(['frank', 'lukas'], $this->userWebDavAuth->getUsers()); + } + + public function testUserExistsExisting() { + $execute = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $execute->expects($this->once()) + ->method('fetchOne') + ->will($this->returnValue('1')); + + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->once()) + ->method('execute') + ->will($this->returnValue($execute)); + + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with('SELECT COUNT(*) FROM `*PREFIX*webdav_user_mapping` WHERE LOWER(`uid`) = LOWER(?)') + ->will($this->returnValue($query)); + + $this->assertSame(true, $this->userWebDavAuth->userExists('ExistingUser')); + } + + + public function testUserExistsNotExisting() { + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->once()) + ->method('execute') + ->will($this->returnValue($query)); + + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with('SELECT COUNT(*) FROM `*PREFIX*webdav_user_mapping` WHERE LOWER(`uid`) = LOWER(?)') + ->will($this->returnValue($query)); + + $this->assertSame(false, $this->userWebDavAuth->userExists('NotExistingUser')); + } + + public function testGetDisplayName() { + $execute = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $execute->expects($this->once()) + ->method('fetchOne') + ->will($this->returnValue('Lukas Reschke')); + + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->once()) + ->method('execute') + ->will($this->returnValue($execute)); + + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with('SELECT `displayname` FROM `*PREFIX*webdav_user_mapping` WHERE LOWER(`uid`) = LOWER(?)') + ->will($this->returnValue($query)); + + $this->assertSame('Lukas Reschke', $this->userWebDavAuth->getDisplayName('lukas')); + } + + public function testGetDisplayNamesWithoutParameter() { + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->exactly(4)) + ->method('fetchRow') + ->will($this->onConsecutiveCalls( + ['uid' => 'Foo', 'displayname' => 'Mr. Foo'], + ['uid' => 'Lukas', 'displayname' => 'Reschke Lukas'], + ['uid' => 'frank', 'displayname' => 'Frank Karlitschek'] + )); + $query->expects($this->once()) + ->method('execute') + ->will($this->returnValue($query)); + + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with( + $this->equalTo( + 'SELECT `uid`, `displayname` FROM `*PREFIX*webdav_user_mapping`' + . ' WHERE LOWER(`displayname`) LIKE LOWER(?) OR ' + . 'LOWER(`uid`) LIKE LOWER(?) ORDER BY `uid` ASC' + ), + null, + null + ) + ->will($this->returnValue($query)); + + + $this->assertSame([ + 'Foo' => 'Mr. Foo', + 'Lukas' => 'Reschke Lukas', + 'frank' => 'Frank Karlitschek' + ], $this->userWebDavAuth->getDisplayNames()); + } + + public function testGetDisplayNamesWithParameter() { + $query = $this->getMockBuilder('\OC_DB_StatementWrapper') + ->disableOriginalConstructor()->getMock(); + $query->expects($this->exactly(2)) + ->method('fetchRow') + ->will($this->onConsecutiveCalls( + ['uid' => 'Foo', 'displayname' => 'Mr. Foo'] + )); + $query->expects($this->once()) + ->method('execute') + ->will($this->returnValue($query)); + + $this->db->expects($this->once()) + ->method('prepareQuery') + ->with( + $this->equalTo( + 'SELECT `uid`, `displayname` FROM `*PREFIX*webdav_user_mapping`' + . ' WHERE LOWER(`displayname`) LIKE LOWER(?) OR ' + . 'LOWER(`uid`) LIKE LOWER(?) ORDER BY `uid` ASC' + ), + 10, + 15 + ) + ->will($this->returnValue($query)); + + + $this->assertSame([ + 'Foo' => 'Mr. Foo', + ], $this->userWebDavAuth->getDisplayNames('Foo', 10, 15)); + } + + public function testHasUserListings() { + $this->assertSame(true, $this->userWebDavAuth->hasUserListings()); + } + +} diff --git a/apps/user_webdavauth/user_webdavauth.php b/apps/user_webdavauth/user_webdavauth.php index 86e5b916f3d2..ea40ad827c57 100644 --- a/apps/user_webdavauth/user_webdavauth.php +++ b/apps/user_webdavauth/user_webdavauth.php @@ -1,89 +1,264 @@ . - * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ -class OC_USER_WEBDAVAUTH extends OC_User_Backend { - protected $webdavauth_url; +namespace OCA\user_webdavauth; - public function __construct() { - $this->webdavauth_url = OC_Config::getValue( "user_webdavauth_url" ); - } +use OC\HTTPHelper; +use OCP\IConfig; +use OCP\IDb; +use OCP\ILogger; - public function deleteUser($uid) { - // Can't delete user - OC_Log::write('OC_USER_WEBDAVAUTH', 'Not possible to delete users from web frontend using WebDAV user backend', 3); - return false; +class USER_WEBDAVAUTH implements \OCP\UserInterface { + /** @var string */ + private $tableName = '*PREFIX*webdav_user_mapping'; + /** @var IConfig */ + private $config; + /** @var IDb */ + private $db; + /** @var HTTPHelper */ + private $httpHelper; + /** @var ILogger */ + private $logger; + /** @var string */ + private $serverRoot; + + /** + * @param IConfig $config + * @param IDb $db + * @param HTTPHelper $httpHelper + * @param ILogger $logger + * @param $serverRoot + */ + public function __construct(IConfig $config, + IDb $db, + HTTPHelper $httpHelper, + ILogger $logger, + $serverRoot) { + $this->config = $config; + $this->db = $db; + $this->httpHelper = $httpHelper; + $this->logger = $logger; + $this->serverRoot = $serverRoot; } - public function setPassword ( $uid, $password ) { - // We can't change user password - OC_Log::write('OC_USER_WEBDAVAUTH', 'Not possible to change password for users from web frontend using WebDAV user backend', 3); - return false; + /** + * Check if backend implements actions + * + * @param int $actions bitwise-or'ed actions + * @return boolean + */ + public function implementsActions($actions) { + return (bool)((\OC_User_Backend::CHECK_PASSWORD + | \OC_User_Backend::GET_DISPLAYNAME + | \OC_User_Backend::SET_DISPLAYNAME + | \OC_User_Backend::COUNT_USERS + | \OC_User_Backend::GET_HOME) + & $actions); } - public function checkPassword( $uid, $password ) { - $arr = explode('://', $this->webdavauth_url, 2); - if( ! isset($arr) OR count($arr) !== 2) { - OC_Log::write('OC_USER_WEBDAVAUTH', 'Invalid Url: "'.$this->webdavauth_url.'" ', 3); + /** + * Builds the auth url from the specified endpoint + * + * @param string $endPointUrl + * @param string $uid + * @param string $password + * @return string|false + */ + private function createAuthUrl($endPointUrl, $uid, $password) { + $arr = explode('://', strtolower($endPointUrl), 2); + if(empty($arr) || count($arr) !== 2) { return false; } list($webdavauth_protocol, $webdavauth_url_path) = $arr; - $url= $webdavauth_protocol.'://'.urlencode($uid).':'.urlencode($password).'@'.$webdavauth_url_path; - $headers = get_headers($url); - if($headers==false) { - OC_Log::write('OC_USER_WEBDAVAUTH', 'Not possible to connect to WebDAV Url: "'.$webdavauth_protocol.'://'.$webdavauth_url_path.'" ', 3); + + if($webdavauth_protocol !== 'http' && $webdavauth_protocol !== 'https') { return false; + } + return $webdavauth_protocol.'://'.urlencode($uid).':'.urlencode($password).'@'.$webdavauth_url_path; + } + + /** + * Check if the password is correct + * + * @param string $uid The username + * @param string $password The password + * @return boolean|false + */ + public function checkPassword($uid, $password) { + $endPointUrl = $this->config->getSystemValue('user_webdavauth_url'); + $headers = $this->httpHelper->getHeaders($this->createAuthUrl($endPointUrl, $uid, $password)); + if($headers === false) { + $this->logger->error('Not possible to connect to WebDAV endpoint: ' . $endPointUrl, + array('app' => 'user_webdavauth')); + return false; } - $returncode= substr($headers[0], 9, 3); - if(substr($returncode, 0, 1) === '2') { + $returnCode = substr($headers[0], 9, 3); + if(substr($returnCode, 0, 1) === '2') { + if(!$this->userExists($uid)) { + $query = $this->db->prepareQuery('INSERT INTO `'.$this->tableName.'` (`uid`) VALUES (?)'); + $query->bindValue(1, $uid); + $query->execute(); + } + return $uid; - } else { - return false; } + return false; } - /* - * we don´t know if a user exists without the password. so we have to return true all the time - */ - public function userExists( $uid ){ - return true; + /** + * get the user's home directory + * + * @param string $uid the username + * @return string|false + */ + public function getHome($uid) { + if ($this->userExists($uid)) { + return $this->config->getSystemValue('datadirectory', $this->serverRoot . '/data') . '/' . $uid; + } + + return false; } /** + * Set display name + * + * @param string $uid The username + * @param string $displayName The new display name * @return bool */ - public function hasUserListings() { + public function setDisplayName($uid, $displayName) { + if ($this->userExists($uid)) { + $query = $this->db->prepareQuery('UPDATE `'.$this->tableName.'` ' . + 'SET `displayname` = ? WHERE LOWER(`uid`) = LOWER(?)'); + $query->bindValue(1, $displayName); + $query->bindValue(2, $uid); + $query->execute(); + return true; + } + return false; } - /* - * we don´t know the users so all we can do it return an empty array here - */ - public function getUsers($search = '', $limit = 10, $offset = 0) { - $returnArray = array(); + /** + * Counts the users + * + * @return int + */ + public function countUsers() { + $query = $this->db->prepareQuery('SELECT COUNT(*) FROM `'.$this->tableName.'`'); + $result = $query->execute(); + return $result->fetchOne(); + } + + /** + * delete a user - not implemented within user_webdavauth + * FIXME: That should be an optional action, but unfortunately it isn't. - Thus we always return false. + * + * @param string $uid The username of the user to delete + * @return bool + */ + public function deleteUser($uid) { + return false; + } + + /** + * Get a list of all users + * + * @param string $search + * @param null $limit + * @param null $offset + * @return array All UIDs + * @throws \OC\DatabaseException + */ + public function getUsers($search = '', $limit = null, $offset = null) { + $users = array(); + + $query = $this->db->prepareQuery('SELECT `uid` FROM `'.$this->tableName.'`' + . ' WHERE LOWER(`uid`) LIKE LOWER(?) ORDER BY `uid` ASC', $limit, $offset); + $query->bindValue(1, '%'.$search.'%'); + $query->bindValue(2, '%'.$search.'%'); + $result = $query->execute(); + while($row = $result->fetchRow()) { + $users[] = $row['uid']; + } + return $users; + } + + /** + * check if a user exists + * + * @param string $uid the username + * @return boolean + */ + public function userExists($uid) { + $query = $this->db->prepareQuery('SELECT COUNT(*) FROM `'.$this->tableName.'`' + . ' WHERE LOWER(`uid`) = LOWER(?)'); + $query->bindValue(1, $uid); + $result = $query->execute(); + $existing = $result->fetchOne(); + if($existing === '1') { + return true; + } - return $returnArray; + return false; + } + + /** + * get display name of the user + * + * @param string $uid user ID of the user + * @return string display name + */ + public function getDisplayName($uid) { + $query = $this->db->prepareQuery('SELECT `displayname` FROM `'.$this->tableName.'`' + . ' WHERE LOWER(`uid`) = LOWER(?)'); + $query->bindValue(1, $uid); + $result = $query->execute(); + return $result->fetchOne(); + } + + /** + * Get a list of all display names + * + * @param string $search + * @param null $limit + * @param null $offset + * @return array Array of displaynames (value) and the corresponding UIDs (key) + * @throws \OC\DatabaseException + */ + public function getDisplayNames($search = '', $limit = null, $offset = null) { + $users = array(); + + $query = $this->db->prepareQuery('SELECT `uid`, `displayname` FROM `'.$this->tableName.'`' + . ' WHERE LOWER(`displayname`) LIKE LOWER(?) OR ' + . 'LOWER(`uid`) LIKE LOWER(?) ORDER BY `uid` ASC', $limit, $offset); + $query->bindValue(1, '%'.$search.'%'); + $query->bindValue(2, '%'.$search.'%'); + $result = $query->execute(); + while($row = $result->fetchRow()) { + $users[$row['uid']] = $row['displayname']; + } + + return $users; + } + + /** + * Check if a user list is available or not + * + * @return boolean if users can be listed or not + */ + public function hasUserListings() { + return true; } } diff --git a/lib/base.php b/lib/base.php index af2474c7d763..ddb8bfe95336 100644 --- a/lib/base.php +++ b/lib/base.php @@ -474,7 +474,7 @@ public static function init() { } // setup the basic server - self::$server = new \OC\Server(\OC::$WEBROOT); + self::$server = new \OC\Server(\OC::$WEBROOT, \OC::$SERVERROOT); \OC::$server->getEventLogger()->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd); \OC::$server->getEventLogger()->start('boot', 'Initialize'); diff --git a/lib/private/httphelper.php b/lib/private/httphelper.php index 846825dee8de..1897f4c57093 100644 --- a/lib/private/httphelper.php +++ b/lib/private/httphelper.php @@ -137,7 +137,7 @@ public function getUrlContent($url) { /** * Returns the response headers of a HTTP URL without following redirects * @param string $location Needs to be a HTTPS or HTTP URL - * @return array + * @return array|false an indexed or associative array with the headers, or false on failure. */ public function getHeaders($location) { stream_context_set_default($this->getDefaultContextArray()); diff --git a/lib/private/server.php b/lib/private/server.php index e0105506970e..2fefd73b9266 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -32,12 +32,16 @@ class Server extends SimpleContainer implements IServerContainer { /** @var string */ private $webRoot; + /** @var string */ + private $serverRoot; /** * @param string $webRoot + * @param string $serverRoot */ - function __construct($webRoot) { + function __construct($webRoot, $serverRoot) { $this->webRoot = $webRoot; + $this->serverRoot = $serverRoot; $this->registerService('ContactsManager', function ($c) { return new ContactsManager(); @@ -692,6 +696,15 @@ function getWebRoot() { return $this->webRoot; } + /** + * Get the server root directory + * + * @return string + */ + function getServerRoot() { + return $this->serverRoot; + } + /** * Get the timezone of the current user, based on his session information and config data * diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 657c9be423bf..9df5b57989fd 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -306,6 +306,13 @@ function getAppManager(); */ function getWebRoot(); + /** + * Get the server root directory + * + * @return string + */ + function getServerRoot(); + /** * @return \OCP\Files\Config\IMountProviderCollection */