aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/allconfig.php55
-rw-r--r--lib/private/appframework/db/db.php15
-rw-r--r--lib/private/appframework/dependencyinjection/dicontainer.php4
-rw-r--r--lib/private/db/connection.php59
-rw-r--r--lib/private/db/querybuilder/expressionbuilder.php8
-rw-r--r--lib/private/db/querybuilder/ociexpressionbuilder.php33
-rw-r--r--lib/private/db/querybuilder/querybuilder.php7
-rw-r--r--lib/private/security/credentialsmanager.php125
-rw-r--r--lib/private/server.php13
9 files changed, 273 insertions, 46 deletions
diff --git a/lib/private/allconfig.php b/lib/private/allconfig.php
index af7ffa4168e..3c85bfacbb8 100644
--- a/lib/private/allconfig.php
+++ b/lib/private/allconfig.php
@@ -205,57 +205,28 @@ class AllConfig implements \OCP\IConfig {
// TODO - FIXME
$this->fixDIInit();
- // Check if the key does exist
- $sql = 'SELECT `configvalue` FROM `*PREFIX*preferences` '.
- 'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?';
- $result = $this->connection->executeQuery($sql, array($userId, $appName, $key));
- $oldValue = $result->fetchColumn();
- $result->closeCursor();
- $exists = $oldValue !== false;
-
- if($oldValue === strval($value)) {
- // no changes
- return;
+ $preconditionArray = [];
+ if (isset($preCondition)) {
+ $preconditionArray = [
+ 'configvalue' => $preCondition,
+ ];
}
- $affectedRows = 0;
- if (!$exists && $preCondition === null) {
- $this->connection->insertIfNotExist('*PREFIX*preferences', [
- 'configvalue' => $value,
- 'userid' => $userId,
- 'appid' => $appName,
- 'configkey' => $key,
- ], ['configkey', 'userid', 'appid']);
- $affectedRows = 1;
- } elseif ($exists) {
- $data = array($value, $userId, $appName, $key);
-
- $sql = 'UPDATE `*PREFIX*preferences` SET `configvalue` = ? '.
- 'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ? ';
-
- if($preCondition !== null) {
- if($this->getSystemValue('dbtype', 'sqlite') === 'oci') {
- //oracle hack: need to explicitly cast CLOB to CHAR for comparison
- $sql .= 'AND to_char(`configvalue`) = ?';
- } else {
- $sql .= 'AND `configvalue` = ?';
- }
- $data[] = $preCondition;
- }
- $affectedRows = $this->connection->executeUpdate($sql, $data);
- }
+ $this->connection->setValues('preferences', [
+ 'userid' => $userId,
+ 'appid' => $appName,
+ 'configkey' => $key,
+ ], [
+ 'configvalue' => $value,
+ ], $preconditionArray);
// only add to the cache if we already loaded data for the user
- if ($affectedRows > 0 && isset($this->userCache[$userId])) {
+ if (isset($this->userCache[$userId])) {
if (!isset($this->userCache[$userId][$appName])) {
$this->userCache[$userId][$appName] = array();
}
$this->userCache[$userId][$appName][$key] = $value;
}
-
- if ($preCondition !== null && $affectedRows === 0) {
- throw new PreConditionNotMetException;
- }
}
/**
diff --git a/lib/private/appframework/db/db.php b/lib/private/appframework/db/db.php
index 812649daa78..5fdc5d1066c 100644
--- a/lib/private/appframework/db/db.php
+++ b/lib/private/appframework/db/db.php
@@ -147,6 +147,21 @@ class Db implements IDb {
}
/**
+ * Insert or update a row value
+ *
+ * @param string $table
+ * @param array $keys (column name => value)
+ * @param array $values (column name => value)
+ * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
+ * @return int number of new rows
+ * @throws \Doctrine\DBAL\DBALException
+ * @throws PreconditionNotMetException
+ */
+ public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
+ return $this->connection->setValues($table, $keys, $values, $updatePreconditionValues);
+ }
+
+ /**
* Start a transaction
*/
public function beginTransaction() {
diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php
index 8fc52141d5b..a9614262603 100644
--- a/lib/private/appframework/dependencyinjection/dicontainer.php
+++ b/lib/private/appframework/dependencyinjection/dicontainer.php
@@ -215,6 +215,10 @@ class DIContainer extends SimpleContainer implements IAppContainer {
return $this->getServer()->getHasher();
});
+ $this->registerService('OCP\\Security\\ICredentialsManager', function($c) {
+ return $this->getServer()->getCredentialsManager();
+ });
+
$this->registerService('OCP\\Security\\ISecureRandom', function($c) {
return $this->getServer()->getSecureRandom();
});
diff --git a/lib/private/db/connection.php b/lib/private/db/connection.php
index 28bf3b6e05b..6c4f518dfb5 100644
--- a/lib/private/db/connection.php
+++ b/lib/private/db/connection.php
@@ -32,6 +32,7 @@ use Doctrine\Common\EventManager;
use OC\DB\QueryBuilder\ExpressionBuilder;
use OC\DB\QueryBuilder\QueryBuilder;
use OCP\IDBConnection;
+use OCP\PreconditionNotMetException;
class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
/**
@@ -241,6 +242,64 @@ class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
return $this->adapter->insertIfNotExist($table, $input, $compare);
}
+ private function getType($value) {
+ if (is_bool($value)) {
+ return \PDO::PARAM_BOOL;
+ } else if (is_int($value)) {
+ return \PDO::PARAM_INT;
+ } else {
+ return \PDO::PARAM_STR;
+ }
+ }
+
+ /**
+ * Insert or update a row value
+ *
+ * @param string $table
+ * @param array $keys (column name => value)
+ * @param array $values (column name => value)
+ * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
+ * @return int number of new rows
+ * @throws \Doctrine\DBAL\DBALException
+ * @throws PreconditionNotMetException
+ */
+ public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
+ try {
+ $insertQb = $this->getQueryBuilder();
+ $insertQb->insert($table)
+ ->values(
+ array_map(function($value) use ($insertQb) {
+ return $insertQb->createNamedParameter($value, $this->getType($value));
+ }, array_merge($keys, $values))
+ );
+ return $insertQb->execute();
+ } catch (\Doctrine\DBAL\Exception\ConstraintViolationException $e) {
+ // value already exists, try update
+ $updateQb = $this->getQueryBuilder();
+ $updateQb->update($table);
+ foreach ($values as $name => $value) {
+ $updateQb->set($name, $updateQb->createNamedParameter($value), $this->getType($value));
+ }
+ $where = $updateQb->expr()->andx();
+ $whereValues = array_merge($keys, $updatePreconditionValues);
+ foreach ($whereValues as $name => $value) {
+ $where->add($updateQb->expr()->eq(
+ $name,
+ $updateQb->createNamedParameter($value, $this->getType($value)),
+ $this->getType($value)
+ ));
+ }
+ $updateQb->where($where);
+ $affected = $updateQb->execute();
+
+ if ($affected === 0) {
+ throw new PreconditionNotMetException();
+ }
+
+ return 0;
+ }
+ }
+
/**
* returns the error code and message as a string for logging
* works with DoctrineException
diff --git a/lib/private/db/querybuilder/expressionbuilder.php b/lib/private/db/querybuilder/expressionbuilder.php
index de10f69b361..1e86db5a081 100644
--- a/lib/private/db/querybuilder/expressionbuilder.php
+++ b/lib/private/db/querybuilder/expressionbuilder.php
@@ -27,10 +27,10 @@ use OCP\IDBConnection;
class ExpressionBuilder implements IExpressionBuilder {
/** @var \Doctrine\DBAL\Query\Expression\ExpressionBuilder */
- private $expressionBuilder;
+ protected $expressionBuilder;
/** @var QuoteHelper */
- private $helper;
+ protected $helper;
/**
* Initializes a new <tt>ExpressionBuilder</tt>.
@@ -109,10 +109,12 @@ class ExpressionBuilder implements IExpressionBuilder {
*
* @param mixed $x The left expression.
* @param mixed $y The right expression.
+ * @param int|null $type one of the \PDO::PARAM_* constants
+ * required when comparing text fields for oci compatibility
*
* @return string
*/
- public function eq($x, $y) {
+ public function eq($x, $y, $type = null) {
$x = $this->helper->quoteColumnName($x);
$y = $this->helper->quoteColumnName($y);
return $this->expressionBuilder->eq($x, $y);
diff --git a/lib/private/db/querybuilder/ociexpressionbuilder.php b/lib/private/db/querybuilder/ociexpressionbuilder.php
new file mode 100644
index 00000000000..742611bf719
--- /dev/null
+++ b/lib/private/db/querybuilder/ociexpressionbuilder.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@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\DB\QueryBuilder;
+
+class OCIExpressionBuilder extends ExpressionBuilder {
+ public function eq($x, $y, $type = null) {
+ $x = $this->helper->quoteColumnName($x);
+ $y = $this->helper->quoteColumnName($y);
+ if ($type === \PDO::PARAM_STR) {
+ $x = new QueryFunction('to_char(' . $x . ')');
+ }
+ return $this->expressionBuilder->eq($x, $y);
+ }
+}
diff --git a/lib/private/db/querybuilder/querybuilder.php b/lib/private/db/querybuilder/querybuilder.php
index 492e9bc9abf..42b290b90e7 100644
--- a/lib/private/db/querybuilder/querybuilder.php
+++ b/lib/private/db/querybuilder/querybuilder.php
@@ -21,6 +21,7 @@
namespace OC\DB\QueryBuilder;
+use OC\DB\OracleConnection;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
use OCP\DB\QueryBuilder\IParameter;
@@ -82,7 +83,11 @@ class QueryBuilder implements IQueryBuilder {
* @return \OCP\DB\QueryBuilder\IExpressionBuilder
*/
public function expr() {
- return new ExpressionBuilder($this->connection);
+ if ($this->connection instanceof OracleConnection) {
+ return new OCIExpressionBuilder($this->connection);
+ } else {
+ return new ExpressionBuilder($this->connection);
+ }
}
/**
diff --git a/lib/private/security/credentialsmanager.php b/lib/private/security/credentialsmanager.php
new file mode 100644
index 00000000000..405922847be
--- /dev/null
+++ b/lib/private/security/credentialsmanager.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @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\Security;
+
+use OCP\Security\ICrypto;
+use OCP\IDBConnection;
+use OCP\Security\ICredentialsManager;
+use OCP\IConfig;
+
+/**
+ * Store and retrieve credentials for external services
+ *
+ * @package OC\Security
+ */
+class CredentialsManager implements ICredentialsManager {
+
+ const DB_TABLE = 'credentials';
+
+ /** @var ICrypto */
+ protected $crypto;
+
+ /** @var IDBConnection */
+ protected $dbConnection;
+
+ /**
+ * @param ICrypto $crypto
+ * @param IDBConnection $dbConnection
+ */
+ public function __construct(ICrypto $crypto, IDBConnection $dbConnection) {
+ $this->crypto = $crypto;
+ $this->dbConnection = $dbConnection;
+ }
+
+ /**
+ * Store a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @param mixed $credentials
+ */
+ public function store($userId, $identifier, $credentials) {
+ $value = $this->crypto->encrypt(json_encode($credentials));
+
+ $this->dbConnection->setValues(self::DB_TABLE, [
+ 'user' => $userId,
+ 'identifier' => $identifier,
+ ], [
+ 'credentials' => $value,
+ ]);
+ }
+
+ /**
+ * Retrieve a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @return mixed
+ */
+ public function retrieve($userId, $identifier) {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->select('credentials')
+ ->from(self::DB_TABLE)
+ ->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
+ ->andWhere($qb->expr()->eq('identifier', $qb->createNamedParameter($identifier)))
+ ;
+ $result = $qb->execute()->fetch();
+
+ if (!$result) {
+ return null;
+ }
+ $value = $result['credentials'];
+
+ return json_decode($this->crypto->decrypt($value), true);
+ }
+
+ /**
+ * Delete a set of credentials
+ *
+ * @param string|null $userId Null for system-wide credentials
+ * @param string $identifier
+ * @return int rows removed
+ */
+ public function delete($userId, $identifier) {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete(self::DB_TABLE)
+ ->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
+ ->andWhere($qb->expr()->eq('identifier', $qb->createNamedParameter($identifier)))
+ ;
+ return $qb->execute();
+ }
+
+ /**
+ * Erase all credentials stored for a user
+ *
+ * @param string $userId
+ * @return int rows removed
+ */
+ public function erase($userId) {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete(self::DB_TABLE)
+ ->where($qb->expr()->eq('user', $qb->createNamedParameter($userId)))
+ ;
+ return $qb->execute();
+ }
+
+}
diff --git a/lib/private/server.php b/lib/private/server.php
index 69f403308b3..2497c056600 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -65,6 +65,7 @@ use OC\Notification\Manager;
use OC\Security\CertificateManager;
use OC\Security\Crypto;
use OC\Security\Hasher;
+use OC\Security\CredentialsManager;
use OC\Security\SecureRandom;
use OC\Security\TrustedDomainHelper;
use OC\Session\CryptoWrapper;
@@ -345,6 +346,9 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService('Hasher', function (Server $c) {
return new Hasher($c->getConfig());
});
+ $this->registerService('CredentialsManager', function (Server $c) {
+ return new CredentialsManager($c->getCrypto(), $c->getDatabaseConnection());
+ });
$this->registerService('DatabaseConnection', function (Server $c) {
$factory = new \OC\DB\ConnectionFactory();
$systemConfig = $c->getSystemConfig();
@@ -940,6 +944,15 @@ class Server extends ServerContainer implements IServerContainer {
}
/**
+ * Returns a CredentialsManager instance
+ *
+ * @return \OCP\Security\ICredentialsManager
+ */
+ public function getCredentialsManager() {
+ return $this->query('CredentialsManager');
+ }
+
+ /**
* Returns an instance of the db facade
*
* @deprecated use getDatabaseConnection, will be removed in ownCloud 10