Skip to content
Snippets Groups Projects
Unverified Commit d9d1d0fe authored by Tim van Dijen's avatar Tim van Dijen Committed by GitHub
Browse files

Externalize ADFS module (#1071)

parent 6eed6144
No related branches found
No related tags found
No related merge requests found
Showing
with 2 additions and 913 deletions
......@@ -47,6 +47,7 @@ php "$TARGET/composer.phar" config version "$VERSION" -d "$TARGET"
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-adfs
php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-authfacebook
php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-authlinkedin
php "$TARGET/composer.phar" require --update-no-dev simplesamlphp/simplesamlphp-module-authtwitter
......
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.
Enables AD FS IdP
Compatible with VS 2012 Identity and Access
Basic Setup Companion based on:
http://simplesamlphp.org/docs/stable/simplesamlphp-idp
1. Enabling the Identity Provider functionality
In config/config.php, the option will be:
'enable.adfs-idp' => true
2. Authentication module
Follow as is.
3. Configuring the authentication module
In addition to enabling authentication module, enable adfs module by creating a file named 'enable' in modules/adfs
In unix from installation directory:
touch modules/adfs/enable
4. Configuring the IdP
ADFS IdP is configured by metadata stored in /metadata/adfs-idp-hosted.php and metadata/adfs-sp-remote.php
If they are not present, copy them from /metadata-templates to the metadata
directory.
5. Using the uri NameFormat on attributes
WS-FED likes a few parameters to be very specifically named. This is
especially true if .net clients will be treating this as a Microsoft ADFS
IdP.
The recommended settings for /metadata/adfs-idp-hosted.php is:
'authproc' => array(
// Convert LDAP names to WS-Fed Claims.
100 => array('class' => 'core:AttributeMap', 'name2claim'),
),
6. Adding SPs to the IdP
The minimal configuration for /metadata/adfs-sp-remote.php is:
$metadata['urn:federation:localhost'] = array(
'prp' => 'https://localhost/adfs/ls/',
);
7. Creating a SSL self signed certificate
Follow as is.
8. Adding this IdP to other SPs
Metadata should be available from /module.php/adfs/idp/metadata.php
9. This module tries its best to emulate a Microsoft ADFS endpoint, and as
such, it is simplest to test using a .net client.
To build the test client, follow the tutorial at:
http://code.msdn.microsoft.com/Claims-Aware-Web-d94a89ca
This will build a .net app that uses a dev machine running STS (their name for
an IdP).
To point to your SimpleSamlPHP ADFS IdP, in VS 2012:
a. Right-click the project in Solution Explorer and select the Identity and
Access option.
b. In the Identity and Access Window, Select Use a business identity
provider.
c. Under “Enter the path to the STS metadata document” enter the url you have
from step 8. Something like
https://.../module.php/adfs/idp/metadata.php
d. Click Ok
For more information in regards to .NET: http://msdn.microsoft.com/en-us/library/hh377151.aspx
<?php
namespace SimpleSAML\Module\adfs\IdP;
use RobRichards\XMLSecLibs\XMLSecurityDSig;
use RobRichards\XMLSecLibs\XMLSecurityKey;
use SimpleSAML\Utils\Config\Metadata;
use SimpleSAML\Utils\Crypto;
class ADFS
{
/**
* @param \SimpleSAML\IdP $idp
* @throws \Exception
* @return void
*/
public static function receiveAuthnRequest(\SimpleSAML\IdP $idp)
{
try {
parse_str($_SERVER['QUERY_STRING'], $query);
$requestid = $query['wctx'];
$issuer = $query['wtrealm'];
$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
$spMetadata = $metadata->getMetaDataConfig($issuer, 'adfs-sp-remote');
\SimpleSAML\Logger::info('ADFS - IdP.prp: Incoming Authentication request: '.$issuer.' id '.$requestid);
} catch (\Exception $exception) {
throw new \SimpleSAML\Error\Error('PROCESSAUTHNREQUEST', $exception);
}
$state = [
'Responder' => ['\SimpleSAML\Module\adfs\IdP\ADFS', 'sendResponse'],
'SPMetadata' => $spMetadata->toArray(),
'ForceAuthn' => false,
'isPassive' => false,
'adfs:wctx' => $requestid,
'adfs:wreply' => false
];
if (isset($query['wreply']) && !empty($query['wreply'])) {
$state['adfs:wreply'] = \SimpleSAML\Utils\HTTP::checkURLAllowed($query['wreply']);
}
$idp->handleAuthenticationRequest($state);
}
/**
* @param string $issuer
* @param string $target
* @param string $nameid
* @param array $attributes
* @param int $assertionLifetime
* @return string
*/
private static function generateResponse($issuer, $target, $nameid, $attributes, $assertionLifetime)
{
$issueInstant = \SimpleSAML\Utils\Time::generateTimestamp();
$notBefore = \SimpleSAML\Utils\Time::generateTimestamp(time() - 30);
$assertionExpire = \SimpleSAML\Utils\Time::generateTimestamp(time() + $assertionLifetime);
$assertionID = \SimpleSAML\Utils\Random::generateID();
$nameidFormat = 'http://schemas.xmlsoap.org/claims/UPN';
$nameid = htmlspecialchars($nameid);
$parsed_attrs = [];
foreach ($attributes as $name => $values) {
if ((!is_array($values)) || (count($values) == 0)) {
continue;
}
list($namespace, $name) = \SimpleSAML\Utils\Attributes::getAttributeNamespace(
$name,
'http://schemas.xmlsoap.org/claims'
);
foreach ($values as $value) {
if ((!isset($value)) || ($value === '')) {
continue;
}
$parsed_attrs[] = ['name' => $name, 'namespace' => $namespace, 'value' => htmlspecialchars($value)];
}
}
$config = \SimpleSAML\Configuration::getInstance();
$t = new \SimpleSAML\XHTML\Template($config, 'adfs:generateResponse.twig');
$twig = $t->getTwig();
return $twig->render(
'adfs:generateResponse.twig',
[
'issueInstant' => $issueInstant,
'notBefore' => $notBefore,
'issuer' => $issuer,
'nameid' => $nameid,
'nameidFormat' => $nameidFormat,
'target' => $target,
'assertionID' => $assertionID,
'assertionExpire' => $assertionExpire,
'parsedAttributes' => $parsed_attrs,
]
);
}
/**
* @param string $response
* @param string $key
* @param string $cert
* @param string $algo
* @return string|bool
*/
private static function signResponse($response, $key, $cert, $algo)
{
$objXMLSecDSig = new XMLSecurityDSig();
$objXMLSecDSig->idKeys = ['AssertionID'];
$objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
$responsedom = \SAML2\DOMDocumentFactory::fromString(str_replace("\r", "", $response));
$firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0);
$objXMLSecDSig->addReferenceList(
[$firstassertionroot],
XMLSecurityDSig::SHA256,
['http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N],
['id_name' => 'AssertionID']
);
$objKey = new XMLSecurityKey($algo, ['type' => 'private']);
$objKey->loadKey($key, true);
$objXMLSecDSig->sign($objKey);
if ($cert) {
$public_cert = file_get_contents($cert);
$objXMLSecDSig->add509Cert($public_cert, true);
}
$newSig = $responsedom->importNode($objXMLSecDSig->sigNode, true);
$firstassertionroot->appendChild($newSig);
return $responsedom->saveXML();
}
/**
* @param string $url
* @param string $wresult
* @param string $wctx
* @return void
*/
private static function postResponse($url, $wresult, $wctx)
{
$config = \SimpleSAML\Configuration::getInstance();
$t = new \SimpleSAML\XHTML\Template($config, 'adfs:postResponse.twig');
$t->data['baseurlpath'] = \SimpleSAML\Module::getModuleURL('adfs');
$t->data['url'] = $url;
$t->data['wresult'] = $wresult;
$t->data['wctx'] = $wctx;
$t->show();
}
/**
* Get the metadata of a given hosted ADFS IdP.
*
* @param string $entityid The entity ID of the hosted ADFS IdP whose metadata we want to fetch.
* @return array
*
* @throws \SimpleSAML\Error\Exception
* @throws \SimpleSAML\Error\MetadataNotFound
*/
public static function getHostedMetadata($entityid)
{
$handler = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
$config = $handler->getMetaDataConfig($entityid, 'adfs-idp-hosted');
$endpoint = \SimpleSAML\Module::getModuleURL('adfs/idp/prp.php');
$metadata = [
'metadata-set' => 'adfs-idp-hosted',
'entityid' => $entityid,
'SingleSignOnService' => [
[
'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
'Location' => $endpoint,
]
],
'SingleLogoutService' => [
'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
'Location' => $endpoint,
],
'NameIDFormat' => $config->getString('NameIDFormat', \SAML2\Constants::NAMEID_TRANSIENT),
'contacts' => [],
];
// add certificates
$keys = [];
$certInfo = Crypto::loadPublicKey($config, false, 'new_');
$hasNewCert = false;
if ($certInfo !== null) {
$keys[] = [
'type' => 'X509Certificate',
'signing' => true,
'encryption' => true,
'X509Certificate' => $certInfo['certData'],
'prefix' => 'new_',
];
$hasNewCert = true;
}
$certInfo = Crypto::loadPublicKey($config, true);
$keys[] = [
'type' => 'X509Certificate',
'signing' => true,
'encryption' => $hasNewCert === false,
'X509Certificate' => $certInfo['certData'],
'prefix' => '',
];
if ($config->hasValue('https.certificate')) {
$httpsCert = Crypto::loadPublicKey($config, true, 'https.');
$keys[] = [
'type' => 'X509Certificate',
'signing' => true,
'encryption' => false,
'X509Certificate' => $httpsCert['certData'],
'prefix' => 'https.'
];
}
$metadata['keys'] = $keys;
// add organization information
if ($config->hasValue('OrganizationName')) {
$metadata['OrganizationName'] = $config->getLocalizedString('OrganizationName');
$metadata['OrganizationDisplayName'] = $config->getLocalizedString(
'OrganizationDisplayName',
$metadata['OrganizationName']
);
if (!$config->hasValue('OrganizationURL')) {
throw new \SimpleSAML\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.');
}
$metadata['OrganizationURL'] = $config->getLocalizedString('OrganizationURL');
}
// add scope
if ($config->hasValue('scope')) {
$metadata['scope'] = $config->getArray('scope');
}
// add extensions
if ($config->hasValue('EntityAttributes')) {
$metadata['EntityAttributes'] = $config->getArray('EntityAttributes');
// check for entity categories
if (Metadata::isHiddenFromDiscovery($metadata)) {
$metadata['hide.from.discovery'] = true;
}
}
if ($config->hasValue('UIInfo')) {
$metadata['UIInfo'] = $config->getArray('UIInfo');
}
if ($config->hasValue('DiscoHints')) {
$metadata['DiscoHints'] = $config->getArray('DiscoHints');
}
if ($config->hasValue('RegistrationInfo')) {
$metadata['RegistrationInfo'] = $config->getArray('RegistrationInfo');
}
// add contact information
$globalConfig = \SimpleSAML\Configuration::getInstance();
$email = $globalConfig->getString('technicalcontact_email', false);
if ($email && $email !== 'na@example.org') {
$contact = [
'emailAddress' => $email,
'name' => $globalConfig->getString('technicalcontact_name', null),
'contactType' => 'technical',
];
$metadata['contacts'][] = Metadata::getContact($contact);
}
return $metadata;
}
/**
* @param array $state
* @return void
*
* @throws \Exception
*/
public static function sendResponse(array $state)
{
$spMetadata = $state["SPMetadata"];
$spEntityId = $spMetadata['entityid'];
$spMetadata = \SimpleSAML\Configuration::loadFromArray(
$spMetadata,
'$metadata['.var_export($spEntityId, true).']'
);
$attributes = $state['Attributes'];
$nameidattribute = $spMetadata->getValue('simplesaml.nameidattribute');
if (!empty($nameidattribute)) {
if (!array_key_exists($nameidattribute, $attributes)) {
throw new \Exception('simplesaml.nameidattribute does not exist in resulting attribute set');
}
$nameid = $attributes[$nameidattribute][0];
} else {
$nameid = \SimpleSAML\Utils\Random::generateID();
}
$idp = \SimpleSAML\IdP::getByState($state);
$idpMetadata = $idp->getConfig();
$idpEntityId = $idpMetadata->getString('entityid');
$idp->addAssociation([
'id' => 'adfs:'.$spEntityId,
'Handler' => '\SimpleSAML\Module\adfs\IdP\ADFS',
'adfs:entityID' => $spEntityId,
]);
$assertionLifetime = $spMetadata->getInteger('assertion.lifetime', null);
if ($assertionLifetime === null) {
$assertionLifetime = $idpMetadata->getInteger('assertion.lifetime', 300);
}
$response = ADFS::generateResponse($idpEntityId, $spEntityId, $nameid, $attributes, $assertionLifetime);
$privateKeyFile = \SimpleSAML\Utils\Config::getCertPath($idpMetadata->getString('privatekey'));
$certificateFile = \SimpleSAML\Utils\Config::getCertPath($idpMetadata->getString('certificate'));
$algo = $spMetadata->getString('signature.algorithm', null);
if ($algo === null) {
$algo = $idpMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA256);
}
$wresult = ADFS::signResponse($response, $privateKeyFile, $certificateFile, $algo);
$wctx = $state['adfs:wctx'];
$wreply = $state['adfs:wreply'] ? : $spMetadata->getValue('prp');
ADFS::postResponse($wreply, $wresult, $wctx);
}
/**
* @param \SimpleSAML\IdP $idp
* @param array $state
* @return void
*/
public static function sendLogoutResponse(\SimpleSAML\IdP $idp, array $state)
{
// NB:: we don't know from which SP the logout request came from
$idpMetadata = $idp->getConfig();
\SimpleSAML\Utils\HTTP::redirectTrustedURL(
$idpMetadata->getValue('redirect-after-logout', \SimpleSAML\Utils\HTTP::getBaseURL())
);
}
/**
* @param \SimpleSAML\IdP $idp
* @return void
*/
public static function receiveLogoutMessage(\SimpleSAML\IdP $idp)
{
// if a redirect is to occur based on wreply, we will redirect to url as
// this implies an override to normal sp notification
if (isset($_GET['wreply']) && !empty($_GET['wreply'])) {
$idp->doLogoutRedirect(\SimpleSAML\Utils\HTTP::checkURLAllowed($_GET['wreply']));
assert(false);
}
$state = [
'Responder' => ['\SimpleSAML\Module\adfs\IdP\ADFS', 'sendLogoutResponse'],
];
$assocId = null;
// TODO: verify that this is really no problem for:
// a) SSP, because there's no caller SP.
// b) ADFS SP because caller will be called back..
$idp->handleLogoutRequest($state, $assocId);
}
/**
* Accepts an association array, and returns a URL that can be accessed to terminate the association
* @param \SimpleSAML\IdP $idp
* @param array $association
* @param string $relayState
* @return string
*/
public static function getLogoutURL(\SimpleSAML\IdP $idp, array $association, $relayState)
{
$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
$spMetadata = $metadata->getMetaDataConfig($association['adfs:entityID'], 'adfs-sp-remote');
$returnTo = \SimpleSAML\Module::getModuleURL(
'adfs/idp/prp.php?assocId='.urlencode($association["id"]).'&relayState='.urlencode($relayState)
);
return $spMetadata->getValue('prp').'?wa=wsignoutcleanup1.0&wreply='.urlencode($returnTo);
}
}
<?php
namespace SimpleSAML\Module\adfs\SAML2\XML\fed;
/**
* Class holding constants relevant for ADFS.
*
* @package SimpleSAMLphp
*/
class Constants
{
/**
* The namespace for WS-FED protocol.
*/
const NS_FED = 'http://docs.oasis-open.org/wsfed/federation/200706';
}
<?php
namespace SimpleSAML\Module\adfs\SAML2\XML\fed;
/**
* Class representing fed Endpoint.
*
* @package SimpleSAMLphp
*/
class Endpoint
{
/**
* Add this endpoint to an XML element.
*
* @param \DOMElement $parent The element we should append this endpoint to.
* @param string $name The name of the element we should create.
* @param string $address
* @return \DOMElement
*/
public static function appendXML(\DOMElement $parent, $name, $address)
{
assert(is_string($name));
assert(is_string($address));
$e = $parent->ownerDocument->createElement($name);
$parent->appendChild($e);
$endpoint = $parent->ownerDocument->createElement('EndpointReference');
$endpoint->setAttribute('xmlns', 'http://www.w3.org/2005/08/addressing');
$e->appendChild($endpoint);
$address = $parent->ownerDocument->createElement('Address', $address);
$endpoint->appendChild($address);
return $e;
}
}
<?php
namespace SimpleSAML\Module\adfs\SAML2\XML\fed;
/**
* Class representing SecurityTokenServiceType RoleDescriptor.
*
* @package SimpleSAMLphp
*/
class SecurityTokenServiceType extends \SAML2\XML\md\RoleDescriptor
{
/**
* List of supported protocols.
*
* @var array
*/
public $protocolSupportEnumeration = [Constants::NS_FED];
/**
* The Location of Services.
*
* @var string|null
*/
public $Location = null;
/**
* Initialize a SecurityTokenServiceType element.
*
* @param \DOMElement|null $xml The XML element we should load.
*/
public function __construct(\DOMElement $xml = null)
{
parent::__construct('RoleDescriptor', $xml);
if ($xml === null) {
return;
}
}
/**
* Convert this SecurityTokenServiceType RoleDescriptor to XML.
*
* @param \DOMElement $parent The element we should add this contact to.
* @return \DOMElement The new ContactPerson-element.
*/
public function toXML(\DOMElement $parent)
{
assert(is_string($this->Location));
$e = parent::toXML($parent);
$e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:fed', Constants::NS_FED);
$e->setAttributeNS(\SAML2\Constants::NS_XSI, 'xsi:type', 'fed:SecurityTokenServiceType');
TokenTypesOffered::appendXML($e);
Endpoint::appendXML($e, 'SecurityTokenServiceEndpoint', $this->Location);
Endpoint::appendXML($e, 'fed:PassiveRequestorEndpoint', $this->Location);
return $e;
}
/**
* Get the location of this service.
*
* @return string|null The full URL where this service can be reached.
*/
public function getLocation()
{
return $this->Location;
}
/**
* Set the location of this service.
*
* @param string $location The full URL where this service can be reached.
* @return void
*/
public function setLocation($location)
{
$this->Location = $location;
}
}
<?php
namespace SimpleSAML\Module\adfs\SAML2\XML\fed;
/**
* Class representing fed TokenTypesOffered.
*
* @package SimpleSAMLphp
*/
class TokenTypesOffered
{
/**
* Add tokentypesoffered to an XML element.
*
* @param \DOMElement $parent The element we should append this endpoint to.
* @return \DOMElement
*/
public static function appendXML(\DOMElement $parent)
{
$e = $parent->ownerDocument->createElementNS(Constants::NS_FED, 'fed:TokenTypesOffered');
$parent->appendChild($e);
$tokentype = $parent->ownerDocument->createElementNS(Constants::NS_FED, 'fed:TokenType');
$tokentype->setAttribute('Uri', 'urn:oasis:names:tc:SAML:1.0:assertion');
$e->appendChild($tokentype);
return $e;
}
}
<wst:RequestSecurityTokenResponse xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust">
<wst:RequestedSecurityToken>
<saml:Assertion Issuer="{{ issuer }}" IssueInstant="{{ issueInstant }}" AssertionID="{{ assertionID }}" MinorVersion="1" MajorVersion="1" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
<saml:Conditions NotOnOrAfter="{{ assertionExpire }}" NotBefore="{{ notBefore }}">
<saml:AudienceRestrictionCondition>
<saml:Audience>{{ target }}</saml:Audience>
</saml:AudienceRestrictionCondition>
</saml:Conditions>
<saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified" AuthenticationInstant="{{ issueInstant }}">
<saml:Subject>
<saml:NameIdentifier Format="{{ nameidFormat }}">{{ nameid }}</saml:NameIdentifier>
</saml:Subject>
</saml:AuthenticationStatement>
<saml:AttributeStatement>
<saml:Subject>
<saml:NameIdentifier Format="{{ nameidFormat }}">{{ nameid }}</saml:NameIdentifier>
</saml:Subject>
{% for attr in parsedAttributes %}
<saml:Attribute AttributeNamespace="{{ attr.namespace }}" AttributeName="{{ attr.name }}">
<saml:AttributeValue>{{ attr.value }}</saml:AttributeValue>
</saml:Attribute>
{% endfor %}
</saml:AttributeStatement>
</saml:Assertion>
</wst:RequestedSecurityToken>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsa:EndpointReference xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<wsa:Address>{{ target }}</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
</wst:RequestSecurityTokenResponse>
<!DOCTYPE html>
<html>
<head>
<script src="/{{ baseurlpath }}module.php/adfs/assets/js/postResponse.js"></script>
</head>
<body>
<form method="post" action="{{ url }}">
<input type="hidden" name="wa" value="wsignin1.0">
<input type="hidden" name="wresult" value="{{ wresult|escape('html') }}">
<input type="hidden" name="wctx" value="{{ wctx|escape('html') }}">
<noscript>
<input type="submit" value="Continue">
</noscript>
</form>
</body>
</html>
document.addEventListener('DOMContentLoaded', function () {
document.forms[0].submit();
});
<?php
// load configuration and metadata
$config = \SimpleSAML\Configuration::getInstance();
$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
if (!$config->getBoolean('enable.adfs-idp', false)) {
throw new \SimpleSAML\Error\Error('NOACCESS');
}
// check if valid local session exists
if ($config->getBoolean('admin.protectmetadata', false)) {
\SimpleSAML\Utils\Auth::requireAdmin();
}
try {
$idpentityid = isset($_GET['idpentityid']) ?
$_GET['idpentityid'] : $metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
$idpmeta = $metadata->getMetaDataConfig($idpentityid, 'adfs-idp-hosted');
$availableCerts = [];
$keys = [];
$certInfo = \SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, false, 'new_');
if ($certInfo !== null) {
$availableCerts['new_idp.crt'] = $certInfo;
$keys[] = [
'type' => 'X509Certificate',
'signing' => true,
'encryption' => true,
'X509Certificate' => $certInfo['certData'],
];
$hasNewCert = true;
} else {
$hasNewCert = false;
}
$certInfo = \SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true);
$availableCerts['idp.crt'] = $certInfo;
$keys[] = [
'type' => 'X509Certificate',
'signing' => true,
'encryption' => ($hasNewCert ? false : true),
'X509Certificate' => $certInfo['certData'],
];
if ($idpmeta->hasValue('https.certificate')) {
$httpsCert = \SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true, 'https.');
assert(isset($httpsCert['certData']));
$availableCerts['https.crt'] = $httpsCert;
$keys[] = [
'type' => 'X509Certificate',
'signing' => true,
'encryption' => false,
'X509Certificate' => $httpsCert['certData'],
];
}
$adfs_service_location = \SimpleSAML\Module::getModuleURL('adfs').'/idp/prp.php';
$metaArray = [
'metadata-set' => 'adfs-idp-remote',
'entityid' => $idpentityid,
'SingleSignOnService' => [
0 => [
'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
'Location' => $adfs_service_location
]
],
'SingleLogoutService' => [
0 => [
'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
'Location' => $adfs_service_location
]
],
];
if (count($keys) === 1) {
$metaArray['certData'] = $keys[0]['X509Certificate'];
} else {
$metaArray['keys'] = $keys;
}
$metaArray['NameIDFormat'] = $idpmeta->getString(
'NameIDFormat',
'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
);
if ($idpmeta->hasValue('OrganizationName')) {
$metaArray['OrganizationName'] = $idpmeta->getLocalizedString('OrganizationName');
$metaArray['OrganizationDisplayName'] = $idpmeta->getLocalizedString(
'OrganizationDisplayName',
$metaArray['OrganizationName']
);
if (!$idpmeta->hasValue('OrganizationURL')) {
throw new \SimpleSAML\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.');
}
$metaArray['OrganizationURL'] = $idpmeta->getLocalizedString('OrganizationURL');
}
if ($idpmeta->hasValue('scope')) {
$metaArray['scope'] = $idpmeta->getArray('scope');
}
if ($idpmeta->hasValue('EntityAttributes')) {
$metaArray['EntityAttributes'] = $idpmeta->getArray('EntityAttributes');
}
if ($idpmeta->hasValue('UIInfo')) {
$metaArray['UIInfo'] = $idpmeta->getArray('UIInfo');
}
if ($idpmeta->hasValue('DiscoHints')) {
$metaArray['DiscoHints'] = $idpmeta->getArray('DiscoHints');
}
if ($idpmeta->hasValue('RegistrationInfo')) {
$metaArray['RegistrationInfo'] = $idpmeta->getArray('RegistrationInfo');
}
$metaflat = '$metadata['.var_export($idpentityid, true).'] = '.var_export($metaArray, true).';';
$metaBuilder = new \SimpleSAML\Metadata\SAMLBuilder($idpentityid);
$metaBuilder->addSecurityTokenServiceType($metaArray);
$metaBuilder->addOrganizationInfo($metaArray);
$technicalContactEmail = $config->getString('technicalcontact_email', null);
if ($technicalContactEmail && $technicalContactEmail !== 'na@example.org') {
$metaBuilder->addContact('technical', \SimpleSAML\Utils\Config\Metadata::getContact([
'emailAddress' => $technicalContactEmail,
'name' => $config->getString('technicalcontact_name', null),
'contactType' => 'technical',
]));
}
$output_xhtml = array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml';
$metaxml = $metaBuilder->getEntityDescriptorText($output_xhtml);
if (!$output_xhtml) {
$metaxml = str_replace("\n", '', $metaxml);
}
// sign the metadata if enabled
$metaxml = \SimpleSAML\Metadata\Signer::sign($metaxml, $idpmeta->toArray(), 'ADFS IdP');
if ($output_xhtml) {
$defaultidp = $config->getString('default-adfs-idp', null);
$t = new \SimpleSAML\XHTML\Template($config, 'saml:metadata.php', 'admin');
$t->data['clipboard.js'] = true;
$t->data['available_certs'] = $availableCerts;
$certdata = [];
foreach (array_keys($availableCerts) as $availableCert) {
$certdata[$availableCert]['name'] = $availableCert;
$certdata[$availableCert]['url'] = \SimpleSAML\Module::getModuleURL('saml/idp/certs.php').
'/'.$availableCert;
$certdata[$availableCert]['comment'] = '';
if ($availableCerts[$availableCert]['certFingerprint'][0] === 'afe71c28ef740bc87425be13a2263d37971da1f9') {
$certdata[$availableCert]['comment'] = 'This is the default certificate.'.
' Generate a new certificate if this is a production system.';
}
}
$t->data['certdata'] = $certdata;
$t->data['header'] = 'adfs-idp'; // TODO: Replace with headerString in 2.0
$t->data['headerString'] = \SimpleSAML\Locale\Translate::noop('metadata_adfs-idp');
$t->data['metaurl'] = \SimpleSAML\Utils\HTTP::getSelfURLNoQuery();
$t->data['metadata'] = htmlspecialchars($metaxml);
$t->data['metadataflat'] = htmlspecialchars($metaflat);
$t->data['defaultidp'] = $defaultidp;
$t->show();
} else {
header('Content-Type: application/xml');
// make sure to export only the md:EntityDescriptor
$metaxml = substr($metaxml, strpos($metaxml, '<md:EntityDescriptor'));
// 22 = strlen('</md:EntityDescriptor>')
$metaxml = substr($metaxml, 0, strrpos($metaxml, '</md:EntityDescriptor>') + 22);
echo $metaxml;
exit(0);
}
} catch (\Exception $exception) {
throw new \SimpleSAML\Error\Error('METADATA', $exception);
}
<?php
/**
* ADFS PRP IDP protocol support for SimpleSAMLphp.
*
* @author Hans Zandbelt, SURFnet bv, <hans.zandbelt@surfnet.nl>
* @package SimpleSAMLphp
*/
\SimpleSAML\Logger::info('ADFS - IdP.prp: Accessing ADFS IdP endpoint prp');
$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
$idp = \SimpleSAML\IdP::getById('adfs:'.$idpEntityId);
if (isset($_GET['wa'])) {
if ($_GET['wa'] === 'wsignout1.0') {
\SimpleSAML\Module\adfs\IdP\ADFS::receiveLogoutMessage($idp);
} elseif ($_GET['wa'] === 'wsignin1.0') {
\SimpleSAML\Module\adfs\IdP\ADFS::receiveAuthnRequest($idp);
}
assert(false);
} elseif (isset($_GET['assocId'])) {
// logout response from ADFS SP
$assocId = $_GET['assocId']; // Association ID of the SP that sent the logout response
$relayState = $_GET['relayState']; // Data that was sent in the logout request to the SP. Can be null
$logoutError = null; // null on success, or an instance of a \SimpleSAML\Error\Exception on failure.
$idp->handleLogoutResponse($assocId, $relayState, $logoutError);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment