xero-8.x-2.x-dev/src/Controller/XeroAuthorizeController.php
src/Controller/XeroAuthorizeController.php
<?php
namespace Drupal\xero\Controller;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\Url;
use Drupal\Core\Utility\Error;
use Drupal\xero\Exception\XeroCsrfTokenException;
use Drupal\xero\XeroTokenManagerInterface;
use GuzzleHttp\ClientInterface;
use Radcliffe\Xero\XeroProvider;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
/**
* Xero authorize controller.
*
* @internal
*/
class XeroAuthorizeController implements ContainerInjectionInterface {
use StringTranslationTrait;
/**
* The user account.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $account;
/**
* Xero configuration.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $config;
/**
* Configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Messenger interface.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* The Xero token manager.
*
* @var \Drupal\xero\XeroTokenManagerInterface
*/
protected $tokenManager;
/**
* An Http client for Xero provider.
*
* @var \GuzzleHttp\ClientInterface
*/
protected $httpClient;
/**
* Logger channel for Xero module.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* The private temp store.
*
* @var \Drupal\Core\TempStore\PrivateTempStore
*/
protected $tempStore;
/**
* Initialization method.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* The config.factory service.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger service.
* @param \Drupal\Core\Session\AccountProxyInterface $account
* The current_user service.
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempStoreFactory
* The tempstore.private service.
* @param \Drupal\xero\XeroTokenManagerInterface $tokenManager
* The xero.token.manager service.
* @param \GuzzleHttp\ClientInterface $httpClient
* A standard http_client to use for XeroProvider.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
* Logger channel factory for logging.
*/
public function __construct(ConfigFactoryInterface $configFactory, MessengerInterface $messenger, AccountProxyInterface $account, PrivateTempStoreFactory $tempStoreFactory, XeroTokenManagerInterface $tokenManager, ClientInterface $httpClient, LoggerChannelFactoryInterface $loggerFactory) {
$this->config = $configFactory->get('xero.settings');
$this->configFactory = $configFactory;
$this->messenger = $messenger;
$this->account = $account;
$this->tokenManager = $tokenManager;
$this->httpClient = $httpClient;
$this->logger = $loggerFactory->get('xero');
$this->tempStore = $tempStoreFactory->get('xero.auth');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('messenger'),
$container->get('current_user'),
$container->get('tempstore.private'),
$container->get('xero.token_manager'),
$container->get('http_client'),
$container->get('logger.factory')
);
}
/**
* Queries Xero for data filtered by the data type name.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The Symfony Request object.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* A redirect response.
*
* @throws \Exception
*/
public function authorize(Request $request) {
$code = $request->query->get('code');
$state = $request->query->get('state');
$route = $request->query->get('destination');
$global = $this->tempStore->get('global');
try {
$storedState = $this->tempStore->get('state');
if ($state !== $storedState) {
$this->clearState();
$this->logger->debug('Xero CSRF Token validation failed: @state != @stored', [
'@state' => $state,
'@stored' => $storedState,
]);
throw new XeroCsrfTokenException($this->t('The xero.authorize route was visited with a cross-site request forgery token that is not valid for this session.'));
}
$provider = new XeroProvider([
'clientId' => $this->config->get('oauth.consumer_key'),
'clientSecret' => $this->config->get('oauth.consumer_secret'),
'redirectUri' => $this->config->get('oauth.redirect_uri'),
]);
$provider->setHttpClient($this->httpClient);
$accessToken = $provider->getAccessToken('authorization_code', ['code' => $code]);
// Get the organisations for the user.
$response = $this->httpClient->request('GET',
'https://api.xero.com/connections',
[
'headers' => [
'Authorization' => 'Bearer ' . $accessToken->getToken(),
],
]);
$organisations = json_decode($response->getBody()->getContents(), TRUE);
if (!is_null($global) && $global) {
$this->tokenManager->setToken($accessToken, NULL, $organisations);
$this->messenger->addStatus($this->t('Successfully authenticated with Xero. This site is now authorized to use the Xero API.'));
}
else {
$this->tokenManager->setToken($accessToken, $this->account, $organisations);
$this->messenger->addStatus($this->t('Successfully authenticated your user account with Xero.'));
}
$this->clearState();
}
catch (\Exception $e) {
$variables = Error::decodeException($e);
$this->logger->error('%type: @message in %function (line %line of %file', $variables);
$this->messenger->addError($this->t('An error occurred authenticating with Xero or the Xero authorisation url was accessed improperly. Please see the web site logs for more details.'));
$this->clearState();
}
$url = $route ? Url::fromRoute($route) : Url::fromRoute('<front>');
return new RedirectResponse($url->toString());
}
/**
* Clears temporary storage.
*
* @throws \Drupal\Core\TempStore\TempStoreException
*/
protected function clearState() {
$this->tempStore->delete('state');
$this->tempStore->delete('global');
}
}
