Create session tokens for apache auth users
This commit is contained in:
parent
9a9c1b9439
commit
c58d8159d7
11 changed files with 116 additions and 13 deletions
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue