<?php header('Content-Type: text/plain'); ini_set('display_errors', 1); error_reporting(E_ALL | E_STRICT); ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . '/Users/kpalmer/Projects/QuickBooks/'); require_once '../QuickBooks.php'; // $username = '******'; $password = ''; $token = ''; $realmID = 192848234; // $IPP = new QuickBooks_IPP(); $Context = $IPP->authenticate($username, $password, $token); $IPP->application($Context, 'bf4in6uym'); $Service = new QuickBooks_IPP_Service_UOM(); $list = $Service->findAll($Context, $realmID); //print_r($list); foreach ($list as $UOM) { print 'Unit of measure [' . $UOM->getName() . '] of type [' . $UOM->getBaseType() . ']' . "\n"; for ($i = 0; $i < $UOM->countConvUnit(); $i++) { $ConvUnit = $UOM->getConvUnit($i); print "\t" . $ConvUnit->getName() . ', ' . $ConvUnit->getConvRatio() . "\n"; } print "\n"; }
protected function _handleSAML($SAML = null) { $this->_log('Starting up (initialized with ' . strlen($SAML) . ' bytes)'); if ($this->_config['test_username'] and $this->_config['test_password']) { $SAML = QUICKBOOKS_IPP_FEDERATOR_TEST_SAML; $private_key_data = QUICKBOOKS_IPP_FEDERATOR_TEST_KEY; } if (!$SAML) { if (!empty($_POST['SAMLResponse'])) { $SAML = base64_decode($_POST['SAMLResponse']); } else { $msg = 'No SAML request in $_POST vars.'; $this->_log($msg); $this->_setError(QuickBooks_IPP_Federator::ERROR_SAML, $msg); return false; } } if (strlen($SAML) > QUICKBOOKS_IPP_FEDERATOR_MAX_SAML_LENGTH) { $msg = 'SAML request seems unusually large, at ' . strlen($SAML) . ' bytes.'; $this->_log($msg); $this->_setError(QuickBooks_IPP_Federator::ERROR_SAML, $msg); return false; } if ($this->_config['test_username'] and $this->_config['test_password']) { // Do nothing, we already fetched our private key data up there ^^^ } else { $fp = fopen($this->_key, 'r'); $private_key_data = fread($fp, 8192); fclose($fp); } // Decode the SAML request if it's base64 encoded if (false === strpos($SAML, '<')) { $SAML = base64_decode($SAML); } $this->_log('Incoming SAML request: ' . substr($SAML, 0, 128) . '...'); $this->_log($SAML, QUICKBOOKS_LOG_DEBUG); //print("\n\n" . $SAML . "\n\n"); // $private_key = openssl_get_privatekey($private_key_data); //$public_key = openssl_get_publickey($__publicKey); $use_backend = QuickBooks_XML_Parser::BACKEND_BUILTIN; $Parser = new QuickBooks_XML_Parser($SAML, $use_backend); if ($Doc = $Parser->parse($errnum, $errmsg)) { $Root = $Doc->getRoot(); $auth_id = $Root->getChildDataAt('samlp:Response saml:Assertion saml:Subject saml:NameID'); $this->_log('Auth ID: [' . $auth_id . ']'); if (!$auth_id) { $this->_setError(QuickBooks_IPP_Federator::ERROR_INTERNAL, 'Could not extract Auth ID from SAML response.'); return false; } /* $AttributeStatement = $Root->getChildAt('samlp:Response saml:Assertion saml:AttributeStatement'); foreach ($AttributeStatement->children() as $Node) { if ($Node->name() == 'saml:Attribute') { $Attribute = $Node; print_r($Attribute); } } exit; */ $encrypted_key = $Root->getChildDataAt('samlp:Response saml:Assertion saml:AttributeStatement saml:EncryptedAttribute xenc:EncryptedData ds:KeyInfo xenc:EncryptedKey xenc:CipherData xenc:CipherValue'); $this->_log('Encrypted key: [' . $encrypted_key . ']'); if (!$encrypted_key) { $this->_setError(QuickBooks_IPP_Federator::ERROR_INTERNAL, 'Could not extract encrypted key from SAML response.'); return false; } $encrypted_ticket = $Root->getChildDataAt('samlp:Response saml:Assertion saml:AttributeStatement saml:EncryptedAttribute xenc:EncryptedData xenc:CipherData xenc:CipherValue'); $this->_log('Encrypted ticket: [' . $encrypted_ticket . ']'); if (!$encrypted_ticket) { $this->_setError(QuickBooks_IPP_Federator::ERROR_INTERNAL, 'Could not extract encrypted ticket from SAML response.'); return false; } // Loop through the nodes, fetching the attributes from the SAML request $Node = $Root->getChildAt('samlp:Response saml:Assertion saml:AttributeStatement'); $target_url = null; $realm_id_pseudonym = null; foreach ($Node->children() as $ChildNode) { if ($ChildNode->name() == 'saml:Attribute') { $Attribute = $ChildNode; if ($Attribute->getAttribute('Name') == 'targetUrl') { $ChildChildNode = $Attribute->getChild(0); $target_url = $ChildChildNode->data(); } else { if ($Attribute->getAttribute('Name') == 'Intuit.Federation.realmIDPseudonym') { $ChildChildNode = $Attribute->getChild(0); $realm_id_pseudonym = $ChildChildNode->data(); } } } } $this->_log('Target URL: [' . $target_url . ']'); $this->_log('Realm ID Pseudonym: [' . $realm_id_pseudonym . ']'); //exit; if (!$target_url) { $this->_setError(QuickBooks_IPP_Federator::ERROR_INTERNAL, 'Could not extract target URL from SAML response.'); return false; } /* // Get the signatureValue $node = $xml->xpath('/samlp:Response/saml:Assertion/ds:Signature/ds:SignatureValue'); $signatureValue = $node[0]; # Get the signed node $signInfo = $xml->xpath('/samlp:Response/saml:Assertion/ds:Signature/ds:SignedInfo'); */ // The key and ticket are base64 encoded, decode them $decoded_key = base64_decode($encrypted_key); $decoded_ticket = base64_decode($encrypted_ticket); // Decrypt the key $decrypted_key = null; $result = $this->_segfault_openssl_private_decrypt($decoded_key, $decrypted_key, $private_key_data); $this->_log('Key: [' . $decrypted_key . ']'); if (!$decrypted_key) { $this->_setError(QuickBooks_IPP_Federator::ERROR_INTERNAL, 'Could not extract decrypted key from SAML response.'); return false; } // @todo Swap out for QuickBooks_Encrypt implementation // Get the key size for decryption $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); // $decoded_ticket is stored as: // 16-byte IV // CONCAT WITH // XX-byte actual encrypted ticket in XML format // Get the IV $iv = substr($decoded_ticket, 0, $iv_size); // This is the actual encrypted ticket $cipher = substr($decoded_ticket, $iv_size); // @todo Swap out for QuickBooks_Encrypt implementation // Decrypt the ticket $decrypted_ticket = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $decrypted_key, $cipher, MCRYPT_MODE_CBC, $iv); // Remove the padding from the ticket $last_byte = substr($decrypted_ticket, -1, 1); $padding = -ord($last_byte); $decrypted_ticket = substr($decrypted_ticket, 0, $padding); $this->_log('Decrypted ticket is ' . strlen($decrypted_ticket) . ' bytes long...'); $this->_log($decrypted_ticket, QUICKBOOKS_LOG_DEBUG); // Parse the XML format to get at the actual ticket value $ticket = null; $errnum = null; $errmsg = null; $use_backend = QuickBooks_XML_Parser::BACKEND_BUILTIN; $Parser = new QuickBooks_XML_Parser($decrypted_ticket, $use_backend); if ($Doc = $Parser->parse($errnum, $errmsg)) { $Root = $Doc->getRoot(); $ticket = $Root->getChildDataAt('Attribute saml:AttributeValue'); $this->_log('Ticket: [' . $ticket . ']'); // Check for test mode overrides if ($this->_config['test_username'] and $this->_config['test_password']) { $username = $this->_config['test_username']; $password = $this->_config['test_password']; $token = 'blablabla'; $test_replace = array('{dbid}' => $this->_config['test_param_dbid'], '{realm}' => $this->_config['test_param_realm'], '{state}' => $this->_config['test_param_state']); $target_url = str_replace(array_keys($test_replace), array_values($test_replace), $this->_config['test_target']); // Grab a ticket $IPP = new QuickBooks_IPP(); $Context = $IPP->authenticate($username, $password, $token); $ticket = $Context->ticket(); $this->_log('TEST MODE [authid=' . $auth_id . ', ticket=' . $ticket . ', target_url=' . $target_url . ']'); } return $this->_doCallback($auth_id, $ticket, $target_url, $realm_id_pseudonym); } else { $this->_setError(QuickBooks_IPP_Federator::ERROR_XML, 'XML parser error while parsing SAML ticket: ' . $errnum . ':' . $errmsg); return false; } } else { $this->_setError(QuickBooks_IPP_Federator::ERROR_XML, 'XML parser error while parsing SAML response: ' . $errnum . ': ' . $errmsg); return false; } }