Jelajahi Sumber

ZF-6483: Added abstract Method to setRegion so you can specify which region you want to be working in.
ZF-6643: Updated the Authenitaction for V2 instead of the depecrated V1
ZF-6730: Added the abstractTest class for the Amazon Abstract Class

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@15647 44c647ce-9c0f-0410-b52a-842ac1e357ba

sidhighwind 16 tahun lalu
induk
melakukan
f2e8095363

+ 33 - 0
documentation/manual/en/module_specs/Zend_Service_Amazon_Ec2.xml

@@ -19,5 +19,38 @@
             purpose.
         </para>
     </sect2>
+    <sect2 id="zend.service.amazon.ec2.staticmethods">
+        <title>Static Methods</title>
+        <para>
+            To make using the Ec2 class easier to use there are two static methods that can be
+            invoked from any of the Ec2 Elements.  The first static method is <code>setKeys</code>
+            which will defind you AWS Access Keys as default keys.  When you then create any new
+            object you don't need to pass in any keys to the constructor.
+        </para>
+        <example id="zend.service.amazon.ec2.staticmethods.setkeys">
+            <title>setKeys() Example</title>
+            <programlisting language="php"><![CDATA[
+Zend_Service_Amazon_Ec2_Ebs::setKeys('aws_key','aws_secret_key');
+]]></programlisting>
+        </example>
+        <para>
+            To set the region that you are working in you can call the <code>setRegion</code> to set which
+            Amazon Ec2 Region you are working in. Currently there is only two region available us-east-1
+            and eu-west-1.  If an invalid value is passed it will throw an exception stating that.
+        </para>
+        <example id="zend.service.amazon.ec2.staticmethods.setregion">
+            <title>setRegion() Example</title>
+            <programlisting language="php"><![CDATA[
+Zend_Service_Amazon_Ec2_Ebs::setRegion('us-east-1');
+]]></programlisting>
+        </example>
+        <note id="zend.service.amazon.ec2.staticmethods.setregion.note">
+            <title>Set Amazon Ec2 Region</title>
+            <para>
+                Alternativly you can set the region when you create each class as the third parameter in the
+                constructor method.
+            </para>
+        </note>
+    </sect2>
 
 </sect1>

+ 56 - 1
library/Zend/Service/Amazon/Abstract.php

@@ -45,6 +45,11 @@ abstract class Zend_Service_Amazon_Abstract extends Zend_Service_Abstract
     protected static $_defaultSecretKey = null;
 
     /**
+     * @var string Amazon Region
+     */
+    protected static $_defaultRegion = null;
+
+    /**
      * @var string Amazon Secret Key
      */
     protected $_secretKey;
@@ -55,6 +60,18 @@ abstract class Zend_Service_Amazon_Abstract extends Zend_Service_Abstract
     protected $_accessKey;
 
     /**
+     * @var string Amazon Region
+     */
+    protected $_region;
+
+    /**
+     * An array that contains all the valid Amazon Ec2 Regions.
+     *
+     * @var array
+     */
+    protected static $_validEc2Regions = array('eu-west-1', 'us-east-1');
+
+    /**
      * Set the keys to use when accessing SQS.
      *
      * @param  string $access_key       Set the default Access Key
@@ -68,13 +85,30 @@ abstract class Zend_Service_Amazon_Abstract extends Zend_Service_Abstract
     }
 
     /**
+     * Set which region you are working in.  It will append the
+     * end point automaticly
+     *
+     * @param string $region
+     */
+    public static function setRegion($region)
+    {
+        if(in_array(strtolower($region), self::$_validEc2Regions, true)) {
+            self::$_defaultRegion = $region;
+        } else {
+            require_once 'Zend/Service/Amazon/Exception.php';
+            throw new Zend_Service_Amazon_Exception('Invalid Amazon Ec2 Region');
+        }
+    }
+
+    /**
      * Create Amazon Sqs client.
      *
      * @param  string $access_key       Override the default Access Key
      * @param  string $secret_key       Override the default Secret Key
+     * @param  string $region           Sets the AWS Region
      * @return void
      */
