external account changes

This commit is contained in:
Yuri Kuznetsov
2020-05-18 09:43:17 +03:00
parent bcc3cfd143
commit 1a06b83d9d
5 changed files with 91 additions and 37 deletions

View File

@@ -93,12 +93,7 @@ class ExternalAccount extends \Espo\Core\Controllers\Record
{
list($integration, $userId) = explode('__', $params['id']);
if ($this->getUser()->id != $userId && !$this->getUser()->isAdmin()) {
throw new Forbidden();
}
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']);
return $entity->toArray();
return $this->getRecordService()->read($params['id'])->getValueMap();
}
public function actionUpdate($params, $data, $request)

View File

@@ -69,11 +69,13 @@ class ClientManager
$externalAccountEntity = $this->clientMap[$hash]['externalAccountEntity'];
$externalAccountEntity->set('accessToken', $data['accessToken']);
$externalAccountEntity->set('tokenType', $data['tokenType']);
$externalAccountEntity->set('expiresAt', $data['expiresAt'] ?? null);
$copy = $this->getEntityManager()->getEntity('ExternalAccount', $externalAccountEntity->id);
if ($copy) {
$copy->set('accessToken', $data['accessToken']);
$copy->set('tokenType', $data['tokenType']);
$copy->set('expiresAt', $data['expiresAt'] ?? null);
$this->getEntityManager()->saveEntity($copy, ['isTokenRenewal' => true]);
}
}

View File

@@ -29,9 +29,9 @@
namespace Espo\Core\ExternalAccount\Clients;
use \Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\Error;
use \Espo\Core\ExternalAccount\OAuth2\Client;
use Espo\Core\ExternalAccount\OAuth2\Client;
abstract class OAuth2Abstract implements IClient
{
@@ -39,7 +39,7 @@ abstract class OAuth2Abstract implements IClient
protected $manager = null;
protected $paramList = array(
protected $paramList = [
'endpoint',
'tokenEndpoint',
'clientId',
@@ -48,7 +48,8 @@ abstract class OAuth2Abstract implements IClient
'accessToken',
'refreshToken',
'redirectUri',
);
'expiresAt',
];
protected $clientId = null;
@@ -60,7 +61,9 @@ abstract class OAuth2Abstract implements IClient
protected $redirectUri = null;
public function __construct($client, array $params = array(), $manager = null)
protected $expiresAt = null;
public function __construct($client, array $params = [], $manager = null)
{
$this->client = $client;
@@ -103,6 +106,25 @@ abstract class OAuth2Abstract implements IClient
}
}
protected function getAccessTokenDataFromResponseResult($result)
{
$data = [];
$data['accessToken'] = $result['access_token'];
$data['tokenType'] = $result['token_type'];
$data['expiresAt'] = null;
if (isset($result['expires_in']) && is_numeric($result['expires_in'])) {
$data['expiresAt'] = (new \DateTime())
->modify('+' . $result['expires_in'] . ' seconds')
->modify('-1 seconds')
->format('Y-m-d H:i:s');
}
return $data;
}
public function getAccessTokenFromAuthorizationCode($code)
{
$r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_AUTHORIZATION_CODE, [
@@ -111,15 +133,16 @@ abstract class OAuth2Abstract implements IClient
]);
if ($r['code'] == 200) {
$data = [];
if (!empty($r['result'])) {
$data['accessToken'] = $r['result']['access_token'];
$data['tokenType'] = $r['result']['token_type'];
$data = $this->getAccessTokenDataFromResponseResult($r['result']);
$data['refreshToken'] = $r['result']['refresh_token'];
return $data;
} else {
$GLOBALS['log']->debug("OAuth getAccessTokenFromAuthorizationCode; Response: " . json_encode($r));
return null;
}
return $data;
} else {
$GLOBALS['log']->debug("OAuth getAccessTokenFromAuthorizationCode; Response: " . json_encode($r));
}
@@ -193,15 +216,13 @@ abstract class OAuth2Abstract implements IClient
protected function refreshToken()
{
if (!empty($this->refreshToken)) {
$r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_REFRESH_TOKEN, array(
$r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_REFRESH_TOKEN, [
'refresh_token' => $this->refreshToken,
));
]);
if ($r['code'] == 200) {
if (is_array($r['result'])) {
if (!empty($r['result']['access_token'])) {
$data = array();
$data['accessToken'] = $r['result']['access_token'];
$data['tokenType'] = $r['result']['token_type'];
$data = $this->getAccessTokenDataFromResponseResult($r['result']);
$this->setParams($data);
$this->afterTokenRefreshed($data);
@@ -209,6 +230,11 @@ abstract class OAuth2Abstract implements IClient
}
}
}
$GLOBALS['log']->notice("Oauth: Refreshing token failed for client {$this->clientId}: " . json_encode($r));
} else {
$GLOBALS['log']->notice(
"Oauth: Could not refresh token for client {$this->clientId}, because refreshToken is empty.");
}
}
@@ -217,21 +243,20 @@ abstract class OAuth2Abstract implements IClient
if ($r['code'] == 401 && !empty($r['result'])) {
$result = $r['result'];
if (strpos($r['header'], 'error=invalid_token') !== false) {
return array(
return [
'action' => 'refreshToken'
);
];
} else {
return array(
return [
'action' => 'renew'
);
];
}
} else if ($r['code'] == 400 && !empty($r['result'])) {
if ($r['result']['error'] == 'invalid_token') {
return array(
return [
'action' => 'refreshToken'
);
];
}
}
}
}

