21 assert(
'isset($state["Attributes"])');
22 assert(
'isset($state["SPMetadata"])');
23 assert(
'isset($state["saml:ConsumerURL"])');
24 assert(
'array_key_exists("saml:RequestId", $state)');
25 assert(
'array_key_exists("saml:RelayState", $state)');
36 $requestId = $state[
'saml:RequestId'];
38 $consumerURL = $state[
'saml:ConsumerURL'];
39 $protocolBinding = $state[
'saml:Binding'];
47 if (isset($state[
'saml:AuthenticatingAuthority'])) {
48 $assertion->setAuthenticatingAuthority($state[
'saml:AuthenticatingAuthority']);
54 'Handler' =>
'sspmod_saml_IdP_SAML2',
55 'Expires' => $assertion->getSessionNotOnOrAfter(),
57 'saml:NameID' => $state[
'saml:idp:NameID'],
58 'saml:SessionIndex' => $assertion->getSessionIndex(),
66 $ar->setInResponseTo($requestId);
68 $ar->setAssertions(
array($assertion));
76 'protocol' =>
'saml2',
78 if (isset($state[
'saml:AuthnRequestReceivedAt'])) {
79 $statsData[
'logintime'] = microtime(
true) - $state[
'saml:AuthnRequestReceivedAt'];
98 assert(
'isset($state["SPMetadata"])');
99 assert(
'isset($state["saml:ConsumerURL"])');
100 assert(
'array_key_exists("saml:RequestId", $state)');
101 assert(
'array_key_exists("saml:RelayState", $state)');
110 $requestId = $state[
'saml:RequestId'];
112 $consumerURL = $state[
'saml:ConsumerURL'];
113 $protocolBinding = $state[
'saml:Binding'];
125 $ar->setInResponseTo($requestId);
129 'Code' =>
$error->getStatus(),
130 'SubCode' =>
$error->getSubStatus(),
131 'Message' =>
$error->getStatusMessage(),
133 $ar->setStatus($status);
138 'protocol' =>
'saml2',
141 if (isset($state[
'saml:AuthnRequestReceivedAt'])) {
142 $statsData[
'logintime'] = microtime(
true) - $state[
'saml:AuthnRequestReceivedAt'];
163 array $supportedBindings,
165 $AssertionConsumerServiceURL,
167 $AssertionConsumerServiceIndex
169 assert(
'is_string($AssertionConsumerServiceURL) || is_null($AssertionConsumerServiceURL)');
170 assert(
'is_string($ProtocolBinding) || is_null($ProtocolBinding)');
171 assert(
'is_int($AssertionConsumerServiceIndex) || is_null($AssertionConsumerServiceIndex)');
180 $firstNotFalse = null;
182 foreach ($spMetadata->
getEndpoints(
'AssertionConsumerService') as $ep) {
183 if ($AssertionConsumerServiceURL !== null && $ep[
'Location'] !== $AssertionConsumerServiceURL) {
186 if ($ProtocolBinding !== null && $ep[
'Binding'] !== $ProtocolBinding) {
189 if ($AssertionConsumerServiceIndex !== null && $ep[
'index'] !== $AssertionConsumerServiceIndex) {
193 if (!in_array($ep[
'Binding'], $supportedBindings,
true)) {
200 if (array_key_exists(
'isDefault', $ep)) {
201 if ($ep[
'isDefault'] ===
true) {
206 if ($firstFalse === null) {
211 if ($firstNotFalse === null) {
213 $firstNotFalse = $ep;
218 if ($firstNotFalse !== null) {
219 return $firstNotFalse;
220 } elseif ($firstFalse !== null) {
225 if ($AssertionConsumerServiceURL !== null) {
228 if ($ProtocolBinding !== null) {
231 if ($AssertionConsumerServiceIndex !== null) {
233 'AssertionConsumerServiceIndex: '.var_export($AssertionConsumerServiceIndex,
true)
238 return $spMetadata->
getDefaultEndpoint(
'AssertionConsumerService', $supportedBindings);
254 $supportedBindings =
array(\
SAML2\Constants::BINDING_HTTP_POST);
255 if (
$idpMetadata->getBoolean(
'saml20.sendartifact',
false)) {
258 if (
$idpMetadata->getBoolean(
'saml20.hok.assertion',
false)) {
262 if (isset($_REQUEST[
'spentityid'])) {
265 if (isset($_REQUEST[
'cookieTime'])) {
266 $cookieTime = (int) $_REQUEST[
'cookieTime'];
267 if ($cookieTime + 5 >
time()) {
279 if (isset($_REQUEST[
'RelayState'])) {
285 if (isset($_REQUEST[
'binding'])) {
286 $protocolBinding = (
string) $_REQUEST[
'binding'];
288 $protocolBinding = null;
291 if (isset($_REQUEST[
'NameIDFormat'])) {
292 $nameIDFormat = (
string) $_REQUEST[
'NameIDFormat'];
294 $nameIDFormat = null;
304 $consumerIndex = null;
307 $authnContext = null;
312 'SAML2.0 - IdP.SSOService: IdP initiated authentication: '.var_export(
$spEntityId,
true)
318 if (!($request instanceof \
SAML2\AuthnRequest)) {
320 'Message received on authentication request endpoint wasn\'t an authentication request.' 327 'Received message on authentication request endpoint without issuer.' 336 $requestId = $request->getId();
337 $IDPList = $request->getIDPList();
338 $ProxyCount = $request->getProxyCount();
339 if ($ProxyCount !== null) {
342 $RequesterID = $request->getRequesterID();
345 $consumerURL = $request->getAssertionConsumerServiceURL();
346 $protocolBinding = $request->getProtocolBinding();
347 $consumerIndex = $request->getAssertionConsumerServiceIndex();
348 $extensions = $request->getExtensions();
349 $authnContext = $request->getRequestedAuthnContext();
351 $nameIdPolicy = $request->getNameIdPolicy();
352 if (isset($nameIdPolicy[
'Format'])) {
353 $nameIDFormat = $nameIdPolicy[
'Format'];
355 $nameIDFormat = null;
357 if (isset($nameIdPolicy[
'AllowCreate'])) {
358 $allowCreate = $nameIdPolicy[
'AllowCreate'];
360 $allowCreate =
false;
366 'SAML2.0 - IdP.SSOService: incoming authentication request: '.var_export(
$spEntityId,
true)
375 'protocol' =>
'saml2',
376 'idpInit' => $idpInit,
379 $acsEndpoint = self::getAssertionConsumerService(
387 $IDPList = array_unique(array_merge($IDPList,
$spMetadata->getArrayizeString(
'IDPList',
array())));
388 if ($ProxyCount === null) {
389 $ProxyCount =
$spMetadata->getInteger(
'ProxyCount', null);
396 $sessionLostParams =
array(
398 'cookieTime' =>
time(),
404 $sessionLostURL = \SimpleSAML\Utils\HTTP::addURLParameters(
410 'Responder' =>
array(
'sspmod_saml_IdP_SAML2',
'sendResponse'),
416 'saml:RequestId' => $requestId,
417 'saml:IDPList' => $IDPList,
418 'saml:ProxyCount' => $ProxyCount,
419 'saml:RequesterID' => $RequesterID,
422 'saml:ConsumerURL' => $acsEndpoint[
'Location'],
423 'saml:Binding' => $acsEndpoint[
'Binding'],
424 'saml:NameIDFormat' => $nameIDFormat,
425 'saml:AllowCreate' => $allowCreate,
426 'saml:Extensions' => $extensions,
427 'saml:AuthnRequestReceivedAt' => microtime(
true),
428 'saml:RequestedAuthnContext' => $authnContext,
444 assert(
'is_string($relayState) || is_null($relayState)');
446 SimpleSAML\Logger::info(
'Sending SAML 2.0 LogoutRequest to: '.var_export($association[
'saml:entityID'],
true));
453 'spEntityID' => $association[
'saml:entityID'],
458 'SingleLogoutService',
460 \
SAML2\Constants::BINDING_HTTP_REDIRECT,
461 \
SAML2\Constants::BINDING_HTTP_POST
466 $lr->setDestination(
$dst[
'Location']);
480 assert(
'isset($state["saml:SPEntityId"])');
481 assert(
'isset($state["saml:RequestId"])');
482 assert(
'array_key_exists("saml:RelayState", $state)');
491 $lr->setInResponseTo($state[
'saml:RequestId']);
492 $lr->setRelayState($state[
'saml:RelayState']);
494 if (isset($state[
'core:Failed']) && $state[
'core:Failed']) {
497 'Code' => \
SAML2\Constants::STATUS_SUCCESS,
498 'SubCode' => \
SAML2\Constants::STATUS_PARTIAL_LOGOUT,
509 'partial' => $partial
512 'SingleLogoutService',
514 \
SAML2\Constants::BINDING_HTTP_REDIRECT,
515 \
SAML2\Constants::BINDING_HTTP_POST
519 if (isset(
$dst[
'ResponseLocation'])) {
561 $statsData[
'error'] =
$message->getStatus();
588 'Responder' =>
array(
'sspmod_saml_IdP_SAML2',
'sendLogoutResponse'),
590 'saml:RelayState' =>
$message->getRelayState(),
591 'saml:RequestId' =>
$message->getId(),
613 assert(
'is_string($relayState) || is_null($relayState)');
615 SimpleSAML\Logger::info(
'Sending SAML 2.0 LogoutRequest to: '.var_export($association[
'saml:entityID'],
true));
622 \
SAML2\Constants::BINDING_HTTP_REDIRECT,
623 \
SAML2\Constants::BINDING_HTTP_POST
627 if (
$dst[
'Binding'] === \
SAML2\Constants::BINDING_HTTP_POST) {
636 $lr->setDestination(
$dst[
'Location']);
638 $binding = new \SAML2\HTTPRedirect();
655 return $metadata->getMetaDataConfig($association[
'saml:entityID'],
'saml20-sp-remote');
677 $attribute = $spMetadata->
getString(
'simplesaml.nameidattribute', null);
678 if ($attribute === null) {
679 $attribute = $idpMetadata->
getString(
'simplesaml.nameidattribute', null);
680 if ($attribute === null) {
681 if (!isset($state[
'UserID'])) {
685 $attributeValue = $state[
'UserID'];
691 $uidData =
'uidhashbase'.$secretSalt;
694 $uidData .= strlen($attributeValue).
':'.$attributeValue;
695 $uidData .= $secretSalt;
697 return hash(
'sha1', $uidData);
704 ' in the attributes of the user.');
729 $base64Attributes = $spMetadata->
getBoolean(
'base64attributes', null);
730 if ($base64Attributes === null) {
731 $base64Attributes = $idpMetadata->
getBoolean(
'base64attributes',
false);
734 if ($base64Attributes) {
735 $defaultEncoding =
'base64';
737 $defaultEncoding =
'string';
740 $srcEncodings = $idpMetadata->
getArray(
'attributeencodings',
array());
741 $dstEncodings = $spMetadata->
getArray(
'attributeencodings',
array());
747 $encodings = array_merge($srcEncodings, $dstEncodings);
750 foreach ($attributes as
$name => $values) {
752 if (array_key_exists(
$name, $encodings)) {
753 $encoding = $encodings[
$name];
755 $encoding = $defaultEncoding;
758 foreach ($values as $value) {
760 if ($value === null) {
766 if ($value instanceof DOMNodeList) {
767 $attrval = new \SAML2\XML\saml\AttributeValue($value->item(0)->parentNode);
772 $value = (
string) $attrval;
775 $value = base64_encode((
string) $attrval);
778 if (is_string($value)) {
780 $value = $doc->firstChild->childNodes;
782 assert(
'$value instanceof DOMNodeList || $value instanceof \SAML2\XML\saml\NameID');
786 var_export(
$name,
true).
': '.var_export($encoding,
true));
830 return 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic';
850 assert(
'isset($state["Attributes"])');
851 assert(
'isset($state["saml:ConsumerURL"])');
855 $signAssertion = $spMetadata->
getBoolean(
'saml20.sign.assertion', null);
856 if ($signAssertion === null) {
857 $signAssertion = $idpMetadata->
getBoolean(
'saml20.sign.assertion',
true);
862 $a = new \SAML2\Assertion();
863 if ($signAssertion) {
867 $a->setIssuer($idpMetadata->
getString(
'entityid'));
870 $a->setNotBefore($now - 30);
878 if (isset($state[
'saml:AuthnContextClassRef'])) {
879 $a->setAuthnContext($state[
'saml:AuthnContextClassRef']);
881 $a->setAuthnContext(\
SAML2\Constants::AC_PASSWORD);
884 $sessionStart = $now;
885 if (isset($state[
'AuthnInstant'])) {
886 $a->setAuthnInstant($state[
'AuthnInstant']);
887 $sessionStart = $state[
'AuthnInstant'];
890 $sessionLifetime =
$config->getInteger(
'session.duration', 8 * 60 * 60);
891 $a->setSessionNotOnOrAfter($sessionStart + $sessionLifetime);
893 $a->setSessionIndex(
SimpleSAML\Utils\Random::generateID());
895 $sc = new \SAML2\XML\saml\SubjectConfirmation();
898 $sc->SubjectConfirmationData->Recipient = $state[
'saml:ConsumerURL'];
899 $sc->SubjectConfirmationData->InResponseTo = $state[
'saml:RequestId'];
902 $hokAssertion = null;
903 if ($state[
'saml:Binding'] === \
SAML2\Constants::BINDING_HOK_SSO) {
904 $hokAssertion =
true;
906 if ($hokAssertion === null) {
907 $hokAssertion = $idpMetadata->
getBoolean(
'saml20.hok.assertion',
false);
914 if (isset(
$_SERVER[
'SSL_CLIENT_CERT']) && !empty(
$_SERVER[
'SSL_CLIENT_CERT'])) {
916 $clientCert =
$_SERVER[
'SSL_CLIENT_CERT'];
917 $pattern =
'/^-----BEGIN CERTIFICATE-----([^-]*)^-----END CERTIFICATE-----/m';
918 if (preg_match($pattern, $clientCert, $matches)) {
920 $x509Certificate = new \SAML2\XML\ds\X509Certificate();
921 $x509Certificate->certificate = str_replace(
array(
"\r",
"\n",
" "),
'', $matches[1]);
923 $x509Data = new \SAML2\XML\ds\X509Data();
924 $x509Data->data[] = $x509Certificate;
926 $keyInfo = new \SAML2\XML\ds\KeyInfo();
927 $keyInfo->info[] = $x509Data;
929 $sc->SubjectConfirmationData->info[] = $keyInfo;
932 'Error creating HoK assertion: No valid client certificate provided during TLS handshake '.
938 'Error creating HoK assertion: No client certificate provided during TLS handshake with IdP' 943 'Error creating HoK assertion: No HTTPS connection to IdP, but required for Holder-of-Key SSO' 950 $a->setSubjectConfirmation(
array(
$sc));
953 if ($spMetadata->
getBoolean(
'simplesaml.attributes',
true)) {
956 $attributes = self::encodeAttributes($idpMetadata, $spMetadata, $state[
'Attributes']);
961 if (isset($state[
'saml:NameIDFormat'])) {
969 $nameIdFormat = $spMetadata->
getString(
'NameIDFormat', null);
970 if ($nameIdFormat === null) {
971 $nameIdFormat = $idpMetadata->
getString(
'NameIDFormat', \
SAML2\Constants::NAMEID_TRANSIENT);
975 if (isset($state[
'saml:NameID'][$nameIdFormat])) {
979 $spNameQualifier = $spMetadata->
getString(
'SPNameQualifier', null);
980 if ($spNameQualifier === null) {
981 $spNameQualifier = $spMetadata->
getString(
'entityid');
984 if ($nameIdFormat === \
SAML2\Constants::NAMEID_TRANSIENT) {
990 $nameIdValue = self::generateNameIdValue($idpMetadata, $spMetadata, $state);
998 $nameId = new \SAML2\XML\saml\NameID();
1001 $nameId->SPNameQualifier = $spNameQualifier;
1004 $state[
'saml:idp:NameID'] =
$nameId;
1037 \
SAML2\Assertion $assertion
1040 $encryptAssertion = $spMetadata->
getBoolean(
'assertion.encryption', null);
1041 if ($encryptAssertion === null) {
1042 $encryptAssertion = $idpMetadata->
getBoolean(
'assertion.encryption',
false);
1044 if (!$encryptAssertion) {
1050 $sharedKey = $spMetadata->
getString(
'sharedkey', null);
1051 if ($sharedKey !== null) {
1053 $key->loadKey($sharedKey);
1057 switch (
$key[
'type']) {
1058 case 'X509Certificate':
1059 $pemKey =
"-----BEGIN CERTIFICATE-----\n".
1060 chunk_split(
$key[
'X509Certificate'], 64).
1061 "-----END CERTIFICATE-----\n";
1069 $key->loadKey($pemKey);
1072 $ea = new \SAML2\EncryptedAssertion();
1073 $ea->setAssertion($assertion,
$key);
1097 $lr->setSessionIndex($association[
'saml:SessionIndex']);
1098 $lr->setNameId($association[
'saml:NameID']);
1133 $signResponse = $spMetadata->
getBoolean(
'saml20.sign.response', null);
1134 if ($signResponse === null) {
1135 $signResponse = $idpMetadata->
getBoolean(
'saml20.sign.response',
true);
1138 $r = new \SAML2\Response();
1140 $r->setIssuer($idpMetadata->
getString(
'entityid'));
1141 $r->setDestination($consumerURL);
1143 if ($signResponse) {
handleLogoutRequest(array &$state, $assocId)
Process a logout request.
const BINDING_HOK_SSO
The URN for the Holder-of-Key Web Browser SSO Profile binding.
static sendLogoutRequest(SimpleSAML_IdP $idp, array $association, $relayState)
Send a logout request to a given association.
getEndpoints($endpointType)
Helper function for dealing with metadata endpoints.
static generateID()
Generate a random identifier, ID_LENGTH bytes long.
handleAuthenticationRequest(array &$state)
Process authentication requests.
static validateMessage(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
Check signature on a SAML2 message if enabled.
const RESTART
The index in the state array which contains the restart URL.
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
static getByState(array &$state)
Retrieve the IdP "owning" the state.
static encodeAttributes(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array $attributes)
Helper function for encoding attributes.
getArray($name, $default=self::REQUIRED_OPTION)
This function retrieves an array configuration option.
log($default_level)
Print the exception to the log, by default with log level error.
static getBinding($urn)
Retrieve a binding with the given URN.
$sc SubjectConfirmationData
const CM_HOK
Holder-of-Key subject confirmation method.
static getCurrentBinding()
Guess the current binding.
static getSecretSalt()
Retrieve the secret salt.
static handleAuthError(SimpleSAML_Error_Exception $exception, array $state)
Handle authentication error.
static buildLogoutRequest(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Build a logout request based on information in the metadata.
$metadata['__DYNAMIC:1__']
static encryptAssertion(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, \SAML2\Assertion $assertion)
Encrypt an assertion.
static sendLogoutResponse(SimpleSAML_IdP $idp, array $state)
Send a logout response.
handleLogoutResponse($assocId, $relayState, SimpleSAML_Error_Exception $error=null)
Process a logout response.
static receiveAuthnRequest(SimpleSAML_IdP $idp)
Receive an authentication request.
static getModuleURL($resource, array $parameters=array())
Get absolute URL to a specified module resource.
static getAssertionConsumerService(array $supportedBindings, SimpleSAML_Configuration $spMetadata, $AssertionConsumerServiceURL, $ProtocolBinding, $AssertionConsumerServiceIndex)
Find SP AssertionConsumerService based on parameter in AuthnRequest.
static generateNameIdValue(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array &$state)
Calculate the NameID value that should be used.
if(!array_key_exists('stateid', $_REQUEST)) $state
Handle linkback() response from LinkedIn.
Attribute-related utility methods.
catch(Exception $e) $message
static getAssociationConfig(SimpleSAML_IdP $idp, array $association)
Retrieve the metadata for the given SP association.
getDefaultEndpoint($endpointType, array $bindings=null, $default=self::REQUIRED_OPTION)
Find the default endpoint of the given type.
static buildResponse(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, $consumerURL)
Build a authentication response based on information in the metadata.
const CM_BEARER
Bearer subject confirmation method.
const EXCEPTION_HANDLER_FUNC
The index in the state array which contains the exception handler function.
static getLogoutURL(SimpleSAML_IdP $idp, array $association, $relayState)
Retrieve a logout URL for a given logout association.
getConfig()
Retrieve the configuration for this IdP.
const BINDING_HTTP_ARTIFACT
The URN for the HTTP-ARTIFACT binding.
static addSign(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\SignedElement $element)
Add signature key and sender certificate to an element (Message or Assertion).
getBoolean($name, $default=self::REQUIRED_OPTION)
This function retrieves a boolean configuration option.
static sendResponse(array $state)
Send a response to the SP.
static buildAssertion(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array &$state)
Build an assertion based on information in the metadata.
Create styles array
The data for the language used.
getId()
Retrieve the ID of this IdP.
const NAMEID_TRANSIENT
Transient NameID format.
static fromException(Exception $exception)
Create a SAML2 error from an exception.
static buildLogoutRequest(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array $association, $relayState)
Build a logout request based on information in the metadata.
getInteger($name, $default=self::REQUIRED_OPTION)
This function retrieves an integer configuration option.
static getEncryptionKey(SimpleSAML_Configuration $metadata)
Retrieve the encryption key for the given entity.
static getResponseError(\SAML2\StatusResponse $response)
Retrieve the status code of a response as a sspmod_saml_Error.
getPublicKeys($use=null, $required=false, $prefix='')
Get public key from metadata.
if(!isset($associations[$assocId])) $association
getString($name, $default=self::REQUIRED_OPTION)
This function retrieves a string configuration option.
static checkSessionCookie($retryURL=null)
Check for session cookie, and show missing-cookie page if it is missing.
if(!isset($_REQUEST['association'])) $assocId
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
hash(StreamInterface $stream, $algo, $rawOutput=false)
Calculate a hash of a Stream.
static receiveLogoutMessage(SimpleSAML_IdP $idp)
Receive a logout message.
static getAttributeNameFormat(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata)
Determine which NameFormat we should use for attributes.
static loadFromArray($config, $location='[ARRAY]', $instance=null)
Loads a configuration from the given array.
static getInstance($instancename='simplesaml')
Get a configuration file by its instance name.
static buildLogoutResponse(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Build a logout response based on information in the metadata.
static log($event, array $data=array())
Notify about an event.