/**
  * 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;
 }