Signed-off-by: Lukas Reschke <lukas@statuscode.ch>tags/v11.0RC2
$dispatcher->addListener('OC\AccountManager::userUpdated', function(\Symfony\Component\EventDispatcher\GenericEvent $event) { | $dispatcher->addListener('OC\AccountManager::userUpdated', function(\Symfony\Component\EventDispatcher\GenericEvent $event) { | ||||
$user = $event->getSubject(); | $user = $event->getSubject(); | ||||
$keyManager = new \OC\Security\IdentityProof\Manager( | |||||
\OC::$server->getAppDataDir('identityproof'), | |||||
\OC::$server->getCrypto() | |||||
); | |||||
$updateLookupServer = new \OCA\LookupServerConnector\UpdateLookupServer( | $updateLookupServer = new \OCA\LookupServerConnector\UpdateLookupServer( | ||||
new \OC\Accounts\AccountManager(\OC::$server->getDatabaseConnection(), \OC::$server->getEventDispatcher()), | new \OC\Accounts\AccountManager(\OC::$server->getDatabaseConnection(), \OC::$server->getEventDispatcher()), | ||||
\OC::$server->getConfig(), | \OC::$server->getConfig(), | ||||
\OC::$server->getSecureRandom(), | \OC::$server->getSecureRandom(), | ||||
\OC::$server->getHTTPClientService() | |||||
\OC::$server->getHTTPClientService(), | |||||
$keyManager, | |||||
new \OC\Security\IdentityProof\Signer( | |||||
$keyManager, | |||||
new \OC\AppFramework\Utility\TimeFactory(), | |||||
\OC::$server->getURLGenerator(), | |||||
\OC::$server->getUserManager() | |||||
) | |||||
); | ); | ||||
$updateLookupServer->userUpdated($user); | $updateLookupServer->userUpdated($user); | ||||
}); | }); |
<?php | <?php | ||||
/** | /** | ||||
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> | * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> | ||||
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> | |||||
* | * | ||||
* @license GNU AGPL version 3 or any later version | * @license GNU AGPL version 3 or any later version | ||||
* | * | ||||
* | * | ||||
*/ | */ | ||||
namespace OCA\LookupServerConnector; | namespace OCA\LookupServerConnector; | ||||
use OC\Accounts\AccountManager; | use OC\Accounts\AccountManager; | ||||
use OC\Security\IdentityProof\Manager; | |||||
use OC\Security\IdentityProof\Signer; | |||||
use OCP\Http\Client\IClientService; | use OCP\Http\Client\IClientService; | ||||
use OCP\IConfig; | use OCP\IConfig; | ||||
use OCP\IUser; | use OCP\IUser; | ||||
* @package OCA\LookupServerConnector | * @package OCA\LookupServerConnector | ||||
*/ | */ | ||||
class UpdateLookupServer { | class UpdateLookupServer { | ||||
/** @var AccountManager */ | |||||
/** @var AccountManager */ | |||||
private $accountManager; | private $accountManager; | ||||
/** @var IConfig */ | /** @var IConfig */ | ||||
private $config; | private $config; | ||||
/** @var ISecureRandom */ | /** @var ISecureRandom */ | ||||
private $secureRandom; | private $secureRandom; | ||||
/** @var IClientService */ | /** @var IClientService */ | ||||
private $clientService; | private $clientService; | ||||
/** @var Manager */ | |||||
private $keyManager; | |||||
/** @var Signer */ | |||||
private $signer; | |||||
/** @var string URL point to lookup server */ | /** @var string URL point to lookup server */ | ||||
private $lookupServer = 'http://192.168.56.102'; | |||||
private $lookupServer = 'http://192.168.176.105/lookup-server/server/'; | |||||
/** | /** | ||||
* UpdateLookupServer constructor. | |||||
* | |||||
* @param AccountManager $accountManager | * @param AccountManager $accountManager | ||||
* @param IConfig $config | * @param IConfig $config | ||||
* @param ISecureRandom $secureRandom | * @param ISecureRandom $secureRandom | ||||
* @param IClientService $clientService | * @param IClientService $clientService | ||||
* @param Manager $manager | |||||
* @param Signer $signer | |||||
*/ | */ | ||||
public function __construct(AccountManager $accountManager, | public function __construct(AccountManager $accountManager, | ||||
IConfig $config, | IConfig $config, | ||||
ISecureRandom $secureRandom, | ISecureRandom $secureRandom, | ||||
IClientService $clientService) { | |||||
IClientService $clientService, | |||||
Manager $manager, | |||||
Signer $signer) { | |||||
$this->accountManager = $accountManager; | $this->accountManager = $accountManager; | ||||
$this->config = $config; | $this->config = $config; | ||||
$this->secureRandom = $secureRandom; | $this->secureRandom = $secureRandom; | ||||
$this->clientService = $clientService; | $this->clientService = $clientService; | ||||
$this->keyManager = $manager; | |||||
$this->signer = $signer; | |||||
} | } | ||||
/** | |||||
* @param IUser $user | |||||
*/ | |||||
public function userUpdated(IUser $user) { | public function userUpdated(IUser $user) { | ||||
$userData = $this->accountManager->getUser($user); | $userData = $this->accountManager->getUser($user); | ||||
$authKey = $this->config->getUserValue($user->getUID(), 'lookup_server_connector', 'authKey'); | |||||
$publicData = []; | $publicData = []; | ||||
foreach ($userData as $key => $data) { | foreach ($userData as $key => $data) { | ||||
} | } | ||||
if (empty($publicData) && !empty($authKey)) { | if (empty($publicData) && !empty($authKey)) { | ||||
$this->removeFromLookupServer($user, $authKey); | |||||
$this->removeFromLookupServer($user); | |||||
} else { | } else { | ||||
$this->sendToLookupServer($user, $publicData, $authKey); | |||||
$this->sendToLookupServer($user, $publicData); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* TODO: FIXME. Implement removal from lookup server. | |||||
* | |||||
* remove user from lookup server | * remove user from lookup server | ||||
* | * | ||||
* @param IUser $user | * @param IUser $user | ||||
* | * | ||||
* @param IUser $user | * @param IUser $user | ||||
* @param array $publicData | * @param array $publicData | ||||
* @param string $authKey | |||||
*/ | */ | ||||
protected function sendToLookupServer(IUser $user, $publicData, $authKey) { | |||||
if (empty($authKey)) { | |||||
$authKey = $this->secureRandom->generate(16); | |||||
$this->sendNewRecord($user, $publicData, $authKey); | |||||
$this->config->setUserValue($user->getUID(), 'lookup_server_connector', 'authKey', $authKey); | |||||
} else { | |||||
$this->updateExistingRecord($user, $publicData, $authKey); | |||||
} | |||||
} | |||||
protected function sendNewRecord(IUser $user, $publicData, $authKey) { | |||||
protected function sendToLookupServer(IUser $user, array $publicData) { | |||||
$dataArray = [ | |||||
'federationId' => $user->getCloudId(), | |||||
'name' => isset($publicData[AccountManager::PROPERTY_DISPLAYNAME]) ? $publicData[AccountManager::PROPERTY_DISPLAYNAME]['value'] : '', | |||||
'email' => isset($publicData[AccountManager::PROPERTY_EMAIL]) ? $publicData[AccountManager::PROPERTY_EMAIL]['value'] : '', | |||||
'address' => isset($publicData[AccountManager::PROPERTY_ADDRESS]) ? $publicData[AccountManager::PROPERTY_ADDRESS]['value'] : '', | |||||
'website' => isset($publicData[AccountManager::PROPERTY_WEBSITE]) ? $publicData[AccountManager::PROPERTY_WEBSITE]['value'] : '', | |||||
'twitter' => isset($publicData[AccountManager::PROPERTY_TWITTER]) ? $publicData[AccountManager::PROPERTY_TWITTER]['value'] : '', | |||||
'phone' => isset($publicData[AccountManager::PROPERTY_PHONE]) ? $publicData[AccountManager::PROPERTY_PHONE]['value'] : '', | |||||
]; | |||||
$dataArray = $this->signer->sign('lookupserver', $dataArray, $user); | |||||
$httpClient = $this->clientService->newClient(); | $httpClient = $this->clientService->newClient(); | ||||
$response = $httpClient->post($this->lookupServer, | |||||
$httpClient->post($this->lookupServer, | |||||
[ | [ | ||||
'body' => [ | |||||
'key' => $authKey, | |||||
'federationid' => $publicData[$user->getCloudId()], | |||||
'name' => isset($publicData[AccountManager::PROPERTY_DISPLAYNAME]) ? $publicData[AccountManager::PROPERTY_DISPLAYNAME]['value'] : '', | |||||
'email' => isset($publicData[AccountManager::PROPERTY_EMAIL]) ? $publicData[AccountManager::PROPERTY_EMAIL]['value'] : '', | |||||
'address' => isset($publicData[AccountManager::PROPERTY_ADDRESS]) ? $publicData[AccountManager::PROPERTY_ADDRESS]['value'] : '', | |||||
'website' => isset($publicData[AccountManager::PROPERTY_WEBSITE]) ? $publicData[AccountManager::PROPERTY_WEBSITE]['value'] : '', | |||||
'twitter' => isset($publicData[AccountManager::PROPERTY_TWITTER]) ? $publicData[AccountManager::PROPERTY_TWITTER]['value'] : '', | |||||
'phone' => isset($publicData[AccountManager::PROPERTY_PHONE]) ? $publicData[AccountManager::PROPERTY_PHONE]['value'] : '', | |||||
], | |||||
'body' => $dataArray, | |||||
'timeout' => 3, | 'timeout' => 3, | ||||
'connect_timeout' => 3, | 'connect_timeout' => 3, | ||||
] | ] | ||||
); | ); | ||||
} | } | ||||
protected function updateExistingRecord(IUser $user, $publicData, $authKey) { | |||||
$httpClient = $this->clientService->newClient(); | |||||
$httpClient->put($this->lookupServer, | |||||
[ | |||||
'body' => [ | |||||
'key' => $authKey, | |||||
'federationid' => $publicData[$user->getCloudId()], | |||||
'name' => isset($publicData[AccountManager::PROPERTY_DISPLAYNAME]) ? $publicData[AccountManager::PROPERTY_DISPLAYNAME]['value'] : '', | |||||
'email' => isset($publicData[AccountManager::PROPERTY_EMAIL]) ? $publicData[AccountManager::PROPERTY_EMAIL]['value'] : '', | |||||
'address' => isset($publicData[AccountManager::PROPERTY_ADDRESS]) ? $publicData[AccountManager::PROPERTY_ADDRESS]['value'] : '', | |||||
'website' => isset($publicData[AccountManager::PROPERTY_WEBSITE]) ? $publicData[AccountManager::PROPERTY_WEBSITE]['value'] : '', | |||||
'twitter' => isset($publicData[AccountManager::PROPERTY_TWITTER]) ? $publicData[AccountManager::PROPERTY_TWITTER]['value'] : '', | |||||
'phone' => isset($publicData[AccountManager::PROPERTY_PHONE]) ? $publicData[AccountManager::PROPERTY_PHONE]['value'] : '', | |||||
], | |||||
'timeout' => 3, | |||||
'connect_timeout' => 3, | |||||
] | |||||
); | |||||
} | |||||
} | } |
public function getIdentityProof($cloudId) { | public function getIdentityProof($cloudId) { | ||||
$userObject = $this->userManager->get($cloudId); | $userObject = $this->userManager->get($cloudId); | ||||
if($cloudId !== null) { | |||||
if($userObject !== null) { | |||||
$key = $this->keyManager->getKey($userObject); | $key = $this->keyManager->getKey($userObject); | ||||
$data = [ | $data = [ | ||||
'public' => $key->getPublic(), | 'public' => $key->getPublic(), | ||||
return new DataResponse($data); | return new DataResponse($data); | ||||
} | } | ||||
return new DataResponse(101); | |||||
return new DataResponse('User not found', 404); | |||||
} | } | ||||
} | } |
} | } | ||||
/** | /** | ||||
* Generate a key for $user | |||||
* Note: If a key already exists it will be overwritten | |||||
* Calls the openssl functions to generate a public and private key. | |||||
* In a separate function for unit testing purposes. | |||||
* | * | ||||
* @param IUser $user | |||||
* @return Key | |||||
* @return array [$publicKey, $privateKey] | |||||
*/ | */ | ||||
public function generateKey(IUser $user) { | |||||
protected function generateKeyPair() { | |||||
$config = [ | $config = [ | ||||
'digest_alg' => 'sha512', | 'digest_alg' => 'sha512', | ||||
'private_key_bits' => 2048, | 'private_key_bits' => 2048, | ||||
$publicKey = openssl_pkey_get_details($res); | $publicKey = openssl_pkey_get_details($res); | ||||
$publicKey = $publicKey['key']; | $publicKey = $publicKey['key']; | ||||
return [$publicKey, $privateKey]; | |||||
} | |||||
/** | |||||
* Generate a key for $user | |||||
* Note: If a key already exists it will be overwritten | |||||
* | |||||
* @param IUser $user | |||||
* @return Key | |||||
*/ | |||||
protected function generateKey(IUser $user) { | |||||
list($publicKey, $privateKey) = $this->generateKeyPair(); | |||||
// Write the private and public key to the disk | // Write the private and public key to the disk | ||||
$this->appData->getFolder($user->getUID())->newFile('private') | |||||
try { | |||||
$this->appData->newFolder($user->getUID()); | |||||
} catch (\Exception $e) {} | |||||
$folder = $this->appData->getFolder($user->getUID()); | |||||
$folder->newFile('private') | |||||
->putContent($this->crypto->encrypt($privateKey)); | ->putContent($this->crypto->encrypt($privateKey)); | ||||
$this->appData->getFolder($user->getUID())->newFile('public') | |||||
$folder->newFile('public') | |||||
->putContent($publicKey); | ->putContent($publicKey); | ||||
return new Key($publicKey, $privateKey); | return new Key($publicKey, $privateKey); | ||||
*/ | */ | ||||
public function getKey(IUser $user) { | public function getKey(IUser $user) { | ||||
try { | try { | ||||
$privateKey = $this->crypto->decrypt($this->appData->getFolder($user->getUID())->getFile('private')->getContent()); | |||||
$publicKey = $this->appData->getFolder($user->getUID())->getFile('public')->getContent(); | |||||
$folder = $this->appData->getFolder($user->getUID()); | |||||
$privateKey = $this->crypto->decrypt( | |||||
$folder->getFile('private')->getContent() | |||||
); | |||||
$publicKey = $folder->getFile('public')->getContent(); | |||||
return new Key($publicKey, $privateKey); | return new Key($publicKey, $privateKey); | ||||
} catch (\Exception $e) { | } catch (\Exception $e) { | ||||
return $this->generateKey($user); | return $this->generateKey($user); |
<?php | |||||
/** | |||||
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* 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 | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace OC\Security\IdentityProof; | |||||
use OCP\AppFramework\Utility\ITimeFactory; | |||||
use OCP\IURLGenerator; | |||||
use OCP\IUser; | |||||
use OCP\IUserManager; | |||||
class Signer { | |||||
/** @var Manager */ | |||||
private $keyManager; | |||||
/** @var ITimeFactory */ | |||||
private $timeFactory; | |||||
/** @var IURLGenerator */ | |||||
private $urlGenerator; | |||||
/** @var IUserManager */ | |||||
private $userManager; | |||||
/** | |||||
* @param Manager $keyManager | |||||
* @param ITimeFactory $timeFactory | |||||
* @param IURLGenerator $urlGenerator | |||||
* @param IUserManager $userManager | |||||
*/ | |||||
public function __construct(Manager $keyManager, | |||||
ITimeFactory $timeFactory, | |||||
IURLGenerator $urlGenerator, | |||||
IUserManager $userManager) { | |||||
$this->keyManager = $keyManager; | |||||
$this->timeFactory = $timeFactory; | |||||
$this->userManager = $userManager; | |||||
} | |||||
/** | |||||
* Returns a signed blob for $data | |||||
* | |||||
* @param string $type | |||||
* @param array $data | |||||
* @param IUser $user | |||||
* @return array ['message', 'signature'] | |||||
*/ | |||||
public function sign($type, array $data, IUser $user) { | |||||
$privateKey = $this->keyManager->getKey($user)->getPrivate(); | |||||
$data = [ | |||||
'data' => $data, | |||||
'type' => $type, | |||||
'signer' => $user->getCloudId(), | |||||
'timestamp' => $this->timeFactory->getTime(), | |||||
]; | |||||
openssl_sign(json_encode($data), $signature, $privateKey, OPENSSL_ALGO_SHA512); | |||||
return [ | |||||
'message' => $data, | |||||
'signature' => base64_encode($signature), | |||||
]; | |||||
} | |||||
/** | |||||
* @param string $url | |||||
* @return string | |||||
*/ | |||||
private function removeProtocolFromUrl($url) { | |||||
if (strpos($url, 'https://') === 0) { | |||||
return substr($url, strlen('https://')); | |||||
} else if (strpos($url, 'http://') === 0) { | |||||
return substr($url, strlen('http://')); | |||||
} | |||||
return $url; | |||||
} | |||||
/** | |||||
* Whether the data is signed properly | |||||
* | |||||
* @param array $data | |||||
* @return bool | |||||
*/ | |||||
public function verify(array $data) { | |||||
if(isset($data['message']) | |||||
&& isset($data['signature']) | |||||
&& isset($data['message']['signer']) | |||||
) { | |||||
$server = $this->urlGenerator->getAbsoluteURL('/'); | |||||
$postfix = strlen('@' . rtrim($this->removeProtocolFromUrl($server), '/')); | |||||
$userId = substr($data['message']['signer'], -$postfix); | |||||
$user = $this->userManager->get($userId); | |||||
if($user !== null) { | |||||
$key = $this->keyManager->getKey($user); | |||||
return (bool)openssl_verify( | |||||
json_encode($data['message']), | |||||
base64_decode($data['signature']), | |||||
$key->getPublic() | |||||
); | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
} |
* @return DataResponse | * @return DataResponse | ||||
*/ | */ | ||||
public function setUserSettings($avatarScope, | public function setUserSettings($avatarScope, | ||||
$displayname, $displaynameScope, | |||||
$phone, $phoneScope, | |||||
$email, $emailScope, | |||||
$website, $websiteScope, | |||||
$address, $addressScope, | |||||
$twitter, $twitterScope | |||||
$displayname, | |||||
$displaynameScope, | |||||
$phone, | |||||
$phoneScope, | |||||
$email, | |||||
$emailScope, | |||||
$website, | |||||
$websiteScope, | |||||
$address, | |||||
$addressScope, | |||||
$twitter, | |||||
$twitterScope | |||||
) { | ) { | ||||
'appforgroup2', | 'appforgroup2', | ||||
'dav', | 'dav', | ||||
'federatedfilesharing', | 'federatedfilesharing', | ||||
'lookup_server_connector', | |||||
'provisioning_api', | 'provisioning_api', | ||||
'twofactor_backupcodes', | 'twofactor_backupcodes', | ||||
'workflowengine', | 'workflowengine', |
<?php | |||||
/** | |||||
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> | |||||
* | |||||
* @license GNU AGPL version 3 or any later version | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Affero General Public License as | |||||
* published by the Free Software Foundation, either version 3 of the | |||||
* License, or (at your option) any later version. | |||||
* | |||||
* 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 | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
namespace Test\Security; | |||||
use OC\Security\IdentityProof\Key; | |||||
use OC\Security\IdentityProof\Manager; | |||||
use OCP\Files\IAppData; | |||||
use OCP\Files\SimpleFS\ISimpleFile; | |||||
use OCP\Files\SimpleFS\ISimpleFolder; | |||||
use OCP\IUser; | |||||
use OCP\Security\ICrypto; | |||||
use Test\TestCase; | |||||
class ManagerTest extends TestCase { | |||||
/** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */ | |||||
private $appData; | |||||
/** @var ICrypto|\PHPUnit_Framework_MockObject_MockObject */ | |||||
private $crypto; | |||||
/** @var Manager|\PHPUnit_Framework_MockObject_MockObject */ | |||||
private $manager; | |||||
public function setUp() { | |||||
parent::setUp(); | |||||
$this->appData = $this->createMock(IAppData::class); | |||||
$this->crypto = $this->createMock(ICrypto::class); | |||||
$this->manager = $this->getMockBuilder(Manager::class) | |||||
->setConstructorArgs([ | |||||
$this->appData, | |||||
$this->crypto | |||||
]) | |||||
->setMethods(['generateKeyPair']) | |||||
->getMock(); | |||||
} | |||||
public function testGetKeyWithExistingKey() { | |||||
$user = $this->createMock(IUser::class); | |||||
$user | |||||
->expects($this->once()) | |||||
->method('getUID') | |||||
->willReturn('MyUid'); | |||||
$folder = $this->createMock(ISimpleFolder::class); | |||||
$privateFile = $this->createMock(ISimpleFile::class); | |||||
$privateFile | |||||
->expects($this->once()) | |||||
->method('getContent') | |||||
->willReturn('EncryptedPrivateKey'); | |||||
$publicFile = $this->createMock(ISimpleFile::class); | |||||
$publicFile | |||||
->expects($this->once()) | |||||
->method('getContent') | |||||
->willReturn('MyPublicKey'); | |||||
$this->crypto | |||||
->expects($this->once()) | |||||
->method('decrypt') | |||||
->with('EncryptedPrivateKey') | |||||
->willReturn('MyPrivateKey'); | |||||
$folder | |||||
->expects($this->at(0)) | |||||
->method('getFile') | |||||
->with('private') | |||||
->willReturn($privateFile); | |||||
$folder | |||||
->expects($this->at(1)) | |||||
->method('getFile') | |||||
->with('public') | |||||
->willReturn($publicFile); | |||||
$this->appData | |||||
->expects($this->once()) | |||||
->method('getFolder') | |||||
->with('MyUid') | |||||
->willReturn($folder); | |||||
$expected = new Key('MyPublicKey', 'MyPrivateKey'); | |||||
$this->assertEquals($expected, $this->manager->getKey($user)); | |||||
} | |||||
public function testGetKeyWithNotExistingKey() { | |||||
$user = $this->createMock(IUser::class); | |||||
$user | |||||
->expects($this->exactly(3)) | |||||
->method('getUID') | |||||
->willReturn('MyUid'); | |||||
$this->appData | |||||
->expects($this->at(0)) | |||||
->method('getFolder') | |||||
->with('MyUid') | |||||
->willThrowException(new \Exception()); | |||||
$this->manager | |||||
->expects($this->once()) | |||||
->method('generateKeyPair') | |||||
->willReturn(['MyNewPublicKey', 'MyNewPrivateKey']); | |||||
$this->appData | |||||
->expects($this->at(1)) | |||||
->method('newFolder') | |||||
->with('MyUid'); | |||||
$folder = $this->createMock(ISimpleFolder::class); | |||||
$this->crypto | |||||
->expects($this->once()) | |||||
->method('encrypt') | |||||
->with('MyNewPrivateKey') | |||||
->willReturn('MyNewEncryptedPrivateKey'); | |||||
$privateFile = $this->createMock(ISimpleFile::class); | |||||
$privateFile | |||||
->expects($this->once()) | |||||
->method('putContent') | |||||
->with('MyNewEncryptedPrivateKey'); | |||||
$publicFile = $this->createMock(ISimpleFile::class); | |||||
$publicFile | |||||
->expects($this->once()) | |||||
->method('putContent') | |||||
->with('MyNewPublicKey'); | |||||
$folder | |||||
->expects($this->at(0)) | |||||
->method('newFile') | |||||
->with('private') | |||||
->willReturn($privateFile); | |||||
$folder | |||||
->expects($this->at(1)) | |||||
->method('newFile') | |||||
->with('public') | |||||
->willReturn($publicFile); | |||||
$this->appData | |||||
->expects($this->at(2)) | |||||
->method('getFolder') | |||||
->with('MyUid') | |||||
->willReturn($folder); | |||||
$expected = new Key('MyNewPublicKey', 'MyNewPrivateKey'); | |||||
$this->assertEquals($expected, $this->manager->getKey($user)); | |||||
} | |||||
public function testGenerateKeyPair() { | |||||
$manager = new Manager( | |||||
$this->appData, | |||||
$this->crypto | |||||
); | |||||
$data = 'MyTestData'; | |||||
list($resultPublicKey, $resultPrivateKey) = $this->invokePrivate($manager, 'generateKeyPair'); | |||||
openssl_sign($data, $signature, $resultPrivateKey); | |||||
$details = openssl_pkey_get_details(openssl_pkey_get_public($resultPublicKey)); | |||||
$this->assertSame(1, openssl_verify($data, $signature, $resultPublicKey)); | |||||
$this->assertSame(2048, $details['bits']); | |||||
} | |||||
} |