function convert_metadata($xmldata) { $config = SimpleSAML_Configuration::getInstance(); if ($xmldata) { $xmldata = htmlspecialchars_decode($xmldata); SimpleSAML_Utilities::validateXMLDocument($xmldata, 'saml-meta'); $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsString($xmldata); foreach ($entities as &$entity) { $entity = array('shib13-sp-remote' => $entity->getMetadata1xSP(), 'shib13-idp-remote' => $entity->getMetadata1xIdP(), 'saml20-sp-remote' => $entity->getMetadata20SP(), 'saml20-idp-remote' => $entity->getMetadata20IdP()); } $output = array($entity['saml20-sp-remote']['entityid'] => $entity['saml20-sp-remote']); } else { $xmldata = ''; $output = array(); } return $output; }
/** * Decode a received response. * * @param array $post POST data received. * @return SimpleSAML_XML_Shib13_AuthnResponse Response. */ public function decodeResponse($post) { assert('is_array($post)'); if (!array_key_exists('SAMLResponse', $post)) { throw new Exception('Missing required SAMLResponse parameter.'); } $rawResponse = $post['SAMLResponse']; $samlResponseXML = base64_decode($rawResponse); SimpleSAML_Utilities::debugMessage($samlResponseXML, 'in'); SimpleSAML_Utilities::validateXMLDocument($samlResponseXML, 'saml11'); $samlResponse = new SimpleSAML_XML_Shib13_AuthnResponse(); $samlResponse->setXML($samlResponseXML); if (array_key_exists('TARGET', $post)) { $samlResponse->setRelayState($post['TARGET']); } return $samlResponse; }
} function requireOwnership($metadata, $userid) { if (!isset($metadata['owner'])) { throw new Exception('Metadata has no owner. Which means no one is granted access, not even you.'); } if ($metadata['owner'] !== $userid) { throw new Exception('Metadata has an owner that is not equal to your userid, hence you are not granted access.'); } } if (array_key_exists('entityid', $_REQUEST)) { $metadata = $mdh->getMetadata($_REQUEST['entityid'], 'saml20-sp-remote'); requireOwnership($metadata, $userid); } elseif (array_key_exists('xmlmetadata', $_REQUEST)) { $xmldata = $_REQUEST['xmlmetadata']; SimpleSAML_Utilities::validateXMLDocument($xmldata, 'saml-meta'); $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsString($xmldata); $entity = array_pop($entities); $metadata = $entity->getMetadata20SP(); } else { $metadata = array('owner' => $userid); } $editor = new sspmod_metaedit_MetaEditor(); if (isset($_POST['submit'])) { $editor->checkForm($_POST); $metadata = $editor->formToMeta($_POST, array(), array('owner' => $userid)); if (isset($_REQUEST['was-entityid']) && $_REQUEST['was-entityid'] !== $metadata['entityid']) { $premetadata = $mdh->getMetadata($_REQUEST['was-entityid'], 'saml20-sp-remote'); requireOwnership($premetadata, $userid); $mdh->deleteMetadata($_REQUEST['was-entityid'], 'saml20-sp-remote'); }
* This should also be stored in your production datastore. */ $metadata_url_for = array(); foreach ($metadata_url_for as $idp_name => $metadata_url) { /* * Fetch SAML metadata from the URL. * NOTE: * SAML metadata changes very rarely. On a production system, * this data should be cached as approprate for your production system. */ $metadata_xml = file_get_contents($metadata_url); /* * Parse the SAML metadata using SimpleSAMLphp's parser. * See also: modules/metaedit/www/edit.php:34 */ SimpleSAML_Utilities::validateXMLDocument($metadata_xml, 'saml-meta'); $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsString($metadata_xml); $entity = array_pop($entities); $idp = $entity->getMetadata20IdP(); $entity_id = $idp['entityid']; /* * Remove HTTP-POST endpoints from metadata, * since we only want to make HTTP-GET AuthN requests. */ for ($x = 0; $x < sizeof($idp['SingleSignOnService']); $x++) { $endpoint = $idp['SingleSignOnService'][$x]; if ($endpoint['Binding'] == 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST') { unset($idp['SingleSignOnService'][$x]); } } /*
function transaleXMLToSsPHP($xmldata) { if (!empty($xmldata)) { SimpleSAML_Utilities::validateXMLDocument($xmldata, 'saml-meta'); $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsString($xmldata); /* Get all metadata for the entities. */ foreach ($entities as &$entity) { $entity = array('saml20-sp-remote' => $entity->getMetadata20SP(), 'saml20-idp-remote' => $entity->getMetadata20IdP()); } /* Transpose from $entities[entityid][type] to $output[type][entityid]. */ $output = SimpleSAML_Utilities::transposeArray($entities); /* Merge all metadata of each type to a single string which should be * added to the corresponding file. */ foreach ($output as $type => &$entities) { $text = ''; foreach ($entities as $entityId => $entityMetadata) { if ($entityMetadata === NULL) { continue; } /* Remove the entityDescriptor element because it is unused, and only * makes the output harder to read. */ unset($entityMetadata['entityDescriptor']); $text .= '$metadata[' . var_export($entityId, TRUE) . '] = ' . var_export($entityMetadata, TRUE) . ";\n"; } $entities = $text; } } else { $output = array(); } return $output; }
/** * Accept a SAML Request and form a Response * NOTE: that this function is Google Specific * */ function gsaml_send_auth_response($samldata) { global $CFG, $SESSION, $USER; SimpleSAML_Configuration::init($CFG->dirroot . '/auth/gsaml/config'); $config = SimpleSAML_Configuration::getInstance(); $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $session = SimpleSAML_Session::getInstance(); try { $idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted'); $idmetaindex = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted', 'metaindex'); $idpmetadata = $metadata->getMetaDataCurrent('saml20-idp-hosted'); if (!array_key_exists('auth', $idpmetadata)) { throw new Exception('Missing mandatory parameter in SAML 2.0 IdP Hosted Metadata: [auth]'); } } catch (Exception $exception) { SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception); } /// SimpleSAML_Logger::info('SAML2.0 - IdP.SSOService: Accessing SAML 2.0 IdP endpoint SSOService'); if (!$config->getValue('enable.saml20-idp', false)) { SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS'); } $rawRequest = $samldata; if (!empty($SESSION->samlrelaystate)) { $relaystate = $SESSION->samlrelaystate; } else { $relaystate = NULL; } $decodedRequest = @base64_decode($rawRequest); if (!$decodedRequest) { throw new Exception('Could not base64 decode SAMLRequest GET parameter'); } $samlRequestXML = @gzinflate($decodedRequest); if (!$samlRequestXML) { $error = error_get_last(); throw new Exception('Could not gzinflate base64 decoded SAMLRequest: ' . $error['message']); } SimpleSAML_Utilities::validateXMLDocument($samlRequestXML, 'saml20'); $samlRequest = new SimpleSAML_XML_SAML20_AuthnRequest($config, $metadata); $samlRequest->setXML($samlRequestXML); if (!is_null($relaystate)) { $samlRequest->setRelayState($relaystate); } // $samlRequest presenting the request object $authnrequest = $samlRequest; if ($session == NULL) { debugging('No SAML Session gsaml_send_auth_response', DEBUG_DEVELOPER); return false; // if this func returns we Know it's an error } if (!empty($USER->id)) { // TODO: if moodle user is not the same as google user // use the mapping $username = $USER->username; } else { debugging('No User given to gsaml_send_auth_response', DEBUG_DEVELOPER); return false; } //TODO: better errors if (!($domain = get_config('auth/gsaml', 'domainname'))) { debugging('No domain set in gsaml_send_auth_response', DEBUG_DEVELOPER); return false; // if this func returns we Know it's an error } $attributes['useridemail'] = array($username . '@' . $domain); $session->doLogin('login'); // was login $session->setAttributes($attributes); $session->setNameID(array('value' => SimpleSAML_Utilities::generateID(), 'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient')); $requestcache = array('RequestID' => $authnrequest->getRequestID(), 'Issuer' => $authnrequest->getIssuer(), 'ConsentCookie' => SimpleSAML_Utilities::generateID(), 'RelayState' => $authnrequest->getRelayState()); try { $spentityid = $requestcache['Issuer']; $spmetadata = $metadata->getMetaData($spentityid, 'saml20-sp-remote'); $sp_name = isset($spmetadata['name']) ? $spmetadata['name'] : $spentityid; // TODO: Are we really tracking SP's??? // // Adding this service provider to the list of sessions. // Right now the list is used for SAML 2.0 only. $session->add_sp_session($spentityid); /// SimpleSAML_Logger::info('SAML2.0 - IdP.SSOService: Sending back AuthnResponse to ' . $spentityid); // TODO: handle passive situtation // Rigth now I replaced $isPassive with isset($isPassive) to prevent notice on debug mode if (isset($isPassive)) { /* Generate an SAML 2.0 AuthNResponse message With statusCode: urn:oasis:names:tc:SAML:2.0:status:NoPassive */ $ar = new SimpleSAML_XML_SAML20_AuthnResponse($config, $metadata); $authnResponseXML = $ar->generate($idpentityid, $spentityid, $requestcache['RequestID'], null, array(), 'NoPassive'); // Sending the AuthNResponse using HTTP-Post SAML 2.0 binding $httppost = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata); $httppost->sendResponse($authnResponseXML, $idpentityid, $spentityid, $requestcache['RelayState']); exit; } /* * Attribute handling */ $attributes = $session->getAttributes(); $afilter = new SimpleSAML_XML_AttributeFilter($config, $attributes); $afilter->process($idpmetadata, $spmetadata); // KEEP this code for REFERENCE // /** // * Make a log entry in the statistics for this SSO login. // */ // $tempattr = $afilter->getAttributes(); // $realmattr = $config->getValue('statistics.realmattr', null); // $realmstr = 'NA'; // if (!empty($realmattr)) { // //error_log('SSO 420: if (!empty($realmattr)) {\n ',0); // if (array_key_exists($realmattr, $tempattr) && is_array($tempattr[$realmattr]) ) { // $realmstr = $tempattr[$realmattr][0]; // } else { // SimpleSAML_Logger::warning('Could not get realm attribute to log [' . $realmattr. ']'); // } // } // SimpleSAML_Logger::stats('saml20-idp-SSO ' . $spentityid . ' ' . $idpentityid . ' ' . $realmstr); // // $afilter->processFilter($idpmetadata, $spmetadata); $filteredattributes = $afilter->getAttributes(); // // KEEP THIS CODE FOR RERFERENCE // /* // * Dealing with attribute release consent. // */ // $requireconsent = false; // if (isset($idpmetadata['requireconsent'])) { // //error_log('SSO 453: if (isset($idpmetadata[\'requireconsent\']))\n ',0); // if (is_bool($idpmetadata['requireconsent'])) { // $requireconsent = $idpmetadata['requireconsent']; // } else { // throw new Exception('SAML 2.0 IdP hosted metadata parameter [requireconsent] is in illegal format, must be a PHP boolean type.'); // } // } // if ($requireconsent) { // // $consent = new SimpleSAML_Consent_Consent($config, $session, $spentityid, $idpentityid, $attributes, $filteredattributes, $requestcache['ConsentCookie']); // // if (!$consent->consent()) { // /* Save the request information. */ // $authId = SimpleSAML_Utilities::generateID(); // $session->setAuthnRequest('saml2', $authId, $requestcache); // // $t = new SimpleSAML_XHTML_Template($config, 'consent.php', 'attributes.php'); // $t->data['header'] = 'Consent'; // $t->data['sp_name'] = $sp_name; // $t->data['attributes'] = $filteredattributes; // $t->data['consenturl'] = SimpleSAML_Utilities::selfURLNoQuery();//$selfURLNoQuery; //SimpleSAML_Utilities::selfURLNoQuery(); DEBUG // $t->data['requestid'] = $authId; // $t->data['consent_cookie'] = $requestcache['ConsentCookie']; // $t->data['usestorage'] = $consent->useStorage(); // $t->data['noconsent'] = '/' . $config->getBaseURL() . 'noconsent.php'; // $t->show(); // exit; // } // // } // // END ATTRIBUTE CONSENT CODE // Generate the SAML 2.0 AuthNResponse message $ar = new SimpleSAML_XML_SAML20_AuthnResponse($config, $metadata); $authnResponseXML = $ar->generate($idpentityid, $spentityid, $requestcache['RequestID'], null, $filteredattributes); // TODO: clean the $SESSION->samlrelaystate so we don't accidently call it again // Sending the AuthNResponse using HTTP-Post SAML 2.0 binding $httppost = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata); $httppost->sendResponse($authnResponseXML, $idmetaindex, $spentityid, $requestcache['RelayState']); die; // VERY IMPORTANT BUG FIX to stop outputing the rest of the page. } catch (Exception $exception) { // TODO: better error reporting debugging('<pre>' . print_r($exception, true) . '</pre>', DEBUG_DEVELOPER); return false; } }
public function decodeLogoutResponse($get) { if (!isset($get['SAMLResponse'])) { throw new Exception('SAMLResponse parameter not set in paramter (on SAML 2.0 HTTP Redirect binding endpoint)'); } $rawRequest = $get["SAMLResponse"]; /* Check if a RelayState was provided with the request. */ if (array_key_exists('RelayState', $get)) { $relaystate = $get['RelayState']; } else { $relaystate = NULL; } $decodedRequest = @base64_decode($rawRequest); if (!$decodedRequest) { throw new Exception('Could not base64 decode SAMLRequest GET parameter'); } $samlRequestXML = @gzinflate($decodedRequest); if (!$samlRequestXML) { $error = error_get_last(); throw new Exception('Could not gzinflate base64 decoded SAMLRequest: ' . $error['message']); } SimpleSAML_Utilities::validateXMLDocument($samlRequestXML, 'saml20'); $samlRequest = new SimpleSAML_XML_SAML20_LogoutResponse($this->configuration, $this->metadata); $samlRequest->setXML($samlRequestXML); if (isset($relaystate)) { $samlRequest->setRelayState($relaystate); } #echo("Authn response = " . $samlResponse ); return $samlRequest; }
public function decodeResponse($post) { if (!isset($post["SAMLResponse"])) { throw new Exception('Could not get SAMLResponse from Browser/POST. May be there is some redirection related problem on your server? In example apache redirecting the POST to http to a GET on https.'); } $rawResponse = $post["SAMLResponse"]; $relaystate = $post["RelayState"]; $samlResponseXML = base64_decode($rawResponse); SimpleSAML_Utilities::validateXMLDocument($samlResponseXML, 'saml20'); //error_log("Response is: " . $samlResponseXML); $samlResponse = new SimpleSAML_XML_SAML20_AuthnResponse($this->configuration, $this->metadata); $samlResponse->setXML($samlResponseXML); if (isset($relaystate)) { $samlResponse->setRelayState($relaystate); } #echo("Authn response = " . $samlResponse ); return $samlResponse; }