Actually convert the token

* When getting the token
* When rotating the token

* Also store the encrypted password as base64 to avoid weird binary
stuff

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
This commit is contained in:
Roeland Jago Douma 2018-05-31 21:56:17 +02:00
parent d03d16a936
commit f168ecfa7a
No known key found for this signature in database
GPG Key ID: F941078878347C0C
3 changed files with 94 additions and 40 deletions

View File

@ -121,8 +121,19 @@ class Manager implements IProvider {
try {
return $this->publicKeyTokenProvider->getToken($tokenId);
} catch (InvalidTokenException $e) {
return $this->defaultTokenProvider->getToken($tokenId);
// No worries we try to convert it to a PublicKey Token
}
//Convert!
$token = $this->defaultTokenProvider->getToken($tokenId);
try {
$password = $this->defaultTokenProvider->getPassword($token, $tokenId);
} catch (PasswordlessTokenException $e) {
$password = null;
}
return $this->publicKeyTokenProvider->convertToken($token, $tokenId, $password);
}
/**
@ -149,7 +160,6 @@ class Manager implements IProvider {
try {
$this->publicKeyTokenProvider->renewSessionToken($oldSessionId, $sessionId);
} catch (InvalidTokenException $e) {
//TODO: Move to new token
$this->defaultTokenProvider->renewSessionToken($oldSessionId, $sessionId);
}
}
@ -163,7 +173,6 @@ class Manager implements IProvider {
*/
public function getPassword(IToken $savedToken, string $tokenId): string {
if ($savedToken instanceof DefaultToken) {
//TODO convert to new token type
return $this->defaultTokenProvider->getPassword($savedToken, $tokenId);
}
@ -173,9 +182,7 @@ class Manager implements IProvider {
}
public function setPassword(IToken $token, string $tokenId, string $password) {
if ($token instanceof DefaultToken) {
//TODO conver to new token
$this->defaultTokenProvider->setPassword($token, $tokenId, $password);
}
@ -200,10 +207,14 @@ class Manager implements IProvider {
}
public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
if ($token instanceof DefaultToken) {
//TODO Migrate to new token
return $this->defaultTokenProvider->rotate($token, $oldTokenId, $newTokenId);
try {
$password = $this->defaultTokenProvider->getPassword($token, $oldTokenId);
} catch (PasswordlessTokenException $e) {
$password = null;
}
return $this->publicKeyTokenProvider->convertToken($token, $newTokenId, $password);
}
if ($token instanceof PublicKeyToken) {

View File

@ -159,4 +159,12 @@ class PublicKeyTokenMapper extends QBMapper {
$qb->execute();
}
public function deleteTempToken(PublicKeyToken $except) {
$qb = $this->db->getQueryBuilder();
$qb->delete('authtoken')
->where($qb->expr()->eq('type', $qb->createNamedParameter(IToken::TEMPORARY_TOKEN)))
->andWhere($qb->expr()->neq('id', $qb->createNamedParameter($except->getId())))
->andWhere($qb->expr()->eq('version', $qb->createNamedParameter(2, IQueryBuilder::PARAM_INT)));
}
}

View File

@ -67,36 +67,7 @@ class PublicKeyTokenProvider implements IProvider {
string $name,
int $type = IToken::TEMPORARY_TOKEN,
int $remember = IToken::DO_NOT_REMEMBER): IToken {
$dbToken = new PublicKeyToken();
$dbToken->setUid($uid);
$dbToken->setLoginName($loginName);
$config = [
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
];
// Generate new key
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $privateKey);
// Extract the public key from $res to $pubKey
$publicKey = openssl_pkey_get_details($res);
$publicKey = $publicKey['key'];
$dbToken->setPublicKey($publicKey);
$dbToken->setPrivateKey($this->encrypt($privateKey, $token));
if (!is_null($password)) {
$dbToken->setPassword($this->encryptPassword($password, $publicKey));
}
$dbToken->setName($name);
$dbToken->setToken($this->hashToken($token));
$dbToken->setType($type);
$dbToken->setRemember($remember);
$dbToken->setLastActivity($this->time->getTime());
$dbToken->setLastCheck($this->time->getTime());
$dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember);
$this->mapper->insert($dbToken);
@ -219,6 +190,9 @@ class PublicKeyTokenProvider implements IProvider {
throw new InvalidTokenException();
}
// When changeing passwords all temp tokens are deleted
$this->mapper->deleteTempToken($token);
// Update the password for all tokens
$tokens = $this->mapper->getTokenByUser($token->getUID());
foreach ($tokens as $t) {
@ -226,8 +200,6 @@ class PublicKeyTokenProvider implements IProvider {
$t->setPassword($this->encryptPassword($password, $publicKey));
$this->updateToken($t);
}
//TODO: should we also do this for temp tokens?
}
public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
@ -267,11 +239,13 @@ class PublicKeyTokenProvider implements IProvider {
private function encryptPassword(string $password, string $publicKey): string {
openssl_public_encrypt($password, $encryptedPassword, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
$encryptedPassword = base64_encode($encryptedPassword);
return $encryptedPassword;
}
private function decryptPassword(string $encryptedPassword, string $privateKey): string {
$encryptedPassword = base64_decode($encryptedPassword);
openssl_private_decrypt($encryptedPassword, $password, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
return $password;
@ -281,4 +255,65 @@ class PublicKeyTokenProvider implements IProvider {
$secret = $this->config->getSystemValue('secret');
return hash('sha512', $token . $secret);
}
/**
* Convert a DefaultToken to a publicKeyToken
* This will also be updated directly in the Database
*/
public function convertToken(DefaultToken $defaultToken, string $token, $password): PublicKeyToken {
$pkToken = $this->newToken(
$token,
$defaultToken->getUID(),
$defaultToken->getLoginName(),
$password,
$defaultToken->getName(),
$defaultToken->getType(),
$defaultToken->getRemember()
);
$pkToken->setId($defaultToken->getId());
return $this->mapper->update($pkToken);
}
private function newToken(string $token,
string $uid,
string $loginName,
$password,
string $name,
int $type,
int $remember): PublicKeyToken {
$dbToken = new PublicKeyToken();
$dbToken->setUid($uid);
$dbToken->setLoginName($loginName);
$config = [
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
];
// Generate new key
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $privateKey);
// Extract the public key from $res to $pubKey
$publicKey = openssl_pkey_get_details($res);
$publicKey = $publicKey['key'];
$dbToken->setPublicKey($publicKey);
$dbToken->setPrivateKey($this->encrypt($privateKey, $token));
if (!is_null($password)) {
$dbToken->setPassword($this->encryptPassword($password, $publicKey));
}
$dbToken->setName($name);
$dbToken->setToken($this->hashToken($token));
$dbToken->setType($type);
$dbToken->setRemember($remember);
$dbToken->setLastActivity($this->time->getTime());
$dbToken->setLastCheck($this->time->getTime());
return $dbToken;
}
}