forked from GNUsocial/gnu-social
		
	
		
			
				
	
	
		
			221 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?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;
 | 
						|
   }
 | 
						|
 | 
						|
}
 | 
						|
?>
 |