Create session tokens for apache auth users

This commit is contained in:
Christoph Wurst 2016-05-31 10:48:14 +02:00
parent 9a9c1b9439
commit c58d8159d7
No known key found for this signature in database
GPG key ID: FEECD2543CA6EAF0
11 changed files with 116 additions and 13 deletions

View file

@ -1084,8 +1084,7 @@
<name>password</name>
<type>clob</type>
<default></default>
<notnull>true</notnull>
<length>4000</length>
<notnull>false</notnull>
</field>
<field>

View file

@ -0,0 +1,29 @@
<?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\Authentication\Exceptions;
use Exception;
class PasswordlessTokenException extends Exception {
}

View file

@ -27,7 +27,6 @@ use OCP\AppFramework\Db\Entity;
* @method void setId(int $id)
* @method void setUid(string $uid);
* @method void setLoginName(string $loginName)
* @method string getLoginName()
* @method void setPassword(string $password)
* @method void setName(string $name)
* @method string getName()

View file

@ -23,6 +23,7 @@ namespace OC\Authentication\Token;
use Exception;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
@ -68,7 +69,7 @@ class DefaultTokenProvider implements IProvider {
* @param string $token
* @param string $uid
* @param string $loginName
* @param string $password
* @param string|null $password
* @param string $name
* @param int $type token type
* @return IToken
@ -77,7 +78,9 @@ class DefaultTokenProvider implements IProvider {
$dbToken = new DefaultToken();
$dbToken->setUid($uid);
$dbToken->setLoginName($loginName);
$dbToken->setPassword($this->encryptPassword($password, $token));
if (!is_null($password)) {
$dbToken->setPassword($this->encryptPassword($password, $token));
}
$dbToken->setName($name);
$dbToken->setToken($this->hashToken($token));
$dbToken->setType($type);
@ -136,10 +139,15 @@ class DefaultTokenProvider implements IProvider {
* @param IToken $savedToken
* @param string $tokenId session token
* @throws InvalidTokenException
* @throws PasswordlessTokenException
* @return string
*/
public function getPassword(IToken $savedToken, $tokenId) {
return $this->decryptPassword($savedToken->getPassword(), $tokenId);
$password = $savedToken->getPassword();
if (is_null($password)) {
throw new PasswordlessTokenException();
}
return $this->decryptPassword($password, $tokenId);
}
/**

View file

@ -22,6 +22,7 @@
namespace OC\Authentication\Token;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
use OCP\IUser;
interface IProvider {
@ -32,7 +33,7 @@ interface IProvider {
* @param string $token
* @param string $uid
* @param string $loginName
* @param string $password
* @param string|null $password
* @param string $name
* @param int $type token type
* @return IToken
@ -94,6 +95,7 @@ interface IProvider {
* @param IToken $token
* @param string $tokenId
* @throws InvalidTokenException
* @throws PasswordlessTokenException
* @return string
*/
public function getPassword(IToken $token, $tokenId);

View file

@ -32,6 +32,7 @@ namespace OC\User;
use OC;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
use OC\Authentication\Token\IProvider;
use OC\Authentication\Token\IToken;
use OC\Hooks\Emitter;
@ -46,6 +47,7 @@ use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Session\Exceptions\SessionNotAvailableException;
use OCP\Util;
/**
* Class Session
@ -220,6 +222,10 @@ class Session implements IUserSession, Emitter {
// An invalid token password was used -> log user out
$this->logout();
return;
} catch (PasswordlessTokenException $ex) {
// Token has no password, nothing to check
$this->session->set('last_login_check', $now);
return;
}
if ($this->manager->checkPassword($token->getLoginName(), $pwd) === false
@ -297,8 +303,12 @@ class Session implements IUserSession, Emitter {
// When logging in with token, the password must be decrypted first before passing to login hook
try {
$token = $this->tokenProvider->getToken($password);
$password = $this->tokenProvider->getPassword($token, $password);
$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
try {
$password = $this->tokenProvider->getPassword($token, $password);
$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
} catch (PasswordlessTokenException $ex) {
$this->manager->emit('\OC\User', 'preLogin', array($uid, ''));
}
} catch (InvalidTokenException $ex) {
// Invalid token, nothing to do
}
@ -359,7 +369,7 @@ class Session implements IUserSession, Emitter {
}
protected function isTwoFactorEnforced($username) {
\OCP\Util::emitHook(
Util::emitHook(
'\OCA\Files_Sharing\API\Server2Server',
'preLoginNameUsedAsUserName',
array('uid' => &$username)
@ -452,7 +462,7 @@ class Session implements IUserSession, Emitter {
* @param string $password
* @return boolean
*/
public function createSessionToken(IRequest $request, $uid, $loginName, $password) {
public function createSessionToken(IRequest $request, $uid, $loginName, $password = null) {
if (is_null($this->manager->get($uid))) {
// User does not exist
return false;

View file

@ -180,6 +180,8 @@ class OC_User {
self::setUserId($uid);
self::setDisplayName($uid);
self::getUserSession()->setLoginName($uid);
$request = OC::$server->getRequest();
self::getUserSession()->createSessionToken($request, $uid, $uid);
// setup the filesystem
OC_Util::setupFS($uid);
// first call the post_login hooks, the login-process needs to be

View file

@ -23,6 +23,7 @@ namespace OC\Settings\Controller;
use OC\AppFramework\Http;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException;
use OC\Authentication\Token\IProvider;
use OC\Authentication\Token\IToken;
use OCP\AppFramework\Controller;
@ -101,7 +102,11 @@ class AuthSettingsController extends Controller {
try {
$sessionToken = $this->tokenProvider->getToken($sessionId);
$loginName = $sessionToken->getLoginName();
$password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
try {
$password = $this->tokenProvider->getPassword($sessionToken, $sessionId);
} catch (PasswordlessTokenException $ex) {
$password = null;
}
} catch (InvalidTokenException $ex) {
$resp = new JSONResponse();
$resp->setStatus(Http::STATUS_SERVICE_UNAVAILABLE);

View file

@ -134,6 +134,17 @@ class DefaultTokenProviderTest extends TestCase {
$this->assertEquals('passme', $actual);
}
/**
* @expectedException \OC\Authentication\Exceptions\PasswordlessTokenException
*/
public function testGetPasswordPasswordLessToken() {
$token = 'token1234';
$tk = new DefaultToken();
$tk->setPassword(null);
$this->tokenProvider->getPassword($tk, $token);
}
/**
* @expectedException \OC\Authentication\Exceptions\InvalidTokenException
*/

View file

@ -621,4 +621,42 @@ class SessionTest extends \Test\TestCase {
$this->invokePrivate($userSession, 'validateSession', [$user]);
}
public function testValidateSessionNoPassword() {
$userManager = $this->getMock('\OCP\IUserManager');
$session = $this->getMock('\OCP\ISession');
$timeFactory = $this->getMock('\OCP\AppFramework\Utility\ITimeFactory');
$tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
$userSession = $this->getMockBuilder('\OC\User\Session')
->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config])
->setMethods(['logout'])
->getMock();
$user = $this->getMock('\OCP\IUser');
$token = $this->getMock('\OC\Authentication\Token\IToken');
$session->expects($this->once())
->method('getId')
->will($this->returnValue('sessionid'));
$tokenProvider->expects($this->once())
->method('getToken')
->with('sessionid')
->will($this->returnValue($token));
$session->expects($this->once())
->method('get')
->with('last_login_check')
->will($this->returnValue(1000));
$timeFactory->expects($this->once())
->method('getTime')
->will($this->returnValue(5000));
$tokenProvider->expects($this->once())
->method('getPassword')
->with($token, 'sessionid')
->will($this->throwException(new \OC\Authentication\Exceptions\PasswordlessTokenException()));
$session->expects($this->once())
->method('set')
->with('last_login_check', 5000);
$this->invokePrivate($userSession, 'validateSession', [$user]);
}
}

View file

@ -25,7 +25,7 @@
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.
$OC_Version = array(9, 1, 0, 6);
$OC_Version = array(9, 1, 0, 7);
// The human readable string
$OC_VersionString = '9.1.0 beta 1';