Skip to content
Snippets Groups Projects
Commit f461c7bf authored by Tim van Dijen's avatar Tim van Dijen
Browse files

Migrate www-scripts to Controllers

parent c6ea0de0
Branches
Tags
No related merge requests found
<?php
declare(strict_types=1);
namespace SimpleSAML\Module\Controller;
use Exception;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\Metadata;
use SimpleSAML\Module;
use SimpleSAML\Module\saml\IdP\SAML2 as SAML2_IdP;
use SimpleSAML\Utils;
use Symfony\Component\HttpFoundation\Request;
use function strpos;
use function strrpos;
use function substr;
/**
* Controller class for the IdP metadata.
*
* This class serves the different views available.
*
* @package simplesamlphp/simplesamlphp
*/
class Metadata
{
/** @var \SimpleSAML\Configuration */
protected Configuration $config;
/** @var \SimpleSAML\Utils\Auth */
protected Utils\Auth $authUtils;
/**
* Controller constructor.
*
* It initializes the global configuration for the controllers implemented here.
*
* @param \SimpleSAML\Configuration $config The configuration to use by the controllers.
*/
public function __construct(
Configuration $config
) {
$this->config = $config;
$this->authUtils = new Utils\Auth();
}
/**
* Inject the \SimpleSAML\Utils\Auth dependency.
*
* @param \SimpleSAML\Utils\Auth $authUtils
*/
public function setAuthUtils(Utils\Auth $authUtils): void
{
$this->authUtils = $authUtils;
}
/**
* This endpoint will offer the SAML 2.0 IdP metadata.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \SimpleSAML\HTTP\RunnableResponse
*/
public function metadata(Request $request): RunnableResponse
{
if (!$this->config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
// check if valid local session exists
if ($config->getOptionalBoolean('admin.protectmetadata', false)) {
return new RunnableResponse([$this->authUtils, 'requireAdmin']);
}
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
try {
if ($request->query->has('idpentityid')) {
$idpentityid = $request->query->get('idpentityid');
} else {
$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
}
$metaArray = SAML2_IdP::getHostedMetadata($idpentityid);
$metaBuilder = new Metadata\SAMLBuilder($idpentityid);
$metaBuilder->addMetadataIdP20($metaArray);
$metaBuilder->addOrganizationInfo($metaArray);
$metaxml = $metaBuilder->getEntityDescriptorText();
// sign the metadata if enabled
$metaxml = Metadata\Signer::sign($metaxml, $metaArray, 'SAML 2 IdP');
// make sure to export only the md:EntityDescriptor
$i = strpos($metaxml, '<md:EntityDescriptor');
$metaxml = substr($metaxml, $i ? $i : 0);
// 22 = strlen('</md:EntityDescriptor>')
$i = strrpos($metaxml, '</md:EntityDescriptor>');
$metaxml = substr($metaxml, 0, $i ? $i + 22 : 0);
$response = new Response();
$response->headers->set('Content-Type', 'application/samlmetadata+xml');
$response->headers->set('Content-Disposition', 'attachment; filename="idp-metadata.xml"');
$response->setContent($metaxml);
return $response;
} catch (Exception $exception) {
throw new Error\Error('METADATA', $exception);
}
}
}
<?php
declare(strict_types=1);
namespace SimpleSAML\Module\Controller;
use SAML2\Exception\Protocol\UnsupportedBindingException;
use SimpleSAML\Assert\Assert;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\IdP;
use SimpleSAML\HTTP\RunnableResponse;
use SimpleSAML\Logger;
use SimpleSAML\Metadata;
use SimpleSAML\Module;
use SimpleSAML\Utils;
use Symfony\Component\HttpFoundation\Request;
/**
* Controller class for the Single Logout Profile.
*
* This class serves the different views available.
*
* @package simplesamlphp/simplesamlphp
*/
class SingleLogout
{
/** @var \SimpleSAML\Configuration */
protected Configuration $config;
/**
* Controller constructor.
*
* It initializes the global configuration for the controllers implemented here.
*
* @param \SimpleSAML\Configuration $config The configuration to use by the controllers.
*/
public function __construct(
Configuration $config
) {
$this->config = $config;
}
/**
* This SAML 2.0 endpoint can receive incoming LogoutRequests. It will also send LogoutResponses,
* and LogoutRequests and also receive LogoutResponses. It is implementing SLO at the SAML 2.0 IdP.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \SimpleSAML\HTTP\RunnableResponse
*/
public function singleLogout(Request $request): RunnableResponse
{
Logger::info('SAML2.0 - IdP.SingleLogoutService: Accessing SAML 2.0 IdP endpoint SingleLogoutService');
if (!$this->config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
$httpUtils = new Utils\HTTP();
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = IdP::getById('saml2:' . $idpEntityId);
if ($request->request->has('ReturnTo')) {
return new RunnableResponse(
[$idp, 'doLogoutRedirect'],
[$httpUtils->checkURLAllowed($request->request->get('ReturnTo'))]
);
} else {
try {
return new RunnableResponse([Module\saml\IdP\SAML2::class, 'receiveLogoutMessage'], [$idp]);
} catch (UnsupportedBindingException $e) {
throw new Error\Error('SLOSERVICEPARAMS', $e, 400);
}
}
Assert::true(false);
}
/**
* This endpoint will initialize the SLO flow at the SAML 2.0 IdP.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \SimpleSAML\HTTP\RunnableResponse
*/
public function initSingleLogout(Request $request): RunnableResponse
{
Logger::info('SAML2.0 - IdP.initSLO: Accessing SAML 2.0 IdP endpoint init Single Logout');
if (!$this->config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = IdP::getById('saml2:' . $idpEntityId);
if (!$request->query->has('RelayState')) {
throw new Error\Error('NORELAYSTATE');
}
$httpUtils = new Utils\HTTP();
return new RunnableResponse(
[$idp, 'doLogoutRedirect'],
[$httpUtils->checkURLAllowed($request->query->get('RelayState')]
);
}
}
<?php
declare(strict_types=1);
namespace SimpleSAML\Module\Controller;
use SAML2\Exception\Protocol\UnsupportedBindingException;
use SAML2\ArtifactResolve;
use SAML2\ArtifactResponse;
use SAML2\DOMDocumentFactory;
use SAML2\SOAP;
use SAML2\XML\saml\Issuer;
use SimpleSAML\Assert\Assert;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\IdP;
use SimpleSAML\HTTP\RunnableResponse;
use SimpleSAML\Logger;
use SimpleSAML\Metadata;
use SimpleSAML\Module;
use SimpleSAML\Store\StoreFactory;
/**
* Controller class for the Web Browser Single Sign On profile.
*
* This class serves the different views available.
*
* @package simplesamlphp/simplesamlphp
*/
class WebBrowserSingleSignOn
{
/** @var \SimpleSAML\Configuration */
protected Configuration $config;
/**
* Controller constructor.
*
* It initializes the global configuration for the controllers implemented here.
*
* @param \SimpleSAML\Configuration $config The configuration to use by the controllers.
*/
public function __construct(
Configuration $config
) {
$this->config = $config;
}
/**
* The ArtifactResolutionService receives the samlart from the sp.
* And when the artifact is found, it sends a \SAML2\ArtifactResponse.
*
* @return \SimpleSAML\HTTP\RunnableResponse
*/
public function artifactResolutionService(): RunnableResponse
{
if (!$this->config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-hosted');
if (!$idpMetadata->getOptionalBoolean('saml20.sendartifact', false)) {
throw new Error\Error('NOACCESS');
}
$storeType = $this->config->getOptionalString('store.type', 'phpsession');
$store = StoreFactory::getInstance($storeType);
if ($store === false) {
throw new Exception('Unable to send artifact without a datastore configured.');
}
$binding = new SOAP();
try {
$request = $binding->receive();
} catch (UnsupportedBindingException $e) {
throw new Error\Error('ARSPARAMS', $e, 400);
}
if (!($request instanceof ArtifactResolve)) {
throw new Exception('Message received on ArtifactResolutionService wasn\'t a ArtifactResolve request.');
}
$issuer = $request->getIssuer();
/** @psalm-assert \SAML2\XML\saml\Issuer $issuer */
Assert::notNull($issuer);
$issuer = $issuer->getValue();
$spMetadata = $metadata->getMetaDataConfig($issuer, 'saml20-sp-remote');
$artifact = $request->getArtifact();
$responseData = $store->get('artifact', $artifact);
$store->delete('artifact', $artifact);
if ($responseData !== null) {
$document = DOMDocumentFactory::fromString($responseData);
$responseXML = $document->documentElement;
} else {
$responseXML = null;
}
$artifactResponse = new ArtifactResponse();
$issuer = new Issuer();
$issuer->setValue($idpEntityId);
$artifactResponse->setIssuer($issuer);
$artifactResponse->setInResponseTo($request->getId());
$artifactResponse->setAny($responseXML);
Module\saml\Message::addSign($idpMetadata, $spMetadata, $artifactResponse);
return new RunnableResponse([$binding, 'send'], [$artifactResponse]);
}
/**
* The SSOService is part of the SAML 2.0 IdP code, and it receives incoming Authentication Requests
* from a SAML 2.0 SP, parses, and process it, and then authenticates the user and sends the user back
* to the SP with an Authentication Response.
*
* @return \SimpleSAML\HTTP\RunnableResponse
*/
public function singleSignOnService(): RunnableResponse
{
Logger::info('SAML2.0 - IdP.SSOService: Accessing SAML 2.0 IdP endpoint SSOService');
if (!$this->config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = IdP::getById('saml2:' . $idpEntityId);
try {
return new RunnableResponse([Module\saml\IdP\SAML2::class, 'receiveAuthnRequest'], [$idp]);
} catch (UnsupportedBindingException $e) {
throw new Error\Error('SSOPARAMS', $e, 400);
}
Assert::true(false);
}
}
...@@ -11,3 +11,35 @@ add_trailing_slash: ...@@ -11,3 +11,35 @@ add_trailing_slash:
requirements: requirements:
url: "[a-zA-Z0-9_-]+[^/]$" url: "[a-zA-Z0-9_-]+[^/]$"
methods: [GET] methods: [GET]
websso-single-sign-on:
path: /saml2/idp/singleSignOnService
defaults: { _controller: 'SimpleSAML\Controller\WebBrowserSingleSignOn::singleSignOnService' }
websso-artifact-resolution:
path: /saml2/idp/artifactResolutionService
defaults: { _controller: 'SimpleSAML\Controller\WebBrowserSingleSignOn::artifactResolutionService' }
websso-metadata:
path: /saml2/idp/metadata
defaults: { _controller: 'SimpleSAML\Controller\Metadata::metadata' }
websso-single-logout:
path: /saml2/idp/singleLogout
defaults: { _controller: 'SimpleSAML\Controller\SingleLogout::singleLogout' }
websso-init-single-logout:
path: /saml2/idp/initSingleLogout
defaults: { _controller: 'SimpleSAML\Controller\SingleLogout::initSingleLogout' }
websso-legacy-single-sign-on:
path: /saml2/idp/SSOService.php
defaults: { _controller: 'SimpleSAML\Controller\WebBrowserSingleSignOn::singleSignOnService', path: /saml2/idp/singleSignOnService, permanent: true }
websso-legacy-artifact-resolution:
path: /saml2/idp/ArtifactResolutionService.php
defaults: { _controller: 'SimpleSAML\Controller\WebBrowserSingleSignOn::artifactResolutionService', path: /saml2/idp/artifactResolutionService, permanent: true }
websso-legacy-metadata:
path: /saml2/idp/metadata.php
defaults: { _controller: 'SimpleSAML\Controller\Metadata::metadata', path: /saml2/idp/metadata, permanent: true }
websso-legacy-single-logout:
path: /saml2/idp/SingleLogoutService.php
defaults: { _controller: 'SimpleSAML\Controller\SingleLogout::singleLogout', path: /saml2/idp/singleLogout, permanent: true }
websso-legacy-init-single-logout:
path: /saml2/idp/initSLO.php
defaults: { _controller: 'SimpleSAML\Controller\SingleLogout::initSingleLogout', path: /saml2/idp/initSingleLogout, permanent: true }
<?php
/**
* The ArtifactResolutionService receives the samlart from the sp.
* And when the artifact is found, it sends a \SAML2\ArtifactResponse.
*
* @package SimpleSAMLphp
*/
require_once('../../_include.php');
use SAML2\Exception\Protocol\UnsupportedBindingException;
use SAML2\ArtifactResolve;
use SAML2\ArtifactResponse;
use SAML2\DOMDocumentFactory;
use SAML2\SOAP;
use SAML2\XML\saml\Issuer;
use SimpleSAML\Assert\Assert;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\Module;
use SimpleSAML\Metadata;
use SimpleSAML\Store\StoreFactory;
$config = Configuration::getInstance();
if (!$config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-hosted');
if (!$idpMetadata->getOptionalBoolean('saml20.sendartifact', false)) {
throw new Error\Error('NOACCESS');
}
$storeType = $config->getOptionalString('store.type', 'phpsession');
$store = StoreFactory::getInstance($storeType);
if ($store === false) {
throw new Exception('Unable to send artifact without a datastore configured.');
}
$binding = new SOAP();
try {
$request = $binding->receive();
} catch (UnsupportedBindingException $e) {
throw new Error\Error('ARSPARAMS', $e, 400);
}
if (!($request instanceof ArtifactResolve)) {
throw new Exception('Message received on ArtifactResolutionService wasn\'t a ArtifactResolve request.');
}
$issuer = $request->getIssuer();
/** @psalm-assert \SAML2\XML\saml\Issuer $issuer */
Assert::notNull($issuer);
$issuer = $issuer->getValue();
$spMetadata = $metadata->getMetaDataConfig($issuer, 'saml20-sp-remote');
$artifact = $request->getArtifact();
$responseData = $store->get('artifact', $artifact);
$store->delete('artifact', $artifact);
if ($responseData !== null) {
$document = DOMDocumentFactory::fromString($responseData);
$responseXML = $document->documentElement;
} else {
$responseXML = null;
}
$artifactResponse = new ArtifactResponse();
$issuer = new Issuer();
$issuer->setValue($idpEntityId);
$artifactResponse->setIssuer($issuer);
$artifactResponse->setInResponseTo($request->getId());
$artifactResponse->setAny($responseXML);
Module\saml\Message::addSign($idpMetadata, $spMetadata, $artifactResponse);
$binding->send($artifactResponse);
<?php
/**
* The SSOService is part of the SAML 2.0 IdP code, and it receives incoming Authentication Requests
* from a SAML 2.0 SP, parses, and process it, and then authenticates the user and sends the user back
* to the SP with an Authentication Response.
*
* @package SimpleSAMLphp
*/
require_once('../../_include.php');
use SAML2\Exception\Protocol\UnsupportedBindingException;
use SimpleSAML\Assert\Assert;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\IdP;
use SimpleSAML\Logger;
use SimpleSAML\Metadata;
use SimpleSAML\Module;
Logger::info('SAML2.0 - IdP.SSOService: Accessing SAML 2.0 IdP endpoint SSOService');
$config = Configuration::getInstance();
if (!$config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = IdP::getById('saml2:' . $idpEntityId);
try {
Module\saml\IdP\SAML2::receiveAuthnRequest($idp);
} catch (UnsupportedBindingException $e) {
throw new Error\Error('SSOPARAMS', $e, 400);
}
Assert::true(false);
<?php
/**
* This SAML 2.0 endpoint can receive incoming LogoutRequests. It will also send LogoutResponses,
* and LogoutRequests and also receive LogoutResponses. It is implemeting SLO at the SAML 2.0 IdP.
*
* @package SimpleSAMLphp
*/
require_once('../../_include.php');
use SAML2\Exception\Protocol\UnsupportedBindingException;
use SimpleSAML\Assert\Assert;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\IdP;
use SimpleSAML\Logger;
use SimpleSAML\Metadata;
use SimpleSAML\Module;
use SimpleSAML\Utils;
Logger::info('SAML2.0 - IdP.SingleLogoutService: Accessing SAML 2.0 IdP endpoint SingleLogoutService');
$config = Configuration::getInstance();
if (!$config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
$httpUtils = new Utils\HTTP();
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = IdP::getById('saml2:' . $idpEntityId);
if (isset($_REQUEST['ReturnTo'])) {
$idp->doLogoutRedirect($httpUtils->checkURLAllowed((string) $_REQUEST['ReturnTo']));
} else {
try {
Module\saml\IdP\SAML2::receiveLogoutMessage($idp);
} catch (UnsupportedBindingException $e) {
throw new Error\Error('SLOSERVICEPARAMS', $e, 400);
}
}
Assert::true(false);
<?php
require_once('../../_include.php');
use SimpleSAML\Assert\Assert;
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\IdP;
use SimpleSAML\Logger;
use SimpleSAML\Metadata;
use SimpleSAML\Module;
use SimpleSAML\Utils;
Logger::info('SAML2.0 - IdP.initSLO: Accessing SAML 2.0 IdP endpoint init Single Logout');
$config = Configuration::getInstance();
if (!$config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
$metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = IdP::getById('saml2:' . $idpEntityId);
if (!isset($_GET['RelayState'])) {
throw new Error\Error('NORELAYSTATE');
}
$httpUtils = new Utils\HTTP();
$idp->doLogoutRedirect($httpUtils->checkURLAllowed((string) $_GET['RelayState']));
Assert::true(false);
<?php
require_once('../../_include.php');
use SimpleSAML\Configuration;
use SimpleSAML\Error;
use SimpleSAML\Module;
use SimpleSAML\Module\saml\IdP\SAML2 as SAML2_IdP;
use SimpleSAML\Utils;
$config = Configuration::getInstance();
if (!$config->getOptionalBoolean('enable.saml20-idp', false) || !Module::isModuleEnabled('saml')) {
throw new Error\Error('NOACCESS', null, 403);
}
// check if valid local session exists
if ($config->getOptionalBoolean('admin.protectmetadata', false)) {
$authUtils = new Utils\Auth();
$authUtils->requireAdmin();
}
$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
try {
$idpentityid = isset($_GET['idpentityid']) ?
$_GET['idpentityid'] : $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$metaArray = SAML2_IdP::getHostedMetadata($idpentityid);
$metaBuilder = new \SimpleSAML\Metadata\SAMLBuilder($idpentityid);
$metaBuilder->addMetadataIdP20($metaArray);
$metaBuilder->addOrganizationInfo($metaArray);
$metaxml = $metaBuilder->getEntityDescriptorText();
// sign the metadata if enabled
$metaxml = \SimpleSAML\Metadata\Signer::sign($metaxml, $metaArray, 'SAML 2 IdP');
header('Content-Type: application/samlmetadata+xml');
header('Content-Disposition: attachment; filename="idp-metadata.xml"');
echo $metaxml;
exit(0);
} catch (\Exception $exception) {
throw new Error\Error('METADATA', $exception);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment