View source
<?php
namespace Drupal\cas\Service;
use Drupal\cas\CasServerConfig;
use Drupal\Core\Config\ConfigFactoryInterface;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use Drupal\Component\Utility\UrlHelper;
use GuzzleHttp\Cookie\CookieJar;
use Drupal\cas\Exception\CasProxyException;
use Psr\Log\LogLevel;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Drupal\Core\Database\Connection;
class CasProxyHelper {
protected $httpClient;
protected $casHelper;
protected $session;
protected $settings;
protected $connection;
public function __construct(Client $http_client, CasHelper $cas_helper, SessionInterface $session, ConfigFactoryInterface $config_factory, Connection $database_connection) {
$this->httpClient = $http_client;
$this->casHelper = $cas_helper;
$this->session = $session;
$this->settings = $config_factory
->get('cas.settings');
$this->connection = $database_connection;
}
private function getServerProxyUrl($target_service) {
$casServerConfig = CasServerConfig::createFromModuleConfig($this->settings);
$url = $casServerConfig
->getServerBaseUrl() . 'proxy';
$params = [];
$params['pgt'] = $this->session
->get('cas_pgt');
$params['targetService'] = $target_service;
return $url . '?' . UrlHelper::buildQuery($params);
}
public function getProxyTicket($target_service) {
if (!($this->settings
->get('proxy.initialize') && $this->session
->has('cas_pgt'))) {
throw new CasProxyException("Session state not sufficient for proxying.");
}
$cas_url = $this
->getServerProxyUrl($target_service);
try {
$this->casHelper
->log(LogLevel::DEBUG, "Retrieving proxy ticket from %cas_url", [
'%cas_url' => $cas_url,
]);
$casServerConfig = CasServerConfig::createFromModuleConfig($this->settings);
$casServerConnectionOptions = $casServerConfig
->getCasServerGuzzleConnectionOptions();
$response = $this->httpClient
->get($cas_url, $casServerConnectionOptions);
} catch (ClientException $e) {
throw new CasProxyException($e
->getMessage());
}
$proxy_ticket = $this
->parseProxyTicket($response
->getBody());
$this->casHelper
->log(LogLevel::DEBUG, "Extracted proxy ticket %ticket", [
'%ticket' => $proxy_ticket,
]);
return $proxy_ticket;
}
public function proxyAuthenticate($target_service) {
$cas_proxy_helper = $this->session
->get('cas_proxy_helper');
if (isset($cas_proxy_helper[$target_service])) {
$cookies = [];
foreach ($cas_proxy_helper[$target_service] as $cookie) {
$cookies[$cookie['Name']] = $cookie['Value'];
}
$domain = $cookie['Domain'];
$jar = CookieJar::fromArray($cookies, $domain);
$this->casHelper
->log(LogLevel::DEBUG, "%target_service already proxied. Returning information from session.", [
'%target_service' => $target_service,
]);
return $jar;
}
$params = [
'ticket' => $this
->getProxyTicket($target_service),
];
$service_url = $target_service . "?" . UrlHelper::buildQuery($params);
$cookie_jar = new CookieJar();
try {
$this->casHelper
->log(LogLevel::DEBUG, "Contacting service: %service", [
'%service' => $service_url,
]);
$this->httpClient
->get($service_url, [
'cookies' => $cookie_jar,
'timeout' => $this->settings
->get('advanced.connection_timeout'),
]);
} catch (ClientException $e) {
throw new CasProxyException($e
->getMessage());
}
$cas_proxy_helper[$target_service] = $cookie_jar
->toArray();
$this->session
->set('cas_proxy_helper', $cas_proxy_helper);
$this->casHelper
->log(LogLevel::DEBUG, "Stored cookies from %service in session.", [
'%service' => $target_service,
]);
return $cookie_jar;
}
private function parseProxyTicket($xml) {
$dom = new \DOMDocument();
$dom->preserveWhiteSpace = FALSE;
$dom->encoding = "utf-8";
if (@$dom
->loadXML($xml) === FALSE) {
throw new CasProxyException("CAS Server returned non-XML response.");
}
$failure_elements = $dom
->getElementsByTagName("proxyFailure");
if ($failure_elements->length > 0) {
throw new CasProxyException("CAS Server rejected proxy request.");
}
$success_elements = $dom
->getElementsByTagName("proxySuccess");
if ($success_elements->length === 0) {
throw new CasProxyException("CAS Server returned malformed response.");
}
$success_element = $success_elements
->item(0);
$proxy_ticket = $success_element
->getElementsByTagName("proxyTicket");
if ($proxy_ticket->length === 0) {
throw new CasProxyException("CAS Server provided invalid or malformed ticket.");
}
return $proxy_ticket
->item(0)->nodeValue;
}
public function storePgtSession($pgt_iou) {
$pgt = $this->connection
->select('cas_pgt_storage', 'c')
->fields('c', [
'pgt',
])
->condition('pgt_iou', $pgt_iou)
->execute()
->fetch()->pgt;
$this->session
->set('cas_pgt', $pgt);
$this->connection
->delete('cas_pgt_storage')
->condition('pgt_iou', $pgt_iou)
->execute();
}
}