Viewing file:      InfoCard.php (12.32 KB)      -rw-r--r-- Select action/file-type:    (+) |   (+) |   (+) | Code (+) | Session (+) |   (+) | SDB (+) |   (+) |   (+) |   (+) |   (+) |   (+) |
 
<?php /* * COAUTHOR: Samuel Muñoz Hidalgo * EMAIL: samuel.mh@gmail.com * LAST REVISION: 22-DEC-08 * DESCRIPTION: Zend Infocard libraries added sts certificate check */ require_once 'Zend_InfoCard_Claims.php';
  class sspmod_InfoCard_RP_InfoCard {
    const XENC_NS = "http://www.w3.org/2001/04/xmlenc#";   const XENC_ELEMENT_TYPE = "http://www.w3.org/2001/04/xmlenc#Element";   const XENC_ENC_ALGO = "http://www.w3.org/2001/04/xmlenc#aes256-cbc";   const XENC_KEYINFO_ENC_ALGO = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p";
    const DSIG_NS = "http://www.w3.org/2000/09/xmldsig#";   const DSIG_RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";   const DSIG_ENVELOPED_SIG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";   const DSIG_SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1";
    const CANON_EXCLUSIVE = "http://www.w3.org/2001/10/xml-exc-c14n#";
    const WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";   const WSSE_KEYID_VALUE_TYPE = "http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1";
    const XMLSOAP_SELF_ISSUED = "http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self";
    const XMLSOAP_CLAIMS_NS = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims';
    const SAML_ASSERTION_1_0_NS = "urn:oasis:names:tc:SAML:1.0:assertion";   const SAML_ASSERTION_1_1_NS = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1";
    protected $_private_key_file;   protected $_public_key_file;   protected $_password;   protected $_sxml;
      protected $_sts_crt;
    public function __construct() {     if(!extension_loaded('mcrypt')) {       throw new Exception("Use of the InfoCard component requires the mcrypt extension to be enabled in PHP");     }
      if(!extension_loaded('openssl')) {       throw new Exception("Use of the InfoCard component requires the openssl extension to be enabled in PHP");     }   }
 
 
      public function addSTSCertificate($sts_crt){         $this->_sts_crt = $sts_crt;         if(($sts_crt==NULL) || (strcmp($sts_crt,'')==0)) {             SimpleSAML_Logger::debug('WARNING: No STS certificate is set, ALL TOKENS WILL BE ACCEPTED');         }else if( (!file_exists($sts_crt)) || (!is_readable($sts_crt))) {       throw new Exception("STS certificate is not readable");     }     }
 
 
      public function addIDPKey($private_key_file, $password = NULL){         $this->_private_key_file = $private_key_file;     $this->_password = $password;
      if(!file_exists($this->_private_key_file)) {       throw new Exception("Private key file does not exists");      }          if(!is_readable($this->_private_key_file)) {       throw new Exception("Private key file is not readable");     }     }
  /*Function not used $public_key_file is not used*/   public function addCertificatePair($private_key_file, $public_key_file, $password = null) {     $this->_private_key_file = $private_key_file;     $this->_public_key_file = $public_key_file;     $this->_password = $password;
      if(!file_exists($this->_private_key_file)) {       throw new Exception("Private key file does not exists");      }          if(!is_readable($this->_private_key_file)) {       throw new Exception("Private key file is not readable");     }
      if(!file_exists($this->_public_key_file)) {       throw new Exception("Public key file does not exists");      }    
      if(!is_readable($this->_public_key_file)) {       throw new Exception("Public key file is not readable");      }   }
 
    public function process($xmlToken) {     if(strpos($xmlToken, "EncryptedData") === false ) { SimpleSAML_Logger::debug('IC: UNsecureToken');       return self::processUnSecureToken($xmlToken);     }     else { SimpleSAML_Logger::debug('IC: secureToken');       return self::processSecureToken($xmlToken);     }   }
    private function processSecureToken($xmlToken) {     $retval = new Zend_InfoCard_Claims();
      try {       $this->_sxml = simplexml_load_string($xmlToken);       $decryptedToken = self::decryptToken($xmlToken);     }     catch(Exception $e) {             SimpleSAML_Logger::debug('ProcSecToken '.$e);       $retval->setError('Failed to extract assertion document');       throw new Exception('Failed to extract assertion document: ' . $e->getMessage());       $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);       return $retval;     }
      try {       $assertions = self::getAssertions($decryptedToken);         }     catch(Exception $e) {        $retval->setError('Failure processing assertion document');           throw new Exception('Failure processing assertion document');        $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);        return $retval;     }
      try {       $reference_id = self::ValidateSignature($assertions);       self::checkConditions($reference_id, $assertions);     }     catch(Exception $e) {       $retval->setError($e->getMessage());       $retval->setCode(Zend_InfoCard_Claims::RESULT_VALIDATION_FAILURE);       return $retval;     }
      return self::getClaims($retval, $assertions);   }
    private function processUnsecureToken($xmlToken) {     $retval = new Zend_InfoCard_Claims();          try {       $assertions = self::getAssertions($xmlToken);         }     catch(Exception $e) {        $retval->setError('Failure processing assertion document');                 throw new Exception('Failure processing assertion document');        $retval->setCode(Zend_InfoCard_Claims::RESULT_PROCESSING_FAILURE);        return $retval;     }
      return self::getClaims($retval, $assertions);   }
    private function ValidateSignature($assertions) {     include_once 'Zend_InfoCard_Xml_Security.php';     $reference_id = Zend_InfoCard_Xml_Security::validateXMLSignature($assertions->asXML(), $this->_sts_crt);     if(!$reference_id) {       throw new Exception("Failure Validating the Signature of the assertion document");     }
      return $reference_id;   }
    private function checkConditions($reference_id, $assertions) {     if($reference_id[0] == '#') {       $reference_id = substr($reference_id, 1);     } else {       throw new Exception("Reference of document signature does not reference the local document");     }
      if($reference_id != $assertions->getAssertionID()) {       throw new Exception("Reference of document signature does not reference the local document");     }
      $conditions = $assertions->getConditions();     if(is_array($condition_error = $assertions->validateConditions($conditions))) {       throw new Exception("Conditions of assertion document are not met: {$condition_error[1]} ({$condition_error[0]})");     }   }
    private function getClaims($retval, $assertions) {     $attributes = $assertions->getAttributes();     $retval->setClaims($attributes);     if($retval->getCode() == 0) {       $retval->setCode(Zend_InfoCard_Claims::RESULT_SUCCESS);     }
      return $retval;   }
    private function getAssertions($strXmlData) {      $sxe = simplexml_load_string($strXmlData);      $namespaces = $sxe->getDocNameSpaces();      foreach($namespaces as $namespace) {        switch($namespace) {          case self::SAML_ASSERTION_1_0_NS:            include_once 'Zend_InfoCard_Xml_Assertion_Saml.php';            return simplexml_load_string($strXmlData, 'Zend_InfoCard_Xml_Assertion_Saml', null);        }      }
       throw new Exception("Unable to determine Assertion type by Namespace");   }
    private function decryptToken($xmlToken) {     if($this->_sxml['Type'] != self::XENC_ELEMENT_TYPE) {       throw new Exception("Unknown EncryptedData type found");     }
      $this->_sxml->registerXPathNamespace('enc', self::XENC_NS);       list($encryptionMethod) = $this->_sxml->xpath("//enc:EncryptionMethod");     if(!$encryptionMethod instanceof SimpleXMLElement) {       throw new Exception("EncryptionMethod node not found");     }
      $encMethodDom = dom_import_simplexml($encryptionMethod);     if(!$encMethodDom instanceof DOMElement) {       throw new Exception("Failed to create DOM from EncryptionMethod node");     }
      if(!$encMethodDom->hasAttribute("Algorithm")) {       throw new Exception("Unable to determine the encryption algorithm in the Symmetric enc:EncryptionMethod XML block");     }
      $algo = $encMethodDom->getAttribute("Algorithm");     if($algo != self::XENC_ENC_ALGO) {       throw new Exception("Unsupported encryption algorithm");     }
      $this->_sxml->registerXPathNamespace('ds', self::DSIG_NS);     list($keyInfo) = $this->_sxml->xpath("ds:KeyInfo");     if(!$keyInfo instanceof SimpleXMLElement) {       throw new Exception("KeyInfo node not found");     }
      $keyInfo->registerXPathNamespace('enc', self::XENC_NS);       list($encryptedKey) = $keyInfo->xpath("enc:EncryptedKey");     if(!$encryptedKey instanceof SimpleXMLElement) {       throw new Exception("EncryptedKey element not found in KeyInfo");     }
      $encryptedKey->registerXPathNamespace('enc', self::XENC_NS);       list($keyInfoEncryptionMethod) = $encryptedKey->xpath("enc:EncryptionMethod");     if(!$keyInfoEncryptionMethod instanceof SimpleXMLElement) {       throw new Exception("EncryptionMethod element not found in EncryptedKey");     }
      $keyInfoEncMethodDom = dom_import_simplexml($keyInfoEncryptionMethod);     if(!$keyInfoEncMethodDom instanceof DOMElement) {       throw new Exception("Failed to create DOM from EncryptionMethod node");     }
      if(!$keyInfoEncMethodDom->hasAttribute("Algorithm")) {       throw new Exception("Unable to determine the encryption algorithm in the Symmetric enc:EncryptionMethod XML block");     }
      $keyInfoEncMethodAlgo = $keyInfoEncMethodDom->getAttribute("Algorithm");     if($keyInfoEncMethodAlgo != self::XENC_KEYINFO_ENC_ALGO) {       throw new Exception("Unsupported encryption algorithm");     }
      $encryptedKey->registerXPathNamespace('ds', self::DSIG_NS);     $encryptedKey->registerXPathNamespace('wsse', self::WSSE_NS);     list($keyIdentifier) = $encryptedKey->xpath("ds:KeyInfo/wsse:SecurityTokenReference/wsse:KeyIdentifier");     if(!$keyIdentifier instanceof SimpleXMLElement) {       throw new Exception("KeyInfo/SecurityTokenReference/KeyIdentifier node not found in KeyInfo");     }
      $keyIdDom =  dom_import_simplexml($keyIdentifier);     if(!$keyIdDom instanceof DOMElement) {       throw new Exception("Failed to create DOM from KeyIdentifier node");     }
      if(!$keyIdDom->hasAttribute("ValueType")) {       throw new Exception("Unable to determine ValueType of KeyIdentifier");     }
      $valueType = $keyIdDom->getAttribute("ValueType");     if($valueType != self::WSSE_KEYID_VALUE_TYPE) {       throw new Exception("Unsupported KeyIdentifier ValueType");     }
      list($cipherValue) = $encryptedKey->xpath("enc:CipherData/enc:CipherValue");     if(!$cipherValue instanceof SimpleXMLElement) {       throw new Exception("CipherValue node found in EncryptedKey");     }
      $base64DecodeSupportsStrictParam = version_compare(PHP_VERSION, '5.2.0', '>=');
      if ($base64DecodeSupportsStrictParam) {       $keyCipherValueBase64Decoded = base64_decode($cipherValue, true);     } else {       $keyCipherValueBase64Decoded = base64_decode($cipherValue);     }
      $private_key = openssl_pkey_get_private(array(file_get_contents($this->_private_key_file), $this->_password));     if(!$private_key) {       throw new Exception("Unable to load private key");     }          $result = openssl_private_decrypt($keyCipherValueBase64Decoded, $symmetricKey, $private_key, OPENSSL_PKCS1_OAEP_PADDING);     openssl_free_key($private_key);
      if(!$result) {       throw new Exception("Unable to decrypt symmetric key");     }
      list($cipherValue) = $this->_sxml->xpath("enc:CipherData/enc:CipherValue");     if(!$cipherValue instanceof SimpleXMLElement) {       throw new Exception("CipherValue node found in EncryptedData");     }
      if ($base64DecodeSupportsStrictParam) {       $keyCipherValueBase64Decoded = base64_decode($cipherValue, true);     } else {       $keyCipherValueBase64Decoded = base64_decode($cipherValue);     }
      $mcrypt_iv = substr($keyCipherValueBase64Decoded, 0, 16);     $keyCipherValueBase64Decoded =  substr($keyCipherValueBase64Decoded, 16);     $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $symmetricKey, $keyCipherValueBase64Decoded, MCRYPT_MODE_CBC, $mcrypt_iv);
      if(!$decrypted) {       throw new Exception("Unable to decrypt token");     }
      $decryptedLength = strlen($decrypted);     $paddingLength = substr($decrypted, $decryptedLength -1, 1);     $decrypted = substr($decrypted, 0, $decryptedLength - ord($paddingLength));     $decrypted = rtrim($decrypted, "\0");
      return $decrypted;   } }
  ?> 
  |