@@ -1084,8 +1084,7 @@ | |||
<name>password</name> | |||
<type>clob</type> | |||
<default></default> | |||
<notnull>true</notnull> | |||
<length>4000</length> | |||
<notnull>false</notnull> | |||
</field> | |||
<field> |
@@ -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 { | |||
} |
@@ -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() |
@@ -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); | |||
} | |||
/** |
@@ -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); |
@@ -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; |
@@ -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 |
@@ -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); |
@@ -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 | |||
*/ |
@@ -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]); | |||
} | |||
} |
@@ -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'; |