-    public function __construct($accessKey=null, $secretKey=null)
+    public function __construct($accessKey=null, $secretKey=null, $region=null)
     {
         if(!$accessKey) {
             $accessKey = self::$_defaultAccessKey;
@@ -82,12 +116,33 @@ abstract class Zend_Service_Amazon_Abstract extends Zend_Service_Abstract
         if(!$secretKey) {
             $secretKey = self::$_defaultSecretKey;
         }
+        if(!$region) {
+            $region = self::$_defaultRegion;
+        } else {
+            // make rue the region is valid
+            if(!empty($region) && !in_array(strtolower($region), self::$_validEc2Regions, true)) {
+                require_once 'Zend/Service/Amazon/Exception.php';
+                throw new Zend_Service_Amazon_Exception('Invalid Amazon Ec2 Region');
+            }
+        }
+
         if(!$accessKey || !$secretKey) {
             require_once 'Zend/Service/Amazon/Exception.php';
             throw new Zend_Service_Amazon_Exception("AWS keys were not supplied");
         }
         $this->_accessKey = $accessKey;
         $this->_secretKey = $secretKey;
+        $this->_region = $region;
+    }
+
+    /**
+     * Method to fetch the AWS Region
+     *
+     * @return string
+     */
+    protected function _getRegion()
+    {
+        return (!empty($this->_region)) ? $this->_region . '.' : '';
     }
 
     /**

+ 21 - 9
library/Zend/Service/Amazon/Ec2/Abstract.php

@@ -24,6 +24,8 @@ require_once 'Zend/Service/Amazon/Abstract.php';
 
 require_once 'Zend/Service/Amazon/Ec2/Response.php';
 
+require_once 'Zend/Service/Amazon/Ec2/Exception.php';
+
 /**
  * Provides the basic functionality to send a request to the Amazon Ec2 Query API
  *
@@ -46,9 +48,14 @@ abstract class Zend_Service_Amazon_Ec2_Abstract extends Zend_Service_Amazon_Abst
     const EC2_API_VERSION = '2008-12-01';
 
     /**
-     * Legacy parameter required by Ec2
+     * Signature Version
      */
-    const EC2_SIGNATURE_VERSION = '1';
+    const EC2_SIGNATURE_VERSION = '2';
+
+    /**
+     * Signature Encoding Method
+     */
+    const EC2_SIGNATURE_METHOD = 'HmacSHA256';
 
     /**
      * Period after which HTTP request will timeout in seconds
@@ -64,7 +71,7 @@ abstract class Zend_Service_Amazon_Ec2_Abstract extends Zend_Service_Amazon_Abst
      */
     protected function sendRequest(array $params = array())
     {
-        $url = 'https://' . self::EC2_ENDPOINT . '/';
+        $url = 'https://' . $this->_getRegion() . self::EC2_ENDPOINT . '/';
 
         $params = $this->addRequiredParameters($params);
 
@@ -118,8 +125,9 @@ abstract class Zend_Service_Amazon_Ec2_Abstract extends Zend_Service_Amazon_Abst
     {
         $parameters['AWSAccessKeyId']   = $this->_getAccessKey();
         $parameters['SignatureVersion'] = self::EC2_SIGNATURE_VERSION;
-        $parameters['Timestamp']        = gmdate('c');
+        $parameters['Expires']          = gmdate('c');
         $parameters['Version']          = self::EC2_API_VERSION;
+        $parameters['SignatureMethod']  = self::EC2_SIGNATURE_METHOD;
         $parameters['Signature']        = $this->signParameters($parameters);
 
         return $parameters;
@@ -147,17 +155,22 @@ abstract class Zend_Service_Amazon_Ec2_Abstract extends Zend_Service_Amazon_Abst
      */
     protected function signParameters(array $paramaters)
     {
-        $data = '';
+        $data = "POST\n";
+        $data .= $this->_getRegion() . self::EC2_ENDPOINT . "\n";
+        $data .= "/\n";
 
-        uksort($paramaters, 'strcasecmp');
+        uksort($paramaters, 'strcmp');
         unset($paramaters['Signature']);
 
+        $arrData = array();
         foreach($paramaters as $key => $value) {
-            $data .= $key . $value;
+            $arrData[] = $key . '=' . str_replace("%7E", "~", urlencode($value));
         }
 
+        $data .= implode('&', $arrData);
+
         require_once 'Zend/Crypt/Hmac.php';
-        $hmac = Zend_Crypt_Hmac::compute($this->_getSecretKey(), 'SHA1', $data, Zend_Crypt_Hmac::BINARY);
+        $hmac = Zend_Crypt_Hmac::compute($this->_getSecretKey(), 'SHA256', $data, Zend_Crypt_Hmac::BINARY);
 
         return base64_encode($hmac);
     }
@@ -181,7 +194,6 @@ abstract class Zend_Service_Amazon_Ec2_Abstract extends Zend_Service_Amazon_Abst
             $node    = $list->item(0);
             $code    = $xpath->evaluate('string(Code/text())', $node);
             $message = $xpath->evaluate('string(Message/text())', $node);
-            require_once 'Zend/Service/Amazon/Ec2/Exception.php';
             throw new Zend_Service_Amazon_Ec2_Exception($message, 0, $code);
         }
 

+ 106 - 0
tests/Zend/Service/Amazon/AbstractTest.php

@@ -0,0 +1,106 @@
+<?php
+
+require_once 'PHPUnit/Framework/TestCase.php';
+require_once 'Zend/Service/Amazon/Abstract.php';
+
+/**
+ * Zend_Service_Amazon_Sqs_Queue test case.
+ */
+class AmamzonAbstract extends PHPUnit_Framework_TestCase
+{
+    /**
+     * Prepares the environment before running a test.
+     */
+    protected function setUp()
+    {
+        parent::setUp();
+    }
+
+    /**
+     * Cleans up the environment after running a test.
+     */
+    protected function tearDown()
+    {
+        parent::tearDown();
+    }
+
+    public function testNoKeysThrowException()
+    {
+        try {
+            $class = new TestAmamzonAbstract();
+            $this->fail('Exception should be thrown when no keys are passed in.');
+        } catch(Zend_Service_Amazon_Exception $zsae) {}
+    }
+
+    public function testConstructorWithKeysDoesNotThrowException()
+    {
+        try {
+            $class = new TestAmamzonAbstract('TestAccessKey', 'TestSecretKey');
+        } catch(Zend_Service_Amazon_Exception $zsae) {
+            $this->fail('Exception should be thrown when no keys are passed in.');
+        }
+    }
+
+    public function testSetStaticKeys()
+    {
+        TestAmamzonAbstract::setKeys('TestAccessKey', 'TestSecretKey');
+        $class = new TestAmamzonAbstract();
+
+        $this->assertEquals('TestAccessKey', $class->returnAccessKey());
+        $this->assertEquals('TestSecretKey', $class->returnSecretKey());
+    }
+
+    public function testPassKeysIntoConstructor()
+    {
+        $class = new TestAmamzonAbstract('TestAccessKey', 'TestSecretKey');
+
+        $this->assertEquals('TestAccessKey', $class->returnAccessKey());
+        $this->assertEquals('TestSecretKey', $class->returnSecretKey());
+    }
+
+    public function testPassedInKeysOverrideStaticSetKeys()
+    {
+        TestAmamzonAbstract::setKeys('TestStaticAccessKey', 'TestStaticSecretKey');
+        $class = new TestAmamzonAbstract('TestAccessKey', 'TestSecretKey');
+
+        $this->assertEquals('TestAccessKey', $class->returnAccessKey());
+        $this->assertEquals('TestSecretKey', $class->returnSecretKey());
+    }
+
+    public function testSetRegion()
+    {
+        TestAmamzonAbstract::setRegion('eu-west-1');
+
+        $class = new TestAmamzonAbstract('TestAccessKey', 'TestSecretKey');
+        $this->assertEquals('eu-west-1', $class->returnRegion());
+    }
+    
+    public function testSetInvalidRegionThrowsException()
+    {
+        try {
+            TestAmamzonAbstract::setRegion('eu-west-1a');
+            $this->fail('Invalid Region Set with no Exception Thrown');
+        } catch (Zend_Service_Amazon_Exception $zsae) {
+            // do nothing
+        }
+    }
+}
+
+class TestAmamzonAbstract extends Zend_Service_Amazon_Abstract
+{
+    public function returnAccessKey()
+    {
+        return $this->_accessKey;
+    }
+
+    public function returnSecretKey()
+    {
+        return $this->_secretKey;
+    }
+
+    public function returnRegion()
+    {
+        return $this->_region;
+    }
+}
+