View File

@@ -62,6 +62,8 @@ class Client
protected $accessToken = null;
protected $expiresAt = null;
protected $authType = self::AUTH_TYPE_URI;
protected $tokenType = self::TOKEN_TYPE_URI;
@@ -72,9 +74,9 @@ class Client
protected $certificateFile = null;
protected $curlOptions = array();
protected $curlOptions = [];
public function __construct(array $params = array())
public function __construct(array $params = [])
{
if (!extension_loaded('curl')) {
throw new \Exception('CURL extension not found.');
@@ -121,12 +123,17 @@ class Client
$this->tokenType = $tokenType;
}
public function setExpiresAt($value)
{
$this->expiresAt = $value;
}
public function setAccessTokenSecret($accessTokenSecret)
{
$this->accessTokenSecret = $accessTokenSecret;
}
public function request($url, $params = null, $httpMethod = self::HTTP_METHOD_GET, array $httpHeaders = array())
public function request($url, $params = null, $httpMethod = self::HTTP_METHOD_GET, array $httpHeaders = [])
{
if ($this->accessToken) {
switch ($this->tokenType) {
@@ -148,7 +155,7 @@ class Client
return $this->execute($url, $params, $httpMethod, $httpHeaders);
}
private function execute($url, $params = null, $httpMethod, array $httpHeaders = array())
private function execute($url, $params = null, $httpMethod, array $httpHeaders = [])
{
$curlOptions = array(
CURLOPT_RETURNTRANSFER => true,
@@ -243,7 +250,7 @@ class Client
{
$params['grant_type'] = $grantType;
$httpHeaders = array();
$httpHeaders = [];
switch ($this->tokenType) {
case self::AUTH_TYPE_URI:
case self::AUTH_TYPE_FORM:
@@ -261,4 +268,3 @@ class Client
return $this->execute($url, $params, self::HTTP_METHOD_POST, $httpHeaders);
}
}

View File

@@ -29,11 +29,11 @@
namespace Espo\Services;
use \Espo\ORM\Entity;
use Espo\ORM\Entity;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\NotFound;
use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\Exceptions\Forbidden;
class ExternalAccount extends Record
{
@@ -92,6 +92,7 @@ class ExternalAccount extends Record
$entity->clear('accessToken');
$entity->clear('refreshToken');
$entity->clear('tokenType');
$entity->clear('expiresAt');
foreach ($result as $name => $value) {
$entity->set($name, $value);
}
@@ -109,4 +110,29 @@ class ExternalAccount extends Record
throw new Error("Could not load client for {$integration}.");
}
}
public function read($id)
{
list($integration, $userId) = explode('__', $id);
if ($this->getUser()->id != $userId && !$this->getUser()->isAdmin()) {
throw new Forbidden();
}
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $id);
if (!$entity) throw new NotFoundSilent("Record does not exist.");
list($integration, $id) = explode('__', $entity->id);
$externalAccountSecretAttributeList = $this->getMetadata()->get(
['integrations', $integration, 'externalAccountSecretAttributeList']) ?? [];
foreach ($externalAccountSecretAttributeList as $a) {
$entity->clear($a);
}
return $entity;
}
}