<?php
/**
 * infocard-lib.php
 *
 * Copyright (c) 2007, Robert Richards <rrichards@cdatazone.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Robert Richards nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author     Robert Richards <rrichards@cdatazone.org>
 * @copyright  2007 Robert Richards <rrichards@cdatazone.org>
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @version    1.1.2
 */
 
require('xmlseclibs.php');

define('SAML_ASSERT_NS''urn:oasis:names:tc:SAML:1.0:assertion');

function 
processCard($xmlToken$privateKey=NULL$sslEnabled=True) {    
    try {
        if (
$sslEnabled) {
            
$encdom = new DOMDocument();
            
$encdom->loadXML($xmlToken);
            
$objenc = new XMLSecEnc();
            
$encData $objenc->locateEncryptedData($encdom);
            if (! 
$encData) {
                throw new 
Exception("Cannot locate Encrypted Data");
            }
            
$objenc->setNode($encData);
            
$objenc->type $encData->getAttribute("Type");
            
            
$key NULL;
            
$objKey $objenc->locateKey();
            if (
$objKey) {
                if (
$objKeyInfo $objenc->locateKeyInfo($objKey)) {
                    if (
$objKeyInfo->isEncrypted) {
                        
$objencKey $objKeyInfo->encryptedCtx;
                        
$objKeyInfo->loadKey($privateKeyTRUE);
                        
$key $objencKey->decryptKey($objKeyInfo);
                    }
                }
            }
            
            if (empty(
$objKey) || empty($key)) {
                throw new 
Exception("Error loading key to handle Decryption");
            }
            
            
$objKey->loadKey($key);
            
            
$token NULL;
            if (
$decrypt $objenc->decryptNode($objKeyFALSE)) {
                
/* we have the saml token so load er up */
                
$token = new DOMDocument();
                
$token->loadXML($decrypt);
            }
        } else {
            
$token = new DOMDocument();
            
$token->loadXML($xmlToken);
        }

        if (empty(
$token)) {
            throw new 
Exception("Unable to decrypt token");
        }

        
/* Validate the SAML token */
        
$objXMLSecDSig = new XMLSecurityDSig();
        
$objXMLSecDSig->idKeys[] = 'AssertionID';
        
$objDSig $objXMLSecDSig->locateSignature($token);

        
/* Canonicalize the signed info */
        
$objXMLSecDSig->canonicalizeSignedInfo();

        
$retVal NULL;
        if (
$objDSig) {
            
$retVal $objXMLSecDSig->validateReference();
        }
        if (! 
$retVal) {
            throw new 
Exception("SAML Validation Failed");
        }


        
$key NULL;
        
$objKey $objXMLSecDSig->locateKey();
        
        if (
$objKey) {
            if (
$objKeyInfo XMLSecEnc::staticLocateKeyInfo($objKey$objDSig)) {
                
/* Handle any additional key processing such as encrypted keys here */
            
}
        }
        
        if (empty(
$objKey)) {
            throw new 
Exception("Error loading key to handle Signature");
        }

        if (! 
$objXMLSecDSig->verify($objKey)) {
            throw new 
Exception("Unable to validate Signature");
        }

        return 
$token;
    } catch (
DOMException $domE) {
        print 
"DOM Error: ".$domE->getMessage();
    } catch (
Exception $e) {
        print 
'Error: '.$e->getMessage();
    }
    return 
NULL;
}

function 
checkDateConditions($start=NULL$end=NULL) {
    
$currentTime time();

    if (! empty(
$start)) {
        
$startTime strtotime($start);
        
/* Allow for a 10 minute difference in Time */
        
if (($startTime 0) || (($startTime 600) > $currentTime)) {
            return 
FALSE;
        }
    }
    if (! empty(
$end)) {
        
$endTime strtotime($end);
        if ((
$endTime 0) || ($endTime <= $currentTime)) {
            return 
FALSE;
        }
    }
    return 
TRUE;
}

function 
getAssertions($token) {
    
$assertions = array();
    if (
$token instanceof DOMDocument) {
        
$xPath = new DOMXpath($token);
        
$xPath->registerNamespace('mysaml'SAML_ASSERT_NS);

        
$query '/mysaml:Assertion/mysaml:Conditions';
        
$nodelist $xPath->query($query);
        if (
$node $nodelist->item(0)) {
            
$start $node->getAttribute('NotBefore');
            
$end $node->getAttribute('NotOnOrAfter');
            if (! 
checkDateConditions($start$end)) {
                return 
$assertions;
            }
        }

        
$query '/mysaml:Assertion/mysaml:AttributeStatement/mysaml:Attribute';
        
$nodelist $xPath->query($query);
        
        foreach (
$nodelist AS $node) {
            if (
$name $node->getAttribute('AttributeName')) {
                
$value '';
                foreach (
$node->childNodes AS $child) {
                    if (
$child->localName == 'AttributeValue') {
                        
$value $child->textContent;
                        break;
                    }
                }
                
$assertions[$name] = $value;
            }
        }
    }
    return 
$assertions;
}