Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Personal settings auth tokens #24703

Merged
merged 3 commits into from
May 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion lib/private/Authentication/Token/DefaultToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
* @method void setId(int $id)
* @method void setUid(string $uid);
* @method void setPassword(string $password)
* @method string getPassword()
* @method void setName(string $name)
* @method string getName()
* @method void setToken(string $token)
Expand Down Expand Up @@ -87,4 +86,13 @@ public function getPassword() {
return parent::getPassword();
}

public function jsonSerialize() {
return [
'id' => $this->id,
'name' => $this->name,
'lastActivity' => $this->lastActivity,
'type' => $this->type,
];
}

}
13 changes: 13 additions & 0 deletions lib/private/Authentication/Token/DefaultTokenMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,17 @@ public function getTokenByUser(IUser $user) {
return $entities;
}

/**
* @param IUser $user
* @param int $id
*/
public function deleteById(IUser $user, $id) {
/* @var $qb IQueryBuilder */
$qb = $this->db->getQueryBuilder();
$qb->delete('authtoken')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not required, because id is unique?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or don't you check ownership before

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$qb->execute();
}

}
12 changes: 12 additions & 0 deletions lib/private/Authentication/Token/DefaultTokenProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ public function getToken($tokenId) {
/**
* @param IToken $savedToken
* @param string $tokenId session token
* @throws InvalidTokenException
* @return string
*/
public function getPassword(IToken $savedToken, $tokenId) {
Expand All @@ -149,6 +150,16 @@ public function invalidateToken($token) {
$this->mapper->invalidate($this->hashToken($token));
}

/**
* Invalidate (delete) the given token
*
* @param IUser $user
* @param int $id
*/
public function invalidateTokenById(IUser $user, $id) {
$this->mapper->deleteById($user, $id);
}

/**
* Invalidate (delete) old session tokens
*/
Expand Down Expand Up @@ -203,6 +214,7 @@ private function encryptPassword($password, $token) {
*
* @param string $password
* @param string $token
* @throws InvalidTokenException
* @return string the decrypted key
*/
private function decryptPassword($password, $token) {
Expand Down
13 changes: 11 additions & 2 deletions lib/private/Authentication/Token/IProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface IProvider {
* @param string $password
* @param string $name
* @param int $type token type
* @return DefaultToken
* @return IToken
*/
public function generateToken($token, $uid, $password, $name, $type = IToken::TEMPORARY_TOKEN);

Expand All @@ -47,7 +47,7 @@ public function generateToken($token, $uid, $password, $name, $type = IToken::TE
* @return IToken
*/
public function getToken($tokenId) ;

/**
* @param string $token
* @throws InvalidTokenException
Expand All @@ -62,6 +62,14 @@ public function validateToken($token);
*/
public function invalidateToken($token);

/**
* Invalidate (delete) the given token
*
* @param IUser $user
* @param int $id
*/
public function invalidateTokenById(IUser $user, $id);

/**
* Update token activity timestamp
*
Expand All @@ -85,6 +93,7 @@ public function getTokenByUser(IUser $user);
*
* @param IToken $token
* @param string $tokenId
* @throws InvalidTokenException
* @return string
*/
public function getPassword(IToken $token, $tokenId);
Expand Down
6 changes: 4 additions & 2 deletions lib/private/Authentication/Token/IToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@

namespace OC\Authentication\Token;

interface IToken {
use JsonSerializable;

interface IToken extends JsonSerializable {

const TEMPORARY_TOKEN = 0;
const PERMANENT_TOKEN = 1;

/**
* Get the token ID
*
* @return string
* @return int
*/
public function getId();

Expand Down
3 changes: 2 additions & 1 deletion lib/private/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,15 @@ public function __construct($webRoot, \OC\Config $config) {
$timeFactory = new TimeFactory();
return new \OC\Authentication\Token\DefaultTokenProvider($mapper, $crypto, $config, $logger, $timeFactory);
});
$this->registerAlias('OC\Authentication\Token\IProvider', 'OC\Authentication\Token\DefaultTokenProvider');
$this->registerService('UserSession', function (Server $c) {
$manager = $c->getUserManager();
$session = new \OC\Session\Memory('');
$timeFactory = new TimeFactory();
// Token providers might require a working database. This code
// might however be called when ownCloud is not yet setup.
if (\OC::$server->getSystemConfig()->getValue('installed', false)) {
$defaultTokenProvider = $c->query('OC\Authentication\Token\DefaultTokenProvider');
$defaultTokenProvider = $c->query('OC\Authentication\Token\IProvider');
} else {
$defaultTokenProvider = null;
}
Expand Down
18 changes: 15 additions & 3 deletions settings/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
namespace OC\Settings;

use OC\Files\View;
use OC\Server;
use OC\Settings\Controller\AppSettingsController;
use OC\Settings\Controller\AuthSettingsController;
use OC\Settings\Controller\CertificateController;
use OC\Settings\Controller\CheckSetupController;
use OC\Settings\Controller\EncryptionController;
Expand All @@ -39,10 +41,9 @@
use OC\Settings\Controller\SecuritySettingsController;
use OC\Settings\Controller\UsersController;
use OC\Settings\Middleware\SubadminMiddleware;
use \OCP\AppFramework\App;
use OCP\AppFramework\App;
use OCP\IContainer;
use \OCP\Util;
use OC\Server;
use OCP\Util;

/**
* @package OC\Settings
Expand Down Expand Up @@ -97,6 +98,17 @@ public function __construct(array $urlParams=[]){
$c->query('OcsClient')
);
});
$container->registerService('AuthSettingsController', function(IContainer $c) {
return new AuthSettingsController(
$c->query('AppName'),
$c->query('Request'),
$c->query('ServerContainer')->query('OC\Authentication\Token\IProvider'),
$c->query('UserManager'),
$c->query('ServerContainer')->getSession(),
$c->query('ServerContainer')->getSecureRandom(),
$c->query('UserId')
);
});
$container->registerService('SecuritySettingsController', function(IContainer $c) {
return new SecuritySettingsController(
$c->query('AppName'),
Expand Down
151 changes: 151 additions & 0 deletions settings/Controller/AuthSettingsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<?php

/**
* @author Christoph Wurst <christoph@owncloud.com>
*
* @copyright Copyright (c) 2016, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OC\Settings\Controller;

use OC\AppFramework\Http;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Token\IProvider;
use OC\Authentication\Token\IToken;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest;
use OCP\ISession;
use OCP\IUserManager;
use OCP\Security\ISecureRandom;
use OCP\Session\Exceptions\SessionNotAvailableException;

class AuthSettingsController extends Controller {

/** @var IProvider */
private $tokenProvider;

/** @var IUserManager */
private $userManager;

/** @var ISession */
private $session;

/** @var string */
private $uid;

/** @var ISecureRandom */
private $random;

/**
* @param string $appName
* @param IRequest $request
* @param IProvider $tokenProvider
* @param IUserManager $userManager
* @param ISession $session
* @param ISecureRandom $random
* @param string $uid
*/
public function __construct($appName, IRequest $request, IProvider $tokenProvider, IUserManager $userManager,
ISession $session, ISecureRandom $random, $uid) {
parent::__construct($appName, $request);
$this->tokenProvider = $tokenProvider;
$this->userManager = $userManager;
$this->uid = $uid;
$this->session = $session;
$this->random = $random;
}

/**
* @NoAdminRequired
* @NoSubadminRequired
*
* @return JSONResponse
*/
public function index() {
$user = $this->userManager->get($this->uid);
if (is_null($user)) {
return [];
}
return $this->tokenProvider->getTokenByUser($user);
}

/**
* @NoAdminRequired
* @NoSubadminRequired
*
* @return JSONResponse
*/
public function create($name) {
try {
$sessionId = $this->session->getId();
} catch (SessionNotAvailableException $ex) {
$resp = new JSONResponse();
$resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);
return $resp;
}

try {
$sessionToken = $this->tokenProvider->getToken($sessionId);
$password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
} catch (InvalidTokenException $ex) {
$resp = new JSONResponse();
$resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);
return $resp;
}

$token = $this->generateRandomDeviceToken();
$deviceToken = $this->tokenProvider->generateToken($token, $this->uid, $password, $name, IToken::PERMANENT_TOKEN);

return [
'token' => $token,
'deviceToken' => $deviceToken
];
}

/**
* Return a 20 digit device password
*
* Example: ABCDE-FGHIJ-KLMNO-PQRST
*
* @return string
*/
private function generateRandomDeviceToken() {
$groups = [];
for ($i = 0; $i < 4; $i++) {
$groups[] = $this->random->generate(5, implode('', range('A', 'Z')));
}
return implode('-', $groups);
}

/**
* @NoAdminRequired
* @NoSubadminRequired
*
* @return JSONResponse
*/
public function destroy($id) {
$user = $this->userManager->get($this->uid);
if (is_null($user)) {
return [];
}

$this->tokenProvider->invalidateTokenById($user, $id);
return [];
}

}
33 changes: 33 additions & 0 deletions settings/css/settings.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,39 @@ input#identity {
table.nostyle label { margin-right: 2em; }
table.nostyle td { padding: 0.2em 0; }

#sessions table,
#devices table {
width: 100%;
min-height: 150px;
padding-top: 25px;
}
#sessions table th,
#devices table th {
font-weight: 800;
}
#sessions table th,
#sessions table td,
#devices table th,
#devices table td {
padding: 10px;
}

#sessions .token-list td,
#devices .token-list td {
border-top: 1px solid #DDD;
}
#sessions .token-list td a.icon-delete,
#devices .token-list td a.icon-delete {
display: block;
opacity: 0.6;
}

#device-new-token {
width: 186px;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if someone knows a better way let me know

font-family: monospace;
background-color: lightyellow;
}

/* USERS */
#newgroup-init a span { margin-left: 20px; }
#newgroup-init a span:before {
Expand Down
Loading