diff options
m--------- | 3rdparty | 0 | ||||
-rw-r--r-- | apps/files_trashbin/lib/helper.php | 2 | ||||
-rw-r--r-- | apps/user_ldap/appinfo/update.php | 26 | ||||
-rw-r--r-- | apps/user_ldap/tests/integration/lib/integrationtestuserhome.php | 159 | ||||
-rw-r--r-- | apps/user_ldap/user_ldap.php | 7 | ||||
-rw-r--r-- | lib/private/api.php | 109 | ||||
-rw-r--r-- | lib/private/ocs.php | 145 | ||||
-rw-r--r-- | lib/private/ocs/exception.php | 34 | ||||
-rw-r--r-- | lib/public/appframework/http/ocsresponse.php | 28 | ||||
-rw-r--r-- | lib/public/appframework/ocscontroller.php | 11 | ||||
-rw-r--r-- | ocs/v1.php | 2 | ||||
-rw-r--r-- | ocs/v2.php | 22 | ||||
-rw-r--r-- | settings/application.php | 3 | ||||
-rw-r--r-- | settings/controller/certificatecontroller.php | 34 | ||||
-rw-r--r-- | settings/css/settings.css | 6 | ||||
-rw-r--r-- | settings/personal.php | 18 | ||||
-rw-r--r-- | settings/templates/admin.php | 13 | ||||
-rw-r--r-- | settings/templates/personal.php | 2 | ||||
-rw-r--r-- | tests/lib/appframework/controller/OCSControllerTest.php | 12 | ||||
-rw-r--r-- | tests/lib/appframework/http/OCSResponseTest.php | 5 | ||||
-rw-r--r-- | tests/ocs/response.php | 42 | ||||
-rw-r--r-- | tests/settings/controller/CertificateControllerTest.php | 25 |
22 files changed, 487 insertions, 218 deletions
diff --git a/3rdparty b/3rdparty -Subproject 0590498b38aa0c760e2ad7af4fbd19787d62ed4 +Subproject b94f7d38f6e13825fd34c7113827d3c369a689a diff --git a/apps/files_trashbin/lib/helper.php b/apps/files_trashbin/lib/helper.php index 42412d5d4c9..f51185712a9 100644 --- a/apps/files_trashbin/lib/helper.php +++ b/apps/files_trashbin/lib/helper.php @@ -83,7 +83,7 @@ class Helper $i = array( 'name' => $id, 'mtime' => $timestamp, - 'mimetype' => \OC_Helper::getFileNameMimeType($id), + 'mimetype' => $view->is_dir($dir . '/' . $entryName) ? 'httpd/unix-directory' : \OC_Helper::getFileNameMimeType($id), 'type' => $view->is_dir($dir . '/' . $entryName) ? 'dir' : 'file', 'directory' => ($dir === '/') ? '' : $dir, ); diff --git a/apps/user_ldap/appinfo/update.php b/apps/user_ldap/appinfo/update.php new file mode 100644 index 00000000000..b904bce072e --- /dev/null +++ b/apps/user_ldap/appinfo/update.php @@ -0,0 +1,26 @@ +<?php +/** + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2015, 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/> + * + */ + +$installedVersion = \OC::$server->getConfig()->getAppValue('user_ldap', 'installed_version'); + +if (version_compare($installedVersion, '0.6.1', '<')) { + \OC::$server->getConfig()->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', false); +} diff --git a/apps/user_ldap/tests/integration/lib/integrationtestuserhome.php b/apps/user_ldap/tests/integration/lib/integrationtestuserhome.php new file mode 100644 index 00000000000..f34fca81c2d --- /dev/null +++ b/apps/user_ldap/tests/integration/lib/integrationtestuserhome.php @@ -0,0 +1,159 @@ +<?php +/** + * Created by PhpStorm. + * User: blizzz + * Date: 06.08.15 + * Time: 08:19 + */ + +namespace OCA\user_ldap\tests\integration\lib; + +use OCA\user_ldap\lib\user\Manager as LDAPUserManager; +use OCA\user_ldap\tests\integration\AbstractIntegrationTest; +use OCA\User_LDAP\Mapping\UserMapping; +use OCA\user_ldap\USER_LDAP; + +require_once __DIR__ . '/../../../../../lib/base.php'; + +class IntegrationTestUserHome extends AbstractIntegrationTest { + /** @var UserMapping */ + protected $mapping; + + /** @var USER_LDAP */ + protected $backend; + + /** + * prepares the LDAP environment and sets up a test configuration for + * the LDAP backend. + */ + public function init() { + require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); + parent::init(); + + $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); + $this->mapping->clear(); + $this->access->setUserMapper($this->mapping); + $this->backend = new \OCA\user_ldap\USER_LDAP($this->access, \OC::$server->getConfig()); + } + + /** + * sets up the LDAP configuration to be used for the test + */ + protected function initConnection() { + parent::initConnection(); + $this->connection->setConfiguration([ + 'homeFolderNamingRule' => 'homeDirectory', + ]); + } + + /** + * initializes an LDAP user manager instance + * @return LDAPUserManager + */ + protected function initUserManager() { + $this->userManager = new LDAPUserManager( + \OC::$server->getConfig(), + new \OCA\user_ldap\lib\FilesystemHelper(), + new \OCA\user_ldap\lib\LogWrapper(), + \OC::$server->getAvatarManager(), + new \OCP\Image(), + \OC::$server->getDatabaseConnection() + ); + } + + /** + * homeDirectory on LDAP is empty. Return values of getHome should be + * identical to user name, following ownCloud default. + * + * @return bool + */ + protected function case1() { + \OC::$server->getConfig()->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', false); + $userManager = \oc::$server->getUserManager(); + $userManager->clearBackends(); + $userManager->registerBackend($this->backend); + $users = $userManager->search('', 5, 0); + + foreach($users as $user) { + $home = $user->getHome(); + $uid = $user->getUID(); + $posFound = strpos($home, '/' . $uid); + $posExpected = strlen($home) - (strlen($uid) + 1); + if($posFound === false || $posFound !== $posExpected) { + print('"' . $user->getUID() . '" was not found in "' . $home . '" or does not end with it.' . PHP_EOL); + return false; + } + } + + return true; + } + + /** + * homeDirectory on LDAP is empty. Having the attributes set is enforced. + * + * @return bool + */ + protected function case2() { + \OC::$server->getConfig()->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', true); + $userManager = \oc::$server->getUserManager(); + // clearing backends is critical, otherwise the userManager will have + // the user objects cached and the value from case1 returned + $userManager->clearBackends(); + $userManager->registerBackend($this->backend); + $users = $userManager->search('', 5, 0); + + try { + foreach ($users as $user) { + $user->getHome(); + print('User home was retrieved without throwing an Exception!' . PHP_EOL); + return false; + } + } catch (\Exception $e) { + if(strpos($e->getMessage(), 'Home dir attribute') === 0) { + return true; + } + } + + return false; + } + + /** + * homeDirectory on LDAP is set to "attr:" which is effectively empty. + * Return values of getHome should be ownCloud default. + * + * @return bool + */ + protected function case3() { + \OC::$server->getConfig()->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', true); + $this->connection->setConfiguration([ + 'homeFolderNamingRule' => 'attr:', + ]); + $userManager = \oc::$server->getUserManager(); + $userManager->clearBackends(); + $userManager->registerBackend($this->backend); + $users = $userManager->search('', 5, 0); + + try { + foreach ($users as $user) { + $home = $user->getHome(); + $uid = $user->getUID(); + $posFound = strpos($home, '/' . $uid); + $posExpected = strlen($home) - (strlen($uid) + 1); + if ($posFound === false || $posFound !== $posExpected) { + print('"' . $user->getUID() . '" was not found in "' . $home . '" or does not end with it.' . PHP_EOL); + return false; + } + } + } catch (\Exception $e) { + print("Unexpected Exception: " . $e->getMessage() . PHP_EOL); + return false; + } + + return true; + } +} + +require_once(__DIR__ . '/../setup-scripts/config.php'); +$test = new IntegrationTestUserHome($host, $port, $adn, $apwd, $bdn); +$test->init(); +$test->run(); diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index caff30a0e60..a2f4b4ee9e5 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -266,7 +266,8 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn if($this->access->connection->isCached($cacheKey)) { return $this->access->connection->getFromCache($cacheKey); } - if(strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0) { + if(strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0 && + $this->access->connection->homeFolderNamingRule !== 'attr:') { $attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:')); $homedir = $this->access->readAttribute( $this->access->username2dn($uid), $attr); @@ -293,6 +294,10 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn //TODO: if home directory changes, the old one needs to be removed. return $homedir; } + if($this->ocConfig->getAppValue('user_ldap', 'enforce_home_folder_naming_rule', true)) { + // a naming rule attribute is defined, but it doesn't exist for that LDAP user + throw new \Exception('Home dir attribute can\'t be read from LDAP for uid: ' . $uid); + } } //false will apply default behaviour as defined and done by OC_User diff --git a/lib/private/api.php b/lib/private/api.php index 8e483b7efe9..6823a19881f 100644 --- a/lib/private/api.php +++ b/lib/private/api.php @@ -1,4 +1,7 @@ <?php +use OCP\API; +use OCP\AppFramework\Http; + /** * @author Bart Visscher <bartv@thisnet.nl> * @author Bernhard Posselt <dev@bernhard-posselt.com> @@ -82,7 +85,7 @@ class OC_API { * @param array $requirements */ public static function register($method, $url, $action, $app, - $authLevel = \OCP\API::USER_AUTH, + $authLevel = API::USER_AUTH, $defaults = array(), $requirements = array()) { $name = strtolower($method).$url; @@ -123,7 +126,7 @@ class OC_API { if(!self::isAuthorised($action)) { $responses[] = array( 'app' => $action['app'], - 'response' => new OC_OCS_Result(null, \OCP\API::RESPOND_UNAUTHORISED, 'Unauthorised'), + 'response' => new OC_OCS_Result(null, API::RESPOND_UNAUTHORISED, 'Unauthorised'), 'shipped' => OC_App::isShipped($action['app']), ); continue; @@ -131,7 +134,7 @@ class OC_API { if(!is_callable($action['action'])) { $responses[] = array( 'app' => $action['app'], - 'response' => new OC_OCS_Result(null, \OCP\API::RESPOND_NOT_FOUND, 'Api method not found'), + 'response' => new OC_OCS_Result(null, API::RESPOND_NOT_FOUND, 'Api method not found'), 'shipped' => OC_App::isShipped($action['app']), ); continue; @@ -252,15 +255,15 @@ class OC_API { private static function isAuthorised($action) { $level = $action['authlevel']; switch($level) { - case \OCP\API::GUEST_AUTH: + case API::GUEST_AUTH: // Anyone can access return true; break; - case \OCP\API::USER_AUTH: + case API::USER_AUTH: // User required return self::loginUser(); break; - case \OCP\API::SUBADMIN_AUTH: + case API::SUBADMIN_AUTH: // Check for subadmin $user = self::loginUser(); if(!$user) { @@ -275,7 +278,7 @@ class OC_API { } } break; - case \OCP\API::ADMIN_AUTH: + case API::ADMIN_AUTH: // Check for admin $user = self::loginUser(); if(!$user) { @@ -342,28 +345,21 @@ class OC_API { */ public static function respond($result, $format='xml') { // Send 401 headers if unauthorised - if($result->getStatusCode() === \OCP\API::RESPOND_UNAUTHORISED) { + if($result->getStatusCode() === API::RESPOND_UNAUTHORISED) { header('WWW-Authenticate: Basic realm="Authorisation Required"'); header('HTTP/1.0 401 Unauthorized'); } - $response = array( - 'ocs' => array( - 'meta' => $result->getMeta(), - 'data' => $result->getData(), - ), - ); - if ($format == 'json') { - OC_JSON::encodedPrint($response); - } else if ($format == 'xml') { - header('Content-type: text/xml; charset=UTF-8'); - $writer = new XMLWriter(); - $writer->openMemory(); - $writer->setIndent( true ); - $writer->startDocument(); - self::toXML($response, $writer); - $writer->endDocument(); - echo $writer->outputMemory(true); + + if (self::isV2()) { + $statusCode = self::mapStatusCodes($result->getStatusCode()); + if (!is_null($statusCode)) { + OC_Response::setStatus($statusCode); + } } + + self::setContentType($format); + $body = self::renderResult($result, $format); + echo $body; } /** @@ -400,8 +396,8 @@ class OC_API { /** * Based on the requested format the response content type is set */ - public static function setContentType() { - $format = self::requestedFormat(); + public static function setContentType($format = null) { + $format = is_null($format) ? self::requestedFormat() : $format; if ($format === 'xml') { header('Content-type: text/xml; charset=UTF-8'); return; @@ -415,5 +411,64 @@ class OC_API { header('Content-Type: application/octet-stream; charset=utf-8'); } + /** + * @return boolean + */ + private static function isV2() { + $request = \OC::$server->getRequest(); + $script = $request->getScriptName(); + + return $script === '/ocs/v2.php'; + } + + /** + * @param integer $sc + * @return int + */ + public static function mapStatusCodes($sc) { + switch ($sc) { + case API::RESPOND_NOT_FOUND: + return Http::STATUS_NOT_FOUND; + case API::RESPOND_SERVER_ERROR: + return Http::STATUS_INTERNAL_SERVER_ERROR; + case API::RESPOND_UNKNOWN_ERROR: + return Http::STATUS_INTERNAL_SERVER_ERROR; + case API::RESPOND_UNAUTHORISED: + // already handled for v1 + return null; + case 100: + return Http::STATUS_OK; + } + // any 2xx, 4xx and 5xx will be used as is + if ($sc >= 200 && $sc < 600) { + return $sc; + } + + return Http::STATUS_BAD_REQUEST; + } + + /** + * @param OC_OCS_Result $result + * @param string $format + * @return string + */ + public static function renderResult($result, $format) { + $response = array( + 'ocs' => array( + 'meta' => $result->getMeta(), + 'data' => $result->getData(), + ), + ); + if ($format == 'json') { + return OC_JSON::encode($response); + } + $writer = new XMLWriter(); + $writer->openMemory(); + $writer->setIndent(true); + $writer->startDocument(); + self::toXML($response, $writer); + $writer->endDocument(); + return $writer->outputMemory(true); + } } diff --git a/lib/private/ocs.php b/lib/private/ocs.php index 6d166f8adb0..bb1aabf8f18 100644 --- a/lib/private/ocs.php +++ b/lib/private/ocs.php @@ -28,6 +28,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/> * */ +use OCP\API; /** * Class to handle open collaboration services API requests @@ -64,8 +65,7 @@ class OC_OCS { } } if ($data === false) { - echo self::generateXml('', 'fail', 400, 'Bad request. Please provide a valid '.$key); - exit(); + throw new \OC\OCS\Exception(new OC_OCS_Result(null, 400, 'Bad request. Please provide a valid '.$key)); } else { // NOTE: Is the raw type necessary? It might be a little risky without sanitization if ($type == 'raw') return $data; @@ -78,23 +78,12 @@ class OC_OCS { } public static function notFound() { - if($_SERVER['REQUEST_METHOD'] == 'GET') { - $method='get'; - }elseif($_SERVER['REQUEST_METHOD'] == 'PUT') { - $method='put'; - }elseif($_SERVER['REQUEST_METHOD'] == 'POST') { - $method='post'; - }else{ - echo('internal server error: method not supported'); - exit(); - } - - $format = self::readData($method, 'format', 'text', ''); + $format = OC_API::requestedFormat(); $txt='Invalid query, please check the syntax. API specifications are here:' .' http://www.freedesktop.org/wiki/Specifications/open-collaboration-services. DEBUG OUTPUT:'."\n"; $txt.=OC_OCS::getDebugOutput(); - echo(OC_OCS::generateXml($format, 'failed', 999, $txt)); + OC_API::respond(new OC_OCS_Result(null, API::RESPOND_UNKNOWN_ERROR, $txt), $format); } /** @@ -110,130 +99,4 @@ class OC_OCS { if(isset($_POST)) foreach($_POST as $key=>$value) $txt.='post parameter: '.$key.'->'.$value."\n"; return($txt); } - - - /** - * generates the xml or json response for the API call from an multidimenional data array. - * @param string $format - * @param string $status - * @param string $statuscode - * @param string $message - * @param array $data - * @param string $tag - * @param string $tagattribute - * @param int $dimension - * @param int|string $itemscount - * @param int|string $itemsperpage - * @return string xml/json - */ - public static function generateXml($format, $status, $statuscode, - $message, $data=array(), $tag='', $tagattribute='', $dimension=-1, $itemscount='', $itemsperpage='') { - if($format=='json') { - $json=array(); - $json['status']=$status; - $json['statuscode']=$statuscode; - $json['message']=$message; - $json['totalitems']=$itemscount; - $json['itemsperpage']=$itemsperpage; - $json['data']=$data; - return(json_encode($json)); - }else{ - $txt=''; - $writer = xmlwriter_open_memory(); - xmlwriter_set_indent( $writer, 2 ); - xmlwriter_start_document($writer ); - xmlwriter_start_element($writer, 'ocs'); - xmlwriter_start_element($writer, 'meta'); - xmlwriter_write_element($writer, 'status', $status); - xmlwriter_write_element($writer, 'statuscode', $statuscode); - xmlwriter_write_element($writer, 'message', $message); - if($itemscount<>'') xmlwriter_write_element($writer, 'totalitems', $itemscount); - if(!empty($itemsperpage)) xmlwriter_write_element($writer, 'itemsperpage', $itemsperpage); - xmlwriter_end_element($writer); - if($dimension=='0') { - // 0 dimensions - xmlwriter_write_element($writer, 'data', $data); - - }elseif($dimension=='1') { - xmlwriter_start_element($writer, 'data'); - foreach($data as $key=>$entry) { - xmlwriter_write_element($writer, $key, $entry); - } - xmlwriter_end_element($writer); - - }elseif($dimension=='2') { - xmlwriter_start_element($writer, 'data'); - foreach($data as $entry) { - xmlwriter_start_element($writer, $tag); - if(!empty($tagattribute)) { - xmlwriter_write_attribute($writer, 'details', $tagattribute); - } - foreach($entry as $key=>$value) { - if(is_array($value)) { - foreach($value as $k=>$v) { - xmlwriter_write_element($writer, $k, $v); - } - } else { - xmlwriter_write_element($writer, $key, $value); - } - } - xmlwriter_end_element($writer); - } - xmlwriter_end_element($writer); - - }elseif($dimension=='3') { - xmlwriter_start_element($writer, 'data'); - foreach($data as $entrykey=>$entry) { - xmlwriter_start_element($writer, $tag); - if(!empty($tagattribute)) { - xmlwriter_write_attribute($writer, 'details', $tagattribute); - } - foreach($entry as $key=>$value) { - if(is_array($value)) { - xmlwriter_start_element($writer, $entrykey); - foreach($value as $k=>$v) { - xmlwriter_write_element($writer, $k, $v); - } - xmlwriter_end_element($writer); - } else { - xmlwriter_write_element($writer, $key, $value); - } - } - xmlwriter_end_element($writer); - } - xmlwriter_end_element($writer); - }elseif($dimension=='dynamic') { - xmlwriter_start_element($writer, 'data'); - OC_OCS::toxml($writer, $data, 'comment'); - xmlwriter_end_element($writer); - } - - xmlwriter_end_element($writer); - - xmlwriter_end_document( $writer ); - $txt.=xmlwriter_output_memory( $writer ); - unset($writer); - return($txt); - } - } - - /** - * @param resource $writer - * @param array $data - * @param string $node - */ - public static function toXml($writer, $data, $node) { - foreach($data as $key => $value) { - if (is_numeric($key)) { - $key = $node; - } - if (is_array($value)) { - xmlwriter_start_element($writer, $key); - OC_OCS::toxml($writer, $value, $node); - xmlwriter_end_element($writer); - }else{ - xmlwriter_write_element($writer, $key, $value); - } - } - } } diff --git a/lib/private/ocs/exception.php b/lib/private/ocs/exception.php new file mode 100644 index 00000000000..93bee773771 --- /dev/null +++ b/lib/private/ocs/exception.php @@ -0,0 +1,34 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2015, 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\OCS; + +class Exception extends \Exception { + + public function __construct(\OC_OCS_Result $result) { + $this->result = $result; + } + + public function getResult() { + return $this->result; + } + +} diff --git a/lib/public/appframework/http/ocsresponse.php b/lib/public/appframework/http/ocsresponse.php index 52d3c2fa665..2e788a52bb9 100644 --- a/lib/public/appframework/http/ocsresponse.php +++ b/lib/public/appframework/http/ocsresponse.php @@ -41,38 +41,26 @@ class OCSResponse extends Response { private $format; private $statuscode; private $message; - private $tag; - private $tagattribute; - private $dimension; private $itemscount; private $itemsperpage; /** * generates the xml or json response for the API call from an multidimenional data array. * @param string $format - * @param string $status - * @param string $statuscode + * @param int $statuscode * @param string $message * @param array $data - * @param string $tag - * @param string $tagattribute - * @param int $dimension * @param int|string $itemscount * @param int|string $itemsperpage * @since 8.1.0 */ - public function __construct($format, $status, $statuscode, $message, - $data=[], $tag='', $tagattribute='', - $dimension=-1, $itemscount='', + public function __construct($format, $statuscode, $message, + $data=[], $itemscount='', $itemsperpage='') { $this->format = $format; - $this->setStatus($status); $this->statuscode = $statuscode; $this->message = $message; $this->data = $data; - $this->tag = $tag; - $this->tagattribute = $tagattribute; - $this->dimension = $dimension; $this->itemscount = $itemscount; $this->itemsperpage = $itemsperpage; @@ -93,11 +81,11 @@ class OCSResponse extends Response { * @since 8.1.0 */ public function render() { - return OC_OCS::generateXml( - $this->format, $this->getStatus(), $this->statuscode, $this->message, - $this->data, $this->tag, $this->tagattribute, $this->dimension, - $this->itemscount, $this->itemsperpage - ); + $r = new \OC_OCS_Result($this->data, $this->statuscode, $this->message); + $r->setTotalItems($this->itemscount); + $r->setItemsPerPage($this->itemsperpage); + + return \OC_API::renderResult($r, $this->format); } diff --git a/lib/public/appframework/ocscontroller.php b/lib/public/appframework/ocscontroller.php index 602731fe761..55ba518020a 100644 --- a/lib/public/appframework/ocscontroller.php +++ b/lib/public/appframework/ocscontroller.php @@ -42,7 +42,7 @@ abstract class OCSController extends ApiController { * constructor of the controller * @param string $appName the name of the app * @param IRequest $request an instance of the request - * @param string $corsMethods comma seperated string of HTTP verbs which + * @param string $corsMethods comma separated string of HTTP verbs which * should be allowed for websites or webapps when calling your API, defaults to * 'PUT, POST, GET, DELETE, PATCH' * @param string $corsAllowedHeaders comma seperated string of HTTP headers @@ -80,13 +80,9 @@ abstract class OCSController extends ApiController { } $params = [ - 'status' => 'OK', 'statuscode' => 100, 'message' => 'OK', 'data' => [], - 'tag' => '', - 'tagattribute' => '', - 'dimension' => 'dynamic', 'itemscount' => '', 'itemsperpage' => '' ]; @@ -96,9 +92,8 @@ abstract class OCSController extends ApiController { } return new OCSResponse( - $format, $params['status'], $params['statuscode'], - $params['message'], $params['data'], $params['tag'], - $params['tagattribute'], $params['dimension'], + $format, $params['statuscode'], + $params['message'], $params['data'], $params['itemscount'], $params['itemsperpage'] ); } diff --git a/ocs/v1.php b/ocs/v1.php index 2829cf08c57..c5c18d20b8a 100644 --- a/ocs/v1.php +++ b/ocs/v1.php @@ -56,5 +56,7 @@ try { } catch (MethodNotAllowedException $e) { OC_API::setContentType(); OC_Response::setStatus(405); +} catch (\OC\OCS\Exception $ex) { + OC_API::respond($ex->getResult(), OC_API::requestedFormat()); } diff --git a/ocs/v2.php b/ocs/v2.php new file mode 100644 index 00000000000..b2e3b259727 --- /dev/null +++ b/ocs/v2.php @@ -0,0 +1,22 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2015, 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/> + * + */ + +require_once 'v1.php'; diff --git a/settings/application.php b/settings/application.php index 8da835c18d2..155cc39d041 100644 --- a/settings/application.php +++ b/settings/application.php @@ -107,7 +107,8 @@ class Application extends App { $c->query('AppName'), $c->query('Request'), $c->query('CertificateManager'), - $c->query('L10N') + $c->query('L10N'), + $c->query('IAppManager') ); }); $container->registerService('GroupsController', function(IContainer $c) { diff --git a/settings/controller/certificatecontroller.php b/settings/controller/certificatecontroller.php index ea20b7c587f..92d0961efb7 100644 --- a/settings/controller/certificatecontroller.php +++ b/settings/controller/certificatecontroller.php @@ -21,6 +21,7 @@ namespace OC\Settings\Controller; +use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; @@ -36,20 +37,25 @@ class CertificateController extends Controller { private $certificateManager; /** @var IL10N */ private $l10n; + /** @var IAppManager */ + private $appManager; /** * @param string $appName * @param IRequest $request * @param ICertificateManager $certificateManager * @param IL10N $l10n + * @param IAppManager $appManager */ public function __construct($appName, IRequest $request, ICertificateManager $certificateManager, - IL10N $l10n) { + IL10N $l10n, + IAppManager $appManager) { parent::__construct($appName, $request); $this->certificateManager = $certificateManager; $this->l10n = $l10n; + $this->appManager = $appManager; } /** @@ -60,6 +66,11 @@ class CertificateController extends Controller { * @return array */ public function addPersonalRootCertificate() { + + if ($this->isCertificateImportAllowed() === false) { + return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN); + } + $file = $this->request->getUploadedFile('rootcert_import'); if(empty($file)) { return new DataResponse(['message' => 'No file uploaded'], Http::STATUS_UNPROCESSABLE_ENTITY); @@ -92,8 +103,29 @@ class CertificateController extends Controller { * @return DataResponse */ public function removePersonalRootCertificate($certificateIdentifier) { + + if ($this->isCertificateImportAllowed() === false) { + return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN); + } + $this->certificateManager->removeCertificate($certificateIdentifier); return new DataResponse(); } + /** + * check if certificate import is allowed + * + * @return bool + */ + protected function isCertificateImportAllowed() { + $externalStorageEnabled = $this->appManager->isEnabledForUser('files_external'); + if ($externalStorageEnabled) { + $backends = \OC_Mount_Config::getPersonalBackends(); + if (!empty($backends)) { + return true; + } + } + return false; + } + } diff --git a/settings/css/settings.css b/settings/css/settings.css index e0fe9b446be..0af63821627 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -386,6 +386,12 @@ table.grid td.date{ display: inline-block; } +#encryptionAPI li { + list-style-type: initial; + margin-left: 20px; + padding: 5px 0; +} + .mail_settings p label:first-child { display: inline-block; width: 300px; diff --git a/settings/personal.php b/settings/personal.php index 8823102e01a..203c9f68af8 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -104,6 +104,17 @@ $clients = array( 'ios' => $config->getSystemValue('customclient_ios', $defaults->getiOSClientUrl()) ); +// only show root certificate import if external storages are enabled +$enableCertImport = false; +$externalStorageEnabled = \OC::$server->getAppManager()->isEnabledForUser('files_external'); +if ($externalStorageEnabled) { + $backends = OC_Mount_Config::getPersonalBackends(); + if (!empty($backends)) { + $enableCertImport = true; + } +} + + // Return template $tmpl = new OC_Template( 'settings', 'personal', 'user'); $tmpl->assign('usage', OC_Helper::humanFileSize($storageInfo['used'])); @@ -120,6 +131,7 @@ $tmpl->assign('displayName', OC_User::getDisplayName()); $tmpl->assign('enableAvatars', $config->getSystemValue('enable_avatars', true)); $tmpl->assign('avatarChangeSupported', OC_User::canUserChangeAvatar(OC_User::getUser())); $tmpl->assign('certs', $certificateManager->listCertificates()); +$tmpl->assign('showCertificates', $enableCertImport); $tmpl->assign('urlGenerator', $urlGenerator); // Get array of group ids for this user @@ -157,7 +169,11 @@ $formsMap = array_map(function($form){ $formsAndMore = array_merge($formsAndMore, $formsMap); // add bottom hardcoded forms from the template -$formsAndMore[]= array( 'anchor' => 'ssl-root-certificates', 'section-name' => $l->t('SSL root certificates') ); +if($enableCertImport) { + $formsAndMore[]= array( 'anchor' => 'ssl-root-certificates', 'section-name' => $l->t('SSL root certificates') ); +} + + $tmpl->assign('forms', $formsAndMore); $tmpl->printPage(); diff --git a/settings/templates/admin.php b/settings/templates/admin.php index 4203ee2cad7..ff8a2f0c953 100644 --- a/settings/templates/admin.php +++ b/settings/templates/admin.php @@ -326,10 +326,17 @@ if ($_['cronErrors']) { </p> <div id="EncryptionWarning" class="warning hidden"> - <?php p($l->t('Encryption is a one way process. Once encryption is enabled, all files from that point forward will be encrypted on the server and it will not be possible to disable encryption at a later date. This is the final warning: Do you really want to enable encryption?')) ?> - <input type="button" + <p><?php p($l->t('Please read carefully before activating server-side encryption: ')); ?></p> + <ul> + <li><?php p($l->t('Server-side encryption is a one way process. Once encryption is enabled, all files from that point forward will be encrypted on the server and it will not be possible to disable encryption at a later date')); ?></li> + <li><?php p($l->t('Anyone who has privileged access to your ownCloud server can decrypt your files either by intercepting requests or reading out user passwords which are stored in plain text session files. Server-side encryption does therefore not protect against malicious administrators but is useful for protecting your data on externally hosted storage.')); ?></li> + <li><?php p($l->t('Depending on the actual encryption module the general file size is increased (by 35%% or more when using the default module)')); ?></li> + <li><?php p($l->t('You should regularly backup all encryption keys to prevent permanent data loss (data/<user>/files_encryption and data/files_encryption)')); ?></li> + </ul> + + <p><?php p($l->t('This is the final warning: Do you really want to enable encryption?')) ?> <input type="button" id="reallyEnableEncryption" - value="<?php p($l->t("Enable encryption")); ?>" /> + value="<?php p($l->t("Enable encryption")); ?>" /></p> </div> <div id="EncryptionSettingsArea" class="<?php if (!$_['encryptionEnabled']) p('hidden'); ?>"> diff --git a/settings/templates/personal.php b/settings/templates/personal.php index e7832b85ebd..490133c9f25 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -205,6 +205,7 @@ if($_['passwordChangeSupported']) { <?php } };?> +<?php if($_['showCertificates']) : ?> <div id="ssl-root-certificates" class="section"> <h2><?php p($l->t('SSL root certificates')); ?></h2> <table id="sslCertificate" class="grid"> @@ -242,6 +243,7 @@ if($_['passwordChangeSupported']) { <input type="button" id="rootcert_import_button" value="<?php p($l->t('Import root certificate')); ?>"/> </form> </div> +<?php endif; ?> <div class="section"> <h2><?php p($l->t('Version'));?></h2> diff --git a/tests/lib/appframework/controller/OCSControllerTest.php b/tests/lib/appframework/controller/OCSControllerTest.php index 11a9d45eb92..92b092cf0e9 100644 --- a/tests/lib/appframework/controller/OCSControllerTest.php +++ b/tests/lib/appframework/controller/OCSControllerTest.php @@ -69,9 +69,11 @@ class OCSControllerTest extends \Test\TestCase { $expected = "<?xml version=\"1.0\"?>\n" . "<ocs>\n" . " <meta>\n" . - " <status>OK</status>\n" . + " <status>failure</status>\n" . " <statuscode>400</statuscode>\n" . " <message>OK</message>\n" . + " <totalitems></totalitems>\n" . + " <itemsperpage></itemsperpage>\n" . " </meta>\n" . " <data>\n" . " <test>hi</test>\n" . @@ -99,9 +101,11 @@ class OCSControllerTest extends \Test\TestCase { $expected = "<?xml version=\"1.0\"?>\n" . "<ocs>\n" . " <meta>\n" . - " <status>OK</status>\n" . + " <status>failure</status>\n" . " <statuscode>400</statuscode>\n" . " <message>OK</message>\n" . + " <totalitems></totalitems>\n" . + " <itemsperpage></itemsperpage>\n" . " </meta>\n" . " <data>\n" . " <test>hi</test>\n" . @@ -126,8 +130,8 @@ class OCSControllerTest extends \Test\TestCase { $this->getMock('\OCP\Security\ISecureRandom'), $this->getMock('\OCP\IConfig') )); - $expected = '{"status":"OK","statuscode":400,"message":"OK",' . - '"totalitems":"","itemsperpage":"","data":{"test":"hi"}}'; + $expected = '{"ocs":{"meta":{"status":"failure","statuscode":400,"message":"OK",' . + '"totalitems":"","itemsperpage":""},"data":{"test":"hi"}}}'; $params = [ 'data' => [ 'test' => 'hi' diff --git a/tests/lib/appframework/http/OCSResponseTest.php b/tests/lib/appframework/http/OCSResponseTest.php index 111dc7ad0a3..1ca3e330bad 100644 --- a/tests/lib/appframework/http/OCSResponseTest.php +++ b/tests/lib/appframework/http/OCSResponseTest.php @@ -47,14 +47,13 @@ class OCSResponseTest extends \Test\TestCase { public function testRender() { $response = new OCSResponse( - 'xml', 'status', 2, 'message', ['test' => 'hi'], 'tag', 'abc', - 'dynamic', 3, 4 + 'xml', 2, 'message', ['test' => 'hi'], 3, 4 ); $out = $response->render(); $expected = "<?xml version=\"1.0\"?>\n" . "<ocs>\n" . " <meta>\n" . - " <status>status</status>\n" . + " <status>failure</status>\n" . " <statuscode>2</statuscode>\n" . " <message>message</message>\n" . " <totalitems>3</totalitems>\n" . diff --git a/tests/ocs/response.php b/tests/ocs/response.php new file mode 100644 index 00000000000..919915a7c78 --- /dev/null +++ b/tests/ocs/response.php @@ -0,0 +1,42 @@ +<?php +use OCP\AppFramework\Http; + +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2015, 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/> + * + */ + +class OcsResponseTest extends \Test\TestCase { + + /** + * @dataProvider providesStatusCodes + */ + public function testStatusCodeMapper($expected, $sc) { + $result = OC_API::mapStatusCodes($sc); + $this->assertEquals($expected, $result); + } + + public function providesStatusCodes() { + return [ + [Http::STATUS_OK, 100], + [Http::STATUS_BAD_REQUEST, 104], + [Http::STATUS_BAD_REQUEST, 1000], + [201, 201], + ]; + } +} diff --git a/tests/settings/controller/CertificateControllerTest.php b/tests/settings/controller/CertificateControllerTest.php index b6981195034..023d7753cca 100644 --- a/tests/settings/controller/CertificateControllerTest.php +++ b/tests/settings/controller/CertificateControllerTest.php @@ -21,6 +21,7 @@ namespace OC\Settings\Controller; +use OCP\App\IAppManager; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; @@ -41,6 +42,8 @@ class CertificateControllerTest extends \Test\TestCase { private $certificateManager; /** @var IL10N */ private $l10n; + /** @var IAppManager */ + private $appManager; public function setUp() { parent::setUp(); @@ -48,13 +51,21 @@ class CertificateControllerTest extends \Test\TestCase { $this->request = $this->getMock('\OCP\IRequest'); $this->certificateManager = $this->getMock('\OCP\ICertificateManager'); $this->l10n = $this->getMock('\OCP\IL10N'); - - $this->certificateController = new CertificateController( - 'settings', - $this->request, - $this->certificateManager, - $this->l10n - ); + $this->appManager = $this->getMock('OCP\App\IAppManager'); + + $this->certificateController = $this->getMockBuilder('OC\Settings\Controller\CertificateController') + ->setConstructorArgs( + [ + 'settings', + $this->request, + $this->certificateManager, + $this->l10n, + $this->appManager + ] + )->setMethods(['isCertificateImportAllowed'])->getMock(); + + $this->certificateController->expects($this->any()) + ->method('isCertificateImportAllowed')->willReturn(true); } public function testAddPersonalRootCertificateWithEmptyFile() { |