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) || $AssertionConsumerServiceURL ===
null);
170 assert(is_string($ProtocolBinding) || $ProtocolBinding ===
null);
171 assert(is_int($AssertionConsumerServiceIndex) || $AssertionConsumerServiceIndex ===
null);
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)) {
265 if (isset($_REQUEST[
'spentityid'])) {
268 if (isset($_REQUEST[
'cookieTime'])) {
269 $cookieTime = (int) $_REQUEST[
'cookieTime'];
270 if ($cookieTime + 5 > time()) {
282 if (isset($_REQUEST[
'RelayState'])) {
288 if (isset($_REQUEST[
'binding'])) {
289 $protocolBinding = (string) $_REQUEST[
'binding'];
291 $protocolBinding =
null;
294 if (isset($_REQUEST[
'NameIDFormat'])) {
295 $nameIDFormat = (string) $_REQUEST[
'NameIDFormat'];
297 $nameIDFormat =
null;
307 $consumerIndex =
null;
310 $authnContext =
null;
316 'SAML2.0 - IdP.SSOService: IdP initiated authentication: '.var_export(
$spEntityId,
true)
324 'Message received on authentication request endpoint wasn\'t an authentication request.'
331 'Received message on authentication request endpoint without issuer.'
342 $ProxyCount =
$request->getProxyCount();
343 if ($ProxyCount !==
null) {
346 $RequesterID =
$request->getRequesterID();
347 $forceAuthn =
$request->getForceAuthn();
348 $isPassive =
$request->getIsPassive();
349 $consumerURL =
$request->getAssertionConsumerServiceURL();
350 $protocolBinding =
$request->getProtocolBinding();
351 $consumerIndex =
$request->getAssertionConsumerServiceIndex();
352 $extensions =
$request->getExtensions();
353 $authnContext =
$request->getRequestedAuthnContext();
355 $nameIdPolicy =
$request->getNameIdPolicy();
356 if (isset($nameIdPolicy[
'Format'])) {
357 $nameIDFormat = $nameIdPolicy[
'Format'];
359 $nameIDFormat =
null;
361 if (isset($nameIdPolicy[
'AllowCreate'])) {
362 $allowCreate = $nameIdPolicy[
'AllowCreate'];
364 $allowCreate =
false;
370 'SAML2.0 - IdP.SSOService: incoming authentication request: '.var_export(
$spEntityId,
true)
377 'forceAuthn' => $forceAuthn,
378 'isPassive' => $isPassive,
379 'protocol' =>
'saml2',
380 'idpInit' => $idpInit,
391 $IDPList = array_unique(array_merge($IDPList,
$spMetadata->getArrayizeString(
'IDPList', array())));
392 if ($ProxyCount ===
null) {
393 $ProxyCount =
$spMetadata->getInteger(
'ProxyCount',
null);
397 $forceAuthn =
$spMetadata->getBoolean(
'ForceAuthn',
false);
400 $sessionLostParams = array(
402 'cookieTime' => time(),
408 $sessionLostURL = \SimpleSAML\Utils\HTTP::addURLParameters(
414 'Responder' => array(
'sspmod_saml_IdP_SAML2',
'sendResponse'),
420 'saml:RequestId' => $requestId,
421 'saml:IDPList' => $IDPList,
422 'saml:ProxyCount' => $ProxyCount,
423 'saml:RequesterID' => $RequesterID,
424 'ForceAuthn' => $forceAuthn,
425 'isPassive' => $isPassive,
426 'saml:ConsumerURL' => $acsEndpoint[
'Location'],
427 'saml:Binding' => $acsEndpoint[
'Binding'],
428 'saml:NameIDFormat' => $nameIDFormat,
429 'saml:AllowCreate' => $allowCreate,
430 'saml:Extensions' => $extensions,
431 'saml:AuthnRequestReceivedAt' => microtime(
true),
432 'saml:RequestedAuthnContext' => $authnContext,
478 'SingleLogoutService',
480 \
SAML2\Constants::BINDING_HTTP_REDIRECT,
481 \
SAML2\Constants::BINDING_HTTP_POST
486 $lr->setDestination(
$dst[
'Location']);
500 assert(isset(
$state[
'saml:SPEntityId']));
501 assert(isset(
$state[
'saml:RequestId']));
502 assert(array_key_exists(
'saml:RelayState',
$state));
511 $lr->setInResponseTo(
$state[
'saml:RequestId']);
512 $lr->setRelayState(
$state[
'saml:RelayState']);
514 if (isset(
$state[
'core:Failed']) &&
$state[
'core:Failed']) {
516 $lr->setStatus(array(
517 'Code' => \
SAML2\Constants::STATUS_SUCCESS,
518 'SubCode' => \
SAML2\Constants::STATUS_PARTIAL_LOGOUT,
529 'partial' => $partial
532 'SingleLogoutService',
534 \
SAML2\Constants::BINDING_HTTP_REDIRECT,
535 \
SAML2\Constants::BINDING_HTTP_POST
539 if (isset(
$dst[
'ResponseLocation'])) {
581 $statsData[
'error'] =
$message->getStatus();
608 'Responder' => array(
'sspmod_saml_IdP_SAML2',
'sendLogoutResponse'),
610 'saml:RelayState' =>
$message->getRelayState(),
611 'saml:RequestId' =>
$message->getId(),
642 \
SAML2\Constants::BINDING_HTTP_REDIRECT,
643 \
SAML2\Constants::BINDING_HTTP_POST
647 if (
$dst[
'Binding'] === \
SAML2\Constants::BINDING_HTTP_POST) {
656 $lr->setDestination(
$dst[
'Location']);
658 $binding = new \SAML2\HTTPRedirect();
676 }
catch (Exception $e) {
697 $attribute =
$spMetadata->getString(
'simplesaml.nameidattribute',
null);
698 if ($attribute ===
null) {
699 $attribute =
$idpMetadata->getString(
'simplesaml.nameidattribute',
null);
700 if ($attribute ===
null) {
701 if (!isset(
$state[
'UserID'])) {
705 $attributeValue =
$state[
'UserID'];
711 $uidData =
'uidhashbase'.$secretSalt;
714 $uidData .= strlen($attributeValue).
':'.$attributeValue;
715 $uidData .= $secretSalt;
717 return hash(
'sha1', $uidData);
724 ' in the attributes of the user.');
749 $base64Attributes =
$spMetadata->getBoolean(
'base64attributes',
null);
750 if ($base64Attributes ===
null) {
751 $base64Attributes =
$idpMetadata->getBoolean(
'base64attributes',
false);
754 if ($base64Attributes) {
755 $defaultEncoding =
'base64';
757 $defaultEncoding =
'string';
760 $srcEncodings =
$idpMetadata->getArray(
'attributeencodings', array());
761 $dstEncodings =
$spMetadata->getArray(
'attributeencodings', array());
767 $encodings = array_merge($srcEncodings, $dstEncodings);
772 if (array_key_exists(
$name, $encodings)) {
773 $encoding = $encodings[
$name];
775 $encoding = $defaultEncoding;
780 if ($value ===
null) {
786 if ($value instanceof DOMNodeList) {
787 $attrval = new \SAML2\XML\saml\AttributeValue($value->item(0)->parentNode);
792 $value = (string) $attrval;
795 $value = base64_encode((
string) $attrval);
798 if (is_string($value)) {
800 $value = $doc->firstChild->childNodes;
802 assert($value instanceof DOMNodeList || $value instanceof \
SAML2\XML\saml\NameID);
806 var_export(
$name,
true).
': '.var_export($encoding,
true));
850 return 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic';
870 assert(isset(
$state[
'Attributes']));
871 assert(isset(
$state[
'saml:ConsumerURL']));
875 $signAssertion =
$spMetadata->getBoolean(
'saml20.sign.assertion',
null);
876 if ($signAssertion ===
null) {
877 $signAssertion =
$idpMetadata->getBoolean(
'saml20.sign.assertion',
true);
882 $a = new \SAML2\Assertion();
883 if ($signAssertion) {
888 $a->setValidAudiences(array(
$spMetadata->getString(
'entityid')));
890 $a->setNotBefore($now - 30);
898 if (isset(
$state[
'saml:AuthnContextClassRef'])) {
899 $a->setAuthnContextClassRef(
$state[
'saml:AuthnContextClassRef']);
900 } elseif (\
SimpleSAML\Utils\HTTP::isHTTPS()) {
901 $a->setAuthnContextClassRef(\
SAML2\Constants::AC_PASSWORD_PROTECTED_TRANSPORT);
903 $a->setAuthnContext(\
SAML2\Constants::AC_PASSWORD);
906 $sessionStart = $now;
907 if (isset(
$state[
'AuthnInstant'])) {
908 $a->setAuthnInstant(
$state[
'AuthnInstant']);
909 $sessionStart =
$state[
'AuthnInstant'];
912 $sessionLifetime =
$config->getInteger(
'session.duration', 8 * 60 * 60);
913 $a->setSessionNotOnOrAfter($sessionStart + $sessionLifetime);
915 $a->setSessionIndex(
SimpleSAML\Utils\Random::generateID());
917 $sc = new \SAML2\XML\saml\SubjectConfirmation();
920 $sc->SubjectConfirmationData->Recipient =
$state[
'saml:ConsumerURL'];
921 $sc->SubjectConfirmationData->InResponseTo =
$state[
'saml:RequestId'];
924 $hokAssertion =
null;
925 if (
$state[
'saml:Binding'] === \
SAML2\Constants::BINDING_HOK_SSO) {
926 $hokAssertion =
true;
928 if ($hokAssertion ===
null) {
929 $hokAssertion =
$idpMetadata->getBoolean(
'saml20.hok.assertion',
false);
936 if (isset(
$_SERVER[
'SSL_CLIENT_CERT']) && !empty(
$_SERVER[
'SSL_CLIENT_CERT'])) {
938 $clientCert =
$_SERVER[
'SSL_CLIENT_CERT'];
939 $pattern =
'/^-----BEGIN CERTIFICATE-----([^-]*)^-----END CERTIFICATE-----/m';
940 if (preg_match($pattern, $clientCert, $matches)) {
942 $x509Certificate = new \SAML2\XML\ds\X509Certificate();
943 $x509Certificate->certificate = str_replace(array(
"\r",
"\n",
" "),
'', $matches[1]);
945 $x509Data = new \SAML2\XML\ds\X509Data();
946 $x509Data->data[] = $x509Certificate;
948 $keyInfo = new \SAML2\XML\ds\KeyInfo();
949 $keyInfo->info[] = $x509Data;
951 $sc->SubjectConfirmationData->info[] = $keyInfo;
954 'Error creating HoK assertion: No valid client certificate provided during TLS handshake '.
960 'Error creating HoK assertion: No client certificate provided during TLS handshake with IdP'
965 'Error creating HoK assertion: No HTTPS connection to IdP, but required for Holder-of-Key SSO'
972 $a->setSubjectConfirmation(array(
$sc));
975 if (
$spMetadata->getBoolean(
'simplesaml.attributes',
true)) {
983 if (isset(
$state[
'saml:NameIDFormat'])) {
1001 $spNameQualifier =
$spMetadata->getString(
'SPNameQualifier',
null);
1002 if ($spNameQualifier ===
null) {
1003 $spNameQualifier =
$spMetadata->getString(
'entityid');
1020 $nameId = new \SAML2\XML\saml\NameID();
1023 $nameId->SPNameQualifier = $spNameQualifier;
1059 \
SAML2\Assertion $assertion
1062 $encryptAssertion =
$spMetadata->getBoolean(
'assertion.encryption',
null);
1063 if ($encryptAssertion ===
null) {
1064 $encryptAssertion =
$idpMetadata->getBoolean(
'assertion.encryption',
false);
1066 if (!$encryptAssertion) {
1072 $sharedKey =
$spMetadata->getString(
'sharedkey',
null);
1073 if ($sharedKey !==
null) {
1075 $key->loadKey($sharedKey);
1078 if (!empty(
$keys)) {
1080 switch (
$key[
'type']) {
1081 case 'X509Certificate':
1082 $pemKey =
"-----BEGIN CERTIFICATE-----\n".
1083 chunk_split(
$key[
'X509Certificate'], 64).
1084 "-----END CERTIFICATE-----\n";
1091 $key =
new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array(
'type' =>
'public'));
1092 $key->loadKey($pemKey);
1094 throw new SimpleSAML_Error_ConfigurationError(
1095 'Missing encryption key for entity `' .
$spMetadata->getString(
'entityid') .
'`',
1102 $ea = new \SAML2\EncryptedAssertion();
1103 $ea->setAssertion($assertion,
$key);
1163 $signResponse =
$spMetadata->getBoolean(
'saml20.sign.response',
null);
1164 if ($signResponse ===
null) {
1165 $signResponse =
$idpMetadata->getBoolean(
'saml20.sign.response',
true);
1168 $r = new \SAML2\Response();
1171 $r->setDestination($consumerURL);
1173 if ($signResponse) {
$metadata['__DYNAMIC:1__']
foreach($paths as $path) $request
$sc SubjectConfirmationData
if(!array_key_exists('stateid', $_REQUEST)) $state
Handle linkback() response from LinkedIn.
An exception for terminatinating execution or to throw for unit testing.
static getCurrentBinding()
Guess the current binding.
static getBinding($urn)
Retrieve a binding with the given URN.
const BINDING_HOK_SSO
The URN for the Holder-of-Key Web Browser SSO Profile binding.
const NAMEID_TRANSIENT
Transient NameID format.
const CM_BEARER
Bearer subject confirmation method.
const BINDING_HTTP_ARTIFACT
The URN for the HTTP-ARTIFACT binding.
const CM_HOK
Holder-of-Key subject confirmation method.
const BINDING_PAOS
The URN for the PAOS binding.
static getModuleURL($resource, array $parameters=array())
Get absolute URL to a specified module resource.
static getSecretSalt()
Retrieve the secret salt.
static checkSessionCookie($retryURL=null)
Check for session cookie, and show missing-cookie page if it is missing.
static generateID()
Generate a random identifier, ID_LENGTH bytes long.
const EXCEPTION_HANDLER_FUNC
The index in the state array which contains the exception handler function.
const RESTART
The index in the state array which contains the restart URL.
static getInstance($instancename='simplesaml')
Get a configuration file by its instance name.
static loadFromArray($config, $location='[ARRAY]', $instance=null)
Loads a configuration from the given array.
log($default_level)
Print the exception to the log, by default with log level error.
static getByState(array &$state)
Retrieve the IdP "owning" the state.
static log($event, array $data=array())
Notify about an event.
static fromException(Exception $exception)
Create a SAML2 error from an exception.
static sendLogoutResponse(SimpleSAML_IdP $idp, array $state)
Send a logout response.
static receiveAuthnRequest(SimpleSAML_IdP $idp)
Receive an authentication request.
static handleAuthError(SimpleSAML_Error_Exception $exception, array $state)
Handle authentication error.
static buildAssertion(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array &$state)
Build an assertion based on information in the metadata.
static getAssociationConfig(SimpleSAML_IdP $idp, array $association)
Retrieve the metadata for the given SP association.
static getLogoutURL(SimpleSAML_IdP $idp, array $association, $relayState)
Retrieve a logout URL for a given logout association.
static receiveLogoutMessage(SimpleSAML_IdP $idp)
Receive a logout message.
static buildLogoutRequest(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array $association, $relayState)
Build a logout request based on information in the metadata.
static getAttributeNameFormat(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata)
Determine which NameFormat we should use for attributes.
static processSOAPAuthnRequest(array &$state)
static sendLogoutRequest(SimpleSAML_IdP $idp, array $association, $relayState)
Send a logout request to a given association.
static encodeAttributes(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array $attributes)
Helper function for encoding attributes.
static generateNameIdValue(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array &$state)
Calculate the NameID value that should be used.
static sendResponse(array $state)
Send a response to the SP.
static encryptAssertion(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, \SAML2\Assertion $assertion)
Encrypt an assertion.
static getAssertionConsumerService(array $supportedBindings, SimpleSAML_Configuration $spMetadata, $AssertionConsumerServiceURL, $ProtocolBinding, $AssertionConsumerServiceIndex)
Find SP AssertionConsumerService based on parameter in AuthnRequest.
static buildResponse(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, $consumerURL)
Build a authentication response based on information in the metadata.
static getResponseError(\SAML2\StatusResponse $response)
Retrieve the status code of a response as a sspmod_saml_Error.
static addSign(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\SignedElement $element)
Add signature key and sender certificate to an element (Message or Assertion).
static buildLogoutRequest(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Build a logout request based on information in the metadata.
static buildLogoutResponse(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Build a logout response based on information in the metadata.
static getEncryptionKey(SimpleSAML_Configuration $metadata)
Retrieve the encryption key for the given entity.
static validateMessage(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
Check signature on a SAML2 message if enabled.
if(array_key_exists('yes', $_REQUEST)) $attributes
catch(Exception $e) $message
if(!isset($associations[$assocId])) $association
if(!isset($_REQUEST['association'])) $assocId
hash(StreamInterface $stream, $algo, $rawOutput=false)
Calculate a hash of a Stream.
Attribute-related utility methods.
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']