/** * Handle an authentication request. * * @param array $params * @return void * */ public function singleSignOnService($params) { if ($this->_server->callfilters('init')) { $request = $this->_server->getBindingsModule()->receiveRequest($params); /** * We are always a proxy so if the scoped proxycount == 0, respond with a ProxyCountExceeded error * @todo register path length in cached responses and use in proxyCount check ?? */ if (nvl2($request, 'samlp:Scoping', '_ProxyCount') === 0) { $response = $this->_server->createErrorResponse($request, 'ProxyCountExceeded'); return $this->_server->sendResponseToRequestIssuer($request, $response); } // Get all registered Single Sign On Services $candidateIDPs = $this->_server->getAllowedIdps(); // No IdPs found! Send an error response back. if (empty($candidateIDPs)) { $response = $this->_server->createErrorResponse($request, 'NoSupportedIDP'); return $this->_server->sendResponseToRequestIssuer($request, $response); } // If we configured an IDPList in metadata this is our primary scoping $scopedIDPs = $this->_server->getPresetIDPs(); /** * Add scoping in request to configured scoping - this is NOT according to the spec * which says that you MUST append to a received IDPList */ foreach ((array) nvl3($request, 'samlp:Scoping', 'samlp:IDPList', 'samlp:IDPEntry') as $IDPEntry) { $scopedIDPs[] = $IDPEntry['_ProviderID']; } // remove issuer + us from scope for use now .. $requesterIDs = array($params['EntityID'], $request['saml:Issuer']['__v']); // filter out already visited proxies (RequesterID) to prevent looping ... foreach ((array) nvl2($request, 'samlp:Scoping', 'samlp:RequesterID') as $requesterID) { $requesterIDs[] = $requesterID['__v']; } $relevantScopedIDPs = array_diff($scopedIDPs, $requesterIDs); // If we have scoping, filter out every non-scoped IdP $scopedCandidateIDPs = array_intersect($relevantScopedIDPs, $candidateIDPs); $state = array(); $filters = $this->_server->getCurrentMD('IDP', 'corto:discoverfilter', null, array()); if (!$filters) { $filters = array('demoFilterClass::showWayf'); } $filterparams = array('request' => $request, 'scopedCandidateIDPs' => $scopedCandidateIDPs, 'relevantScopedIDPs' => $relevantScopedIDPs, 'server' => $this->_server); } /* If we end up her we should show the wayf ... */ if ($this->_server->callfilters("discovery", $state, $filters, $filterparams)) { } }
/** * Handles the reception of SLO responses and sending of new SLO requests. * Deletes information for handled SLO request and finally deletes the session * the original SLO request was sent to. * * @param array $message * @return void * * */ public function handleslo(array $message) { $me = $this->getCurrentMD('entityID'); $inresponseto = $message['_InResponseTo']; $req = db_get('REQ-' . $inresponseto); if ($remote = nvl($req, 'entity')) { db_del($req['type'] . '-' . $req['sessionindex'], sha1($remote)); } $sloinfo = db_get('SLO-' . $req['ID']); $success = 'urn:oasis:names:tc:SAML:2.0:status:Success'; if ($status = nvl2($message, 'samlp:Status', 'samlp:StatusCode')) { if ($status['_Value'] != $success || nvl2($status, 'samlp:StatusCode', '_Value')) { $sloinfo['success'] = false; db_put('SLO-' . $req['request '], $sloinfo); } } foreach ((array) nvl($sloinfo, 'sessions') as $session => $dummy) { foreach (array('IDP', 'SP') as $type) { $responses = db_get($type . '-' . $session, '*'); foreach ($responses as $hashedentity => $info) { if ($info['entity'] == $sloinfo['Issuer']) { db_del($type . '-' . $session, $hashedentity); continue; } $id = ID(); $info['ID'] = $id; $info['type'] = $type; debug("REQ id+", $id); db_put("REQ-{$id}", serialize($info)); $response = $this->sendLogoutRequest($info); if (!$response) { $res = false; } else { $status = $response['samlp:Status']['samlp:StatusCode']; $res = $status['_Value'] != $success || nvl2($status, 'samlp:StatusCode', '_Value'); } if (!$res && $sloinfo['success']) { $sloinfo['success'] = false; db_put('SLO-' . $req['ID'], serialize($sloinfo)); } } db_del('REQ-' . $inresponseto); } delete_corto_session($session); } db_del('SLO-' . $req['ID']); $this->sendLogoutResponse($sloinfo); }
protected static function optimizeMetaData($type, $md, $optimized = array()) { // @note remember not to set keys for things that might be overidden by merged md // ie. set ['saveSLOInfo'] to true, but do not set the ['saveSLOInfo'] at all // when false as it WILL overwrite the true !!! $meta = array(); $rawmeta = $md[$type]; $commonmd = self::merge(nvl($optimized, '_COMMON_'), nvl($rawmeta, '_COMMON_')); unset($rawmeta['_COMMON_']); if ($entitymd = nvl($rawmeta, 'md:EntityDescriptor')) { $rawmeta['md:EntitiesDescriptor'] = array(array('md:EntityDescriptor' => $entitymd)); unset($rawmeta['md:EntityDescriptor']); } foreach ((array) nvl($rawmeta, 'md:EntitiesDescriptor') as $entitiesDescriptor) { $entitiescommon = array(); if (isset($entitiesDescriptor['md:Extensions']['mdattr:EntityAttributes']['saml:Attribute'])) { foreach ((array) $entitiesDescriptor['md:Extensions']['mdattr:EntityAttributes']['saml:Attribute'] as $attribute) { foreach ((array) $attribute['saml:AttributeValue'] as $attributeValue) { $entitiescommon[$attribute['_Name']][] = $attributeValue; } } } $entitiescommon = self::merge($commonmd, $entitiescommon); foreach ((array) $entitiesDescriptor['md:EntityDescriptor'] as $entityDescriptor) { if (empty($entityDescriptor['_entityID'])) { $entityDescriptor['_entityID'] = '_COMMON_'; } $cortoEntityDescriptor = array(); $cortoEntityDescriptor['entityID'] = $entityDescriptor['_entityID']; foreach ((array) nvl3($entityDescriptor, 'md:Extensions', 'mdattr:EntityAttributes', 'saml:Attribute') as $attribute) { foreach ((array) $attribute['saml:AttributeValue'] as $attributeValue) { $cortoEntityDescriptor[$attribute['_Name']][] = $attributeValue; } } foreach ((array) nvl($entityDescriptor, 'md:IDPSSODescriptor') as $idpsso) { foreach (array('SingleSignOnService', 'SingleLogoutService') as $service) { foreach ((array) nvl($idpsso, 'md:' . $service) as $sso) { $cortoEntityDescriptor['IDP'][$service][] = array('Location' => $sso['_Location'], 'Binding' => $sso['_Binding']); } } // metadata overrides auto setting if (empty($cortoEntityDescriptor['IDP']['saveSLOInfo']) && ($saveSLOInfo = (bool) nvl2($cortoEntityDescriptor, 'IDP', 'SingleLogoutService'))) { $cortoEntityDescriptor['IDP']['saveSLOInfo'] = $saveSLOInfo; } } foreach ((array) nvl($entityDescriptor, 'md:SPSSODescriptor') as $spsso) { foreach (array('AssertionConsumerService', 'SingleLogoutService') as $service) { foreach ((array) nvl($spsso, 'md:' . $service) as $acs) { $cortoEntityDescriptor['SP'][$service][$acs['_index']] = array('Location' => $acs['_Location'], 'Binding' => $acs['_Binding'], 'isDefault' => empty($acs['_isDefault']) ? null : $acs['_isDefault']); } } // metadata overrides auto setting if (empty($cortoEntityDescriptor['SP']['saveSLOInfo']) && ($saveSLOInfo = (bool) nvl2($cortoEntityDescriptor, 'SP', 'SingleLogoutService'))) { $cortoEntityDescriptor['SP']['saveSLOInfo'] = $saveSLOInfo; } } // this is the default resolution algorithm from Meta 2.2.3 if (isset($cortoEntityDescriptor['SP']['AssertionConsumerService'])) { $acslist =& $cortoEntityDescriptor['SP']['AssertionConsumerService']; ksort($acslist); $default = null; foreach ((array) $acslist as $index => $acs) { if ($acs['isDefault']) { $default = $index; } } $cortoEntityDescriptor['SP']['AssertionConsumerService']['default'] = $default ? $default : min(array_keys($acslist)); } foreach (self::$descriptors as $descriptor) { foreach ((array) nvl($entityDescriptor, 'md:' . $descriptor . 'SSODescriptor') as $idporsp) { foreach (self::$signings as $signing) { if (isset($idporsp['_' . $signing])) { $cortoEntityDescriptor[$descriptor][$signing] = $idporsp['_' . $signing] == 'true' || $idporsp['_' . $signing] == '1'; } } foreach ((array) nvl3($idporsp, 'md:Extensions', 'mdattr:EntityAttributes', 'saml:Attribute') as $attribute) { #print_r($attribute); foreach ((array) $attribute['saml:AttributeValue'] as $attributeValue) { foreach ($attributeValue as $value) { #print_r($value); $cortoEntityDescriptor[$descriptor][$attribute['_Name']][] = $value; } } } foreach ((array) nvl($idporsp, 'md:KeyDescriptor') as $keyDescriptor) { $use = nvl($keyDescriptor, '_use', 'signing'); if (isset($keyDescriptor['ds:KeyInfo']['ds:X509Data'])) { $cortoEntityDescriptor[$descriptor][$use]['X509Certificate'] = $keyDescriptor['ds:KeyInfo']['ds:X509Data']['ds:X509Certificate']['__v']; } elseif (isset($keyDescriptor['ds:KeyInfo']['ds:KeyName'])) { $cortoEntityDescriptor[$descriptor][$use]['KeyName'] = $keyDescriptor['ds:KeyInfo']['ds:KeyName']['__v']; } /* $cortoEntityDescriptor[$descriptor][$keyDescriptor['_use']]['KeyName'] = $keyDescriptor['ds:KeyInfo']['ds:X509Data']['ds:KeyName']['__v']; */ } foreach ((array) nvl($cortoEntityDescriptor[$descriptor], 'corto:privatekey') as $privatekey) { $cortoEntityDescriptor[$descriptor][$privatekey['_use']]['X509Privatekey'] = $privatekey['__v']; } unset($cortoEntityDescriptor[$descriptor]['corto:privatekey']); $cortoEntityDescriptor[$descriptor] = self::merge(nvl($entitiescommon, $descriptor), nvl($cortoEntityDescriptor, $descriptor)); #unset($common[$descriptor]); } } $meta[$entityDescriptor['_entityID']] = self::merge($entitiescommon, $cortoEntityDescriptor); } } return $meta; }