From f0c4c64b849bb1de45ec702a56cd195801096901 Mon Sep 17 00:00:00 2001 From: Tim van Dijen <tim.dijen@minbzk.nl> Date: Mon, 18 Feb 2019 10:26:03 +0100 Subject: [PATCH] Externalize CDC-module --- bin/build-release.sh | 5 +- modules/cdc/config-templates/module_cdc.php | 22 - modules/cdc/default-disable | 3 - modules/cdc/lib/Auth/Process/CDC.php | 74 ---- modules/cdc/lib/Client.php | 70 ---- modules/cdc/lib/Server.php | 426 -------------------- modules/cdc/www/resume.php | 20 - modules/cdc/www/server.php | 3 - 8 files changed, 3 insertions(+), 620 deletions(-) delete mode 100644 modules/cdc/config-templates/module_cdc.php delete mode 100644 modules/cdc/default-disable delete mode 100644 modules/cdc/lib/Auth/Process/CDC.php delete mode 100644 modules/cdc/lib/Client.php delete mode 100644 modules/cdc/lib/Server.php delete mode 100644 modules/cdc/www/resume.php delete mode 100644 modules/cdc/www/server.php diff --git a/bin/build-release.sh b/bin/build-release.sh index 57d4421d4..344a6380e 100755 --- a/bin/build-release.sh +++ b/bin/build-release.sh @@ -44,11 +44,12 @@ fi php "$TARGET/composer.phar" install --no-dev --prefer-dist -o -d "$TARGET" # Install external modules +php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-cdc php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-memcookie -php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-riak php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-oauth +php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-riak -cd $TARGET +cd $TARGET npm install npm audit fix npm run build diff --git a/modules/cdc/config-templates/module_cdc.php b/modules/cdc/config-templates/module_cdc.php deleted file mode 100644 index 411bbc471..000000000 --- a/modules/cdc/config-templates/module_cdc.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -$config = [ - 'example.org' => [ - /* - * The shared key for this CDC server. - */ - 'key' => 'ExampleSharedKey', - - /* - * The URL to the server script. - */ - 'server' => 'https://my-cdc.example.org/simplesaml/module.php/cdc/server.php', - - /* - * The lifetime of our cookie, in seconds. - * - * If this is 0, the cookie will expire when the browser is closed. - */ - 'cookie.lifetime' => 0, - ], -]; diff --git a/modules/cdc/default-disable b/modules/cdc/default-disable deleted file mode 100644 index fa0bd82e2..000000000 --- a/modules/cdc/default-disable +++ /dev/null @@ -1,3 +0,0 @@ -This file indicates that the default state of this module -is disabled. To enable, create a file named enable in the -same directory as this file. diff --git a/modules/cdc/lib/Auth/Process/CDC.php b/modules/cdc/lib/Auth/Process/CDC.php deleted file mode 100644 index bf2a669d6..000000000 --- a/modules/cdc/lib/Auth/Process/CDC.php +++ /dev/null @@ -1,74 +0,0 @@ -<?php - -namespace SimpleSAML\module\cdc\Auth\Process; - -/** - * Filter for setting the SAML 2 common domain cookie. - * - * @package SimpleSAMLphp - */ - -class CDC extends \SimpleSAML\Auth\ProcessingFilter -{ - /** - * Our CDC domain. - * - * @var string - */ - private $domain; - - - /** - * Our CDC client. - * - * @var \SimpleSAML\Module\cdc\Client - */ - private $client; - - - /** - * Initialize this filter. - * - * @param array $config Configuration information about this filter. - * @param mixed $reserved For future use. - */ - public function __construct($config, $reserved) - { - parent::__construct($config, $reserved); - assert(is_array($config)); - - if (!isset($config['domain'])) { - throw new \SimpleSAML\Error\Exception('Missing domain option in cdc:CDC filter.'); - } - $this->domain = (string) $config['domain']; - - $this->client = new \SimpleSAML\Module\cdc\Client($this->domain); - } - - - /** - * Redirect to page setting CDC. - * - * @param array &$state The request state. - */ - public function process(&$state) - { - assert(is_array($state)); - - if (!isset($state['Source']['entityid'])) { - \SimpleSAML\Logger::warning('saml:CDC: Could not find IdP entityID.'); - return; - } - - // Save state and build request - $id = \SimpleSAML\Auth\State::saveState($state, 'cdc:resume'); - - $returnTo = \SimpleSAML\Module::getModuleURL('cdc/resume.php', ['domain' => $this->domain]); - - $params = [ - 'id' => $id, - 'entityID' => $state['Source']['entityid'], - ]; - $this->client->sendRequest($returnTo, 'append', $params); - } -} diff --git a/modules/cdc/lib/Client.php b/modules/cdc/lib/Client.php deleted file mode 100644 index 609aef63f..000000000 --- a/modules/cdc/lib/Client.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php - -namespace SimpleSAML\Module\cdc; - -/** - * CDC client class. - * - * @package SimpleSAMLphp - */ - -class Client -{ - /** - * Our CDC domain. - * - * @var string - */ - private $domain; - - - /** - * The CDC server we send requests to. - * - * @var Server|NULL - */ - private $server; - - - /** - * Initialize a CDC client. - * - * @param string $domain The domain we should query the server for. - */ - public function __construct($domain) - { - assert(is_string($domain)); - - $this->domain = $domain; - $this->server = new Server($domain); - } - - - /** - * Receive a CDC response. - * - * @return array|NULL The response, or NULL if no response is received. - */ - public function getResponse() - { - return $this->server->getResponse(); - } - - - /** - * Send a request. - * - * @param string $returnTo The URL we should return to afterwards. - * @param string $op The operation we are performing. - * @param array $params Additional parameters. - */ - public function sendRequest($returnTo, $op, array $params = []) - { - assert(is_string($returnTo)); - assert(is_string($op)); - - $params['op'] = $op; - $params['return'] = $returnTo; - $this->server->sendRequest($params); - } -} diff --git a/modules/cdc/lib/Server.php b/modules/cdc/lib/Server.php deleted file mode 100644 index affcf668a..000000000 --- a/modules/cdc/lib/Server.php +++ /dev/null @@ -1,426 +0,0 @@ -<?php - -namespace SimpleSAML\Module\cdc; - -/** - * CDC server class. - * - * @package SimpleSAMLphp - */ - -class Server -{ - /** - * The domain. - * - * @var string - */ - private $domain; - - - /** - * The URL to the server. - * - * @var string - */ - private $server; - - - /** - * Our shared key. - * - * @var string - */ - private $key; - - - /** - * The lifetime of our cookie, in seconds. - * - * If this is 0, the cookie will expire when the browser is closed. - * - * @param int - */ - private $cookieLifetime; - - - /** - * Initialize a CDC server. - * - * @param string $domain The domain we are a server for. - */ - public function __construct($domain) - { - assert(is_string($domain)); - - $cdcConfig = \SimpleSAML\Configuration::getConfig('module_cdc.php'); - $config = $cdcConfig->getConfigItem($domain, null); - - if ($config === null) { - throw new \SimpleSAML\Error\Exception('Unknown CDC domain: '.var_export($domain, true)); - } - - $this->domain = $domain; - $this->server = $config->getString('server'); - $this->key = $config->getString('key'); - $this->cookieLifetime = $config->getInteger('cookie.lifetime', 0); - - if ($this->key === 'ExampleSharedKey') { - throw new \SimpleSAML\Error\Exception( - 'Key for CDC domain '.var_export($domain, true).' not changed from default.' - ); - } - } - - - /** - * Send a request to this CDC server. - * - * @param array $request The CDC request. - */ - public function sendRequest(array $request) - { - assert(isset($request['return'])); - assert(isset($request['op'])); - - $request['domain'] = $this->domain; - $this->send($this->server, 'CDCRequest', $request); - } - - - /** - * Parse and validate response received from a CDC server. - * - * @return array|NULL The response, or NULL if no response is received. - */ - public function getResponse() - { - $response = self::get('CDCResponse'); - if ($response === null) { - return null; - } - - if ($response['domain'] !== $this->domain) { - throw new \SimpleSAML\Error\Exception('Response received from wrong domain.'); - } - - $this->validate('CDCResponse'); - - return $response; - } - - - /** - * Parse and process a CDC request. - */ - public static function processRequest() - { - $request = self::get('CDCRequest'); - if ($request === null) { - throw new \SimpleSAML\Error\BadRequest('Missing "CDCRequest" parameter.'); - } - - $domain = $request['domain']; - $server = new Server($domain); - - $server->validate('CDCRequest'); - $server->handleRequest($request); - } - - - /** - * Handle a parsed CDC requst. - * - * @param array $request - */ - private function handleRequest(array $request) - { - if (!isset($request['op'])) { - throw new \SimpleSAML\Error\BadRequest('Missing "op" in CDC request.'); - } - $op = (string) $request['op']; - - \SimpleSAML\Logger::info('Received CDC request with "op": '.var_export($op, true)); - - if (!isset($request['return'])) { - throw new \SimpleSAML\Error\BadRequest('Missing "return" in CDC request.'); - } - $return = (string) $request['return']; - - switch ($op) { - case 'append': - $response = $this->handleAppend($request); - break; - case 'delete': - $response = $this->handleDelete($request); - break; - case 'read': - $response = $this->handleRead($request); - break; - default: - $response = 'unknown-op'; - } - - if (is_string($response)) { - $response = [ - 'status' => $response, - ]; - } - - $response['op'] = $op; - if (isset($request['id'])) { - $response['id'] = (string) $request['id']; - } - $response['domain'] = $this->domain; - - $this->send($return, 'CDCResponse', $response); - } - - - /** - * Handle an append request. - * - * @param array $request The request. - * @return string The response. - */ - private function handleAppend(array $request) - { - if (!isset($request['entityID'])) { - throw new \SimpleSAML\Error\BadRequest('Missing entityID in append request.'); - } - $entityID = (string) $request['entityID']; - - $list = $this->getCDC(); - - $prevIndex = array_search($entityID, $list, true); - if ($prevIndex !== false) { - unset($list[$prevIndex]); - } - $list[] = $entityID; - - $this->setCDC($list); - - return 'ok'; - } - - - /** - * Handle a delete request. - * - * @param array $request The request. - * @return string The response. - */ - private function handleDelete(array $request) - { - $params = [ - 'path' => '/', - 'domain' => '.'.$this->domain, - 'secure' => true, - 'httponly' => false, - ]; - - \SimpleSAML\Utils\HTTP::setCookie('_saml_idp', null, $params, false); - return 'ok'; - } - - - /** - * Handle a read request. - * - * @param array $request The request. - * @return array The response. - */ - private function handleRead(array $request) - { - $list = $this->getCDC(); - - return [ - 'status' => 'ok', - 'cdc' => $list, - ]; - } - - - /** - * Helper function for parsing and validating a CDC message. - * - * @param string $parameter The name of the query parameter. - * @return array|NULL The response, or NULL if no response is received. - */ - private static function get($parameter) - { - assert(is_string($parameter)); - - if (!isset($_REQUEST[$parameter])) { - return null; - } - $message = (string) $_REQUEST[$parameter]; - - $message = @base64_decode($message); - if ($message === false) { - throw new \SimpleSAML\Error\BadRequest('Error base64-decoding CDC message.'); - } - - $message = @json_decode($message, true); - if ($message === false) { - throw new \SimpleSAML\Error\BadRequest('Error json-decoding CDC message.'); - } - - if (!isset($message['timestamp'])) { - throw new \SimpleSAML\Error\BadRequest('Missing timestamp in CDC message.'); - } - $timestamp = (int) $message['timestamp']; - - if ($timestamp + 60 < time()) { - throw new \SimpleSAML\Error\BadRequest('CDC signature has expired.'); - } - if ($timestamp - 60 > time()) { - throw new \SimpleSAML\Error\BadRequest('CDC signature from the future.'); - } - - if (!isset($message['domain'])) { - throw new \SimpleSAML\Error\BadRequest('Missing domain in CDC message.'); - } - - return $message; - } - - - /** - * Helper function for validating the signature on a CDC message. - * - * Will throw an exception if the message is invalid. - * - * @param string $parameter The name of the query parameter. - */ - private function validate($parameter) - { - assert(is_string($parameter)); - assert(isset($_REQUEST[$parameter])); - - $message = (string) $_REQUEST[$parameter]; - - if (!isset($_REQUEST['Signature'])) { - throw new \SimpleSAML\Error\BadRequest('Missing Signature on CDC message.'); - } - $signature = (string) $_REQUEST['Signature']; - - $cSignature = $this->calcSignature($message); - if ($signature !== $cSignature) { - throw new \SimpleSAML\Error\BadRequest('Invalid signature on CDC message.'); - } - } - - - /** - * Helper function for sending CDC messages. - * - * @param string $to The URL the message should be delivered to. - * @param string $parameter The query parameter the message should be sent in. - * @param array $message The CDC message. - */ - private function send($to, $parameter, array $message) - { - assert(is_string($to)); - assert(is_string($parameter)); - - $message['timestamp'] = time(); - $message = json_encode($message); - $message = base64_encode($message); - - $signature = $this->calcSignature($message); - - $params = [ - $parameter => $message, - 'Signature' => $signature, - ]; - - $url = \SimpleSAML\Utils\HTTP::addURLParameters($to, $params); - if (strlen($url) < 2048) { - \SimpleSAML\Utils\HTTP::redirectTrustedURL($url); - } else { - \SimpleSAML\Utils\HTTP::submitPOSTData($to, $params); - } - } - - - /** - * Calculate the signature on the given message. - * - * @param string $rawMessage The base64-encoded message. - * @return string The signature. - */ - private function calcSignature($rawMessage) - { - assert(is_string($rawMessage)); - - return sha1($this->key.$rawMessage.$this->key); - } - - - /** - * Get the IdP entities saved in the common domain cookie. - * - * @return array List of IdP entities. - */ - private function getCDC() - { - if (!isset($_COOKIE['_saml_idp'])) { - return []; - } - - $ret = (string) $_COOKIE['_saml_idp']; - $ret = explode(' ', $ret); - foreach ($ret as &$idp) { - $idp = base64_decode($idp); - if ($idp === false) { - // Not properly base64 encoded - \SimpleSAML\Logger::warning('CDC - Invalid base64-encoding of CDC entry.'); - return []; - } - } - - return $ret; - } - - - /** - * Build a CDC cookie string. - * - * @param array $list The list of IdPs. - * @return string The CDC cookie value. - */ - private function setCDC(array $list) - { - foreach ($list as &$value) { - $value = base64_encode($value); - } - - $cookie = implode(' ', $list); - - while (strlen($cookie) > 4000) { - // The cookie is too long. Remove the oldest elements until it is short enough - $tmp = explode(' ', $cookie, 2); - if (count($tmp) === 1) { - /* - * We are left with a single entityID whose base64 - * representation is too long to fit in a cookie. - */ - break; - } - $cookie = $tmp[1]; - } - - $params = [ - 'lifetime' => $this->cookieLifetime, - 'path' => '/', - 'domain' => '.'.$this->domain, - 'secure' => true, - 'httponly' => false, - ]; - - \SimpleSAML\Utils\HTTP::setCookie('_saml_idp', $cookie, $params, false); - - return '_saml_idp'; - } -} diff --git a/modules/cdc/www/resume.php b/modules/cdc/www/resume.php deleted file mode 100644 index ebe6b1cc9..000000000 --- a/modules/cdc/www/resume.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -if (!array_key_exists('domain', $_REQUEST)) { - throw new \SimpleSAML\Error\BadRequest('Missing domain to CDC resume handler.'); -} - -$domain = (string) $_REQUEST['domain']; -$client = new \SimpleSAML\Module\cdc\Client($domain); - -$response = $client->getResponse(); -if ($response === null) { - throw new \SimpleSAML\Error\BadRequest('Missing CDC response to CDC resume handler.'); -} - -if (!isset($response['id'])) { - throw new \SimpleSAML\Error\BadRequest('CDCResponse without id.'); -} -$state = \SimpleSAML\Auth\State::loadState($response['id'], 'cdc:resume'); - -\SimpleSAML\Auth\ProcessingChain::resumeProcessing($state); diff --git a/modules/cdc/www/server.php b/modules/cdc/www/server.php deleted file mode 100644 index d5cfd16ec..000000000 --- a/modules/cdc/www/server.php +++ /dev/null @@ -1,3 +0,0 @@ -<?php - -\SimpleSAML\Module\cdc\Server::processRequest(); -- GitLab