From d9bf22a0e29c2a70049443a0ae8521a2c0492c8b Mon Sep 17 00:00:00 2001 From: Cash Costello Date: Sun, 11 Dec 2011 06:38:23 -0500 Subject: initial commit for git repository --- .../contrib/signed_assertions/SAML.php | 220 +++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 models/openid-php-openid-782224d/contrib/signed_assertions/SAML.php (limited to 'models/openid-php-openid-782224d/contrib/signed_assertions/SAML.php') diff --git a/models/openid-php-openid-782224d/contrib/signed_assertions/SAML.php b/models/openid-php-openid-782224d/contrib/signed_assertions/SAML.php new file mode 100644 index 000000000..fa6df51f6 --- /dev/null +++ b/models/openid-php-openid-782224d/contrib/signed_assertions/SAML.php @@ -0,0 +1,220 @@ + + ** @author Shishir Randive + ** Stony Brook University. + ** largely derived from + ** + * Copyright (C) 2007 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +class SAML{ + private $assertionTemplate=null; + /** + * Returns a SAML response with various elements filled in. + * @param string $authenticatedUser The OpenId of the user + * @param string $notBefore The ISO 8601 formatted date before which the + response is invalid + * @param string $notOnOrAfter The ISO 8601 formatted data after which the + response is invalid + * @param string $rsadsa 'rsa' if the response will be signed with RSA keys, + 'dsa' for DSA keys + * @param string $requestID The ID of the request we're responding to + * @param string $destination The ACS URL that the response is submitted to + * @return string XML SAML response. + */ + function createSamlAssertion($authenticatedUser, $notBefore, $notOnOrAfter, $rsadsa, $acsURI,$attribute,$value,$assertionTemplate) + { + $samlResponse = $assertionTemplate; + $samlResponse = str_replace('USERNAME_STRING', $authenticatedUser, $samlResponse); + $samlResponse = str_replace('RESPONSE_ID', $this->samlCreateId(), $samlResponse); + $samlResponse = str_replace('ISSUE_INSTANT', $this->samlGetDateTime(time()), $samlResponse); + $samlResponse = str_replace('NOT_BEFORE', $this->samlGetDateTime(strtotime($notBefore)), $samlResponse); + $samlResponse = str_replace('NOT_ON_OR_AFTER', $this->samlGetDateTime(strtotime($notOnOrAfter)),$samlResponse); + $samlResponse = str_replace('ASSERTION_ID',$this->samlCreateId(), $samlResponse); + $samlResponse = str_replace('RSADSA', strtolower($rsadsa), $samlResponse); + $samlResponse = str_replace('ISSUER_DOMAIN', $acsURI, $samlResponse); + $samlResponse = str_replace('ATTRIBUTE_NAME', $attribute, $samlResponse); + $samlResponse = str_replace('ATTRIBUTE_VALUE', $value, $samlResponse); + return $samlResponse; + } + + /** + * Signs a SAML response with the given private key, and embeds the public key. + * @param string $responseXmlString The unsigned Assertion which will be signed + * @param string $priKey Private key to sign the certificate + * @param string $cert Public key certificate of signee + * @return string Signed Assertion + */ + function signAssertion($responseXmlString,$privKey,$cert) + { + if (file_exists("/tmp/xml")) { + $tempFileDir="/tmp/xml/"; + + } else { + mkdir("/tmp/xml",0777); + $tempFileDir="/tmp/xml/"; + } + $tempName = 'saml-response-' . $this->samlCreateId() . '.xml'; + $tempFileName=$tempFileDir.$tempName; + while (file_exists($tempFileName)) + $tempFileName = 'saml-response-' . $this->samlCreateId() . '.xml'; + + if (!$handle = fopen($tempFileName, 'w')) { + return null; + } + if (fwrite($handle, $responseXmlString) === false) { + return null; + } + fclose($handle); + $cmd = 'xmlsec1 --sign --privkey-pem ' . $privKey . + ',' . $cert . ' --output ' . $tempFileName . + '.out ' . $tempFileName; + exec($cmd, $resp); + unlink($tempFileName); + + $xmlResult = @file_get_contents($tempFileName . '.out'); + if (!$xmlResult) { + return null; + } else { + unlink($tempFileName . '.out'); + return $xmlResult; + } + } + + + /** + * Verify a saml response with the given public key. + * @param string $responseXmlString Response to sign + * @param string $rootcert trusted public key certificate + * @return string Signed SAML response + */ + function verifyAssertion($responseXmlString,$rootcert) + { + date_default_timezone_set("UTC"); + if (file_exists("/tmp/xml")) { + $tempFileDir="/tmp/xml/"; + + } else { + mkdir("/tmp/xml",0777); + $tempFileDir="/tmp/xml/"; + } + + $tempName = 'saml-response-' . $this->samlCreateId() . '.xml'; + $tempFileName=$tempFileDir.$tempName; + while (file_exists($tempFileName)) + $tempFileName = 'saml-response-' . $this->samlCreateId() . '.xml'; + + if (!$handle = fopen($tempFileName, 'w')) { + return false; + } + + if (fwrite($handle, $responseXmlString) === false) { + return false; + } + + $p=xml_parser_create(); + $result=xml_parse_into_struct($p,$responseXmlString,$vals,$index); + xml_parser_free($p); + $cert_info=$index["X509CERTIFICATE"]; + $conditions=$index["CONDITIONS"]; + foreach($cert_info as $key=>$value){ + file_put_contents($tempFileName.'.cert',$vals[$value]['value']); + } + $cert=$tempFileName.'.cert'; + $before=0; + $after=0; + foreach($conditions as $key=>$value){ + $before=$vals[$value]['attributes']['NOTBEFORE']; + $after=$vals[$value]['attributes']['NOTONORAFTER']; + } + $before=$this->validSamlDateFormat($before); + $after=$this->validSamlDateFormat($after); + if(strtotime("now") < $before || strtotime("now") >= $after){ + unlink($tempFileName); + unlink($cert); + return false; + } + fclose($handle); + $cmd = 'xmlsec1 --verify --pubkey-cert ' . $cert .'--trusted '.$rootcert. ' '.$tempFileName.'* 2>&1 1>/dev/null'; + exec($cmd,$resp); + if(strcmp($resp[0],"FAIL") == 0){ + $value = false; + }elseif(strcmp($resp[0],"ERROR") == 0){ + $value = false; + }elseif(strcmp($resp[0],"OK") == 0){ + $value = TRUE; + } + unlink($tempFileName); + unlink($cert); + return $value; + } + + /** + * Creates a 40-character string containing 160-bits of pseudorandomness. + * @return string Containing pseudorandomness of 160 bits + */ + + function samlCreateId() + { + $rndChars = 'abcdefghijklmnop'; + $rndId = ''; + for ($i = 0; $i < 40; $i++ ) { + $rndId .= $rndChars[rand(0,strlen($rndChars)-1)]; + } + return $rndId; + } + + /** + * Returns a unix timestamp in xsd:dateTime format. + * @param timestamp int UNIX Timestamp to convert to xsd:dateTime + * ISO 8601 format. + * @return string + */ + function samlGetDateTime($timestamp) + { + return gmdate('Y-m-d\TH:i:s\Z', $timestamp); + } + /** + * Attempts to check whether a SAML date is valid. Returns true or false. + * @param string $samlDate + * @return bool + */ + + function validSamlDateFormat($samlDate) + { + if ($samlDate == "") return false; + $indexT = strpos($samlDate, 'T'); + $indexZ = strpos($samlDate, 'Z'); + if (($indexT != 10) || ($indexZ != 19)) { + return false; + } + $dateString = substr($samlDate, 0, 10); + $timeString = substr($samlDate, $indexT + 1, 8); + list($year, $month, $day) = explode('-', $dateString); + list($hour, $minute, $second) = explode(':', $timeString); + $parsedDate = gmmktime($hour, $minute, $second, $month, $day, $year); + if (($parsedDate === false) || ($parsedDate == -1)) return false; + if (!checkdate($month, $day, $year)) return false; + return $parsedDate; + } + +} +?> -- cgit v1.2.3