123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- <?php
- /**
- ** PHP versions 4 and 5
- **
- ** LICENSE: See the COPYING file included in this distribution.
- **
- ** @package OpenID
- ** @author Santosh Subramanian <subrasan@cs.sunysb.edu>
- ** @author Shishir Randive <srandive@cs.sunysb.edu>
- ** 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;
- }
- }
- ?>
|