web/lib/Zend/Service/WindowsAzure/Credentials/SharedAccessSignature.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Service_WindowsAzure
       
    17  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  * @version    $Id: SharedAccessSignature.php 22773 2010-08-03 07:18:27Z maartenba $
       
    20  */
       
    21 
       
    22 /**
       
    23  * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
       
    24  */
       
    25 require_once 'Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php';
       
    26 
       
    27 /**
       
    28  * @see Zend_Service_WindowsAzure_Storage
       
    29  */
       
    30 require_once 'Zend/Service/WindowsAzure/Storage.php';
       
    31 
       
    32 /**
       
    33  * @see Zend_Http_Client
       
    34  */
       
    35 require_once 'Zend/Http/Client.php';
       
    36 
       
    37 /**
       
    38  * @category   Zend
       
    39  * @package    Zend_Service_WindowsAzure
       
    40  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    41  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    42  */ 
       
    43 class Zend_Service_WindowsAzure_Credentials_SharedAccessSignature
       
    44     extends Zend_Service_WindowsAzure_Credentials_CredentialsAbstract
       
    45 {
       
    46     /**
       
    47      * Permission set
       
    48      * 
       
    49      * @var array
       
    50      */
       
    51     protected $_permissionSet = array();
       
    52     
       
    53 	/**
       
    54 	 * Creates a new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance
       
    55 	 *
       
    56 	 * @param string $accountName Account name for Windows Azure
       
    57 	 * @param string $accountKey Account key for Windows Azure
       
    58 	 * @param boolean $usePathStyleUri Use path-style URI's
       
    59 	 * @param array $permissionSet Permission set
       
    60 	 */
       
    61 	public function __construct(
       
    62 		$accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT,
       
    63 		$accountKey  = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY,
       
    64 		$usePathStyleUri = false, $permissionSet = array()
       
    65 	) {
       
    66 	    parent::__construct($accountName, $accountKey, $usePathStyleUri);
       
    67 	    $this->_permissionSet = $permissionSet;
       
    68 	}
       
    69 	
       
    70 	/**
       
    71 	 * Get permission set
       
    72 	 * 
       
    73 	 * @return array
       
    74 	 */
       
    75     public function getPermissionSet()
       
    76 	{
       
    77 	    return $this->_permissionSet;   
       
    78 	}
       
    79 	
       
    80 	/**
       
    81 	 * Set permisison set
       
    82 	 * 
       
    83 	 * Warning: fine-grained permissions should be added prior to coarse-grained permissions.
       
    84 	 * For example: first add blob permissions, end with container-wide permissions.
       
    85 	 * 
       
    86 	 * Warning: the signed access signature URL must match the account name of the
       
    87 	 * Zend_Service_WindowsAzure_Credentials_Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance
       
    88 	 * 
       
    89 	 * @param  array $value Permission set
       
    90 	 * @return void
       
    91 	 */
       
    92     public function setPermissionSet($value = array())
       
    93 	{
       
    94 		foreach ($value as $url) {
       
    95 			if (strpos($url, $this->_accountName) === false) {
       
    96 				throw new Zend_Service_WindowsAzure_Exception('The permission set can only contain URLs for the account name specified in the Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance.');
       
    97 			}
       
    98 		}
       
    99 	    $this->_permissionSet = $value;
       
   100 	}
       
   101     
       
   102     /**
       
   103      * Create signature
       
   104      * 
       
   105      * @param string $path 		   Path for the request
       
   106      * @param string $resource     Signed resource - container (c) - blob (b)
       
   107      * @param string $permissions  Signed permissions - read (r), write (w), delete (d) and list (l)
       
   108      * @param string $start        The time at which the Shared Access Signature becomes valid.
       
   109      * @param string $expiry       The time at which the Shared Access Signature becomes invalid.
       
   110      * @param string $identifier   Signed identifier
       
   111      * @return string 
       
   112      */
       
   113     public function createSignature(
       
   114     	$path = '/',
       
   115     	$resource = 'b',
       
   116     	$permissions = 'r',
       
   117     	$start = '',
       
   118     	$expiry = '',
       
   119     	$identifier = ''
       
   120     ) {
       
   121 		// Determine path
       
   122 		if ($this->_usePathStyleUri) {
       
   123 			$path = substr($path, strpos($path, '/'));
       
   124 		}
       
   125 			
       
   126 		// Add trailing slash to $path
       
   127 		if (substr($path, 0, 1) !== '/') {
       
   128 		    $path = '/' . $path;
       
   129 		}
       
   130 
       
   131 		// Build canonicalized resource string
       
   132 		$canonicalizedResource  = '/' . $this->_accountName;
       
   133 		/*if ($this->_usePathStyleUri) {
       
   134 			$canonicalizedResource .= '/' . $this->_accountName;
       
   135 		}*/
       
   136 		$canonicalizedResource .= $path;
       
   137 		    
       
   138 		// Create string to sign   
       
   139 		$stringToSign   = array();
       
   140 		$stringToSign[] = $permissions;
       
   141     	$stringToSign[] = $start;
       
   142     	$stringToSign[] = $expiry;
       
   143     	$stringToSign[] = $canonicalizedResource;
       
   144     	$stringToSign[] = $identifier;
       
   145 
       
   146     	$stringToSign = implode("\n", $stringToSign);
       
   147     	$signature    = base64_encode(hash_hmac('sha256', $stringToSign, $this->_accountKey, true));
       
   148 	
       
   149     	return $signature;
       
   150     }
       
   151 
       
   152     /**
       
   153      * Create signed query string
       
   154      * 
       
   155      * @param string $path 		   Path for the request
       
   156      * @param string $queryString  Query string for the request
       
   157      * @param string $resource     Signed resource - container (c) - blob (b)
       
   158      * @param string $permissions  Signed permissions - read (r), write (w), delete (d) and list (l)
       
   159      * @param string $start        The time at which the Shared Access Signature becomes valid.
       
   160      * @param string $expiry       The time at which the Shared Access Signature becomes invalid.
       
   161      * @param string $identifier   Signed identifier
       
   162      * @return string 
       
   163      */
       
   164     public function createSignedQueryString(
       
   165     	$path = '/',
       
   166     	$queryString = '',
       
   167     	$resource = 'b',
       
   168     	$permissions = 'r',
       
   169     	$start = '',
       
   170     	$expiry = '',
       
   171     	$identifier = ''
       
   172     ) {
       
   173         // Parts
       
   174         $parts = array();
       
   175         if ($start !== '') {
       
   176             $parts[] = 'st=' . urlencode($start);
       
   177         }
       
   178         $parts[] = 'se=' . urlencode($expiry);
       
   179         $parts[] = 'sr=' . $resource;
       
   180         $parts[] = 'sp=' . $permissions;
       
   181         if ($identifier !== '') {
       
   182             $parts[] = 'si=' . urlencode($identifier);
       
   183         }
       
   184         $parts[] = 'sig=' . urlencode($this->createSignature($path, $resource, $permissions, $start, $expiry, $identifier));
       
   185 
       
   186         // Assemble parts and query string
       
   187         if ($queryString != '') {
       
   188             $queryString .= '&';
       
   189 	    }
       
   190         $queryString .= implode('&', $parts);
       
   191 
       
   192         return $queryString;
       
   193     }
       
   194     
       
   195     /**
       
   196 	 * Permission matches request?
       
   197 	 *
       
   198 	 * @param string $permissionUrl Permission URL
       
   199 	 * @param string $requestUrl Request URL
       
   200 	 * @param string $resourceType Resource type
       
   201 	 * @param string $requiredPermission Required permission
       
   202 	 * @return string Signed request URL
       
   203 	 */
       
   204     public function permissionMatchesRequest(
       
   205     	$permissionUrl = '',
       
   206     	$requestUrl = '',
       
   207     	$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
       
   208     	$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
       
   209     ) {
       
   210         // Build requirements
       
   211         $requiredResourceType = $resourceType;
       
   212         if ($requiredResourceType == Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB) {
       
   213             $requiredResourceType .= Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER;
       
   214         }
       
   215 
       
   216         // Parse permission url
       
   217 	    $parsedPermissionUrl = parse_url($permissionUrl);
       
   218 	    
       
   219 	    // Parse permission properties
       
   220 	    $permissionParts = explode('&', $parsedPermissionUrl['query']);
       
   221 	    
       
   222 	    // Parse request url
       
   223 	    $parsedRequestUrl = parse_url($requestUrl);
       
   224 	    
       
   225 	    // Check if permission matches request
       
   226 	    $matches = true;
       
   227 	    foreach ($permissionParts as $part) {
       
   228 	        list($property, $value) = explode('=', $part, 2);
       
   229 	        
       
   230 	        if ($property == 'sr') {
       
   231 	            $matches = $matches && (strpbrk($value, $requiredResourceType) !== false);
       
   232 	        }
       
   233 	        
       
   234 	    	if ($property == 'sp') {
       
   235 	            $matches = $matches && (strpbrk($value, $requiredPermission) !== false);
       
   236 	        }
       
   237 	    }
       
   238 	    
       
   239 	    // Ok, but... does the resource match?
       
   240 	    $matches = $matches && (strpos($parsedRequestUrl['path'], $parsedPermissionUrl['path']) !== false);
       
   241 	    
       
   242         // Return
       
   243 	    return $matches;
       
   244     }    
       
   245     
       
   246     /**
       
   247 	 * Sign request URL with credentials
       
   248 	 *
       
   249 	 * @param string $requestUrl Request URL
       
   250 	 * @param string $resourceType Resource type
       
   251 	 * @param string $requiredPermission Required permission
       
   252 	 * @return string Signed request URL
       
   253 	 */
       
   254 	public function signRequestUrl(
       
   255 		$requestUrl = '',
       
   256 		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
       
   257 		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ
       
   258 	) {
       
   259 	    // Look for a matching permission
       
   260 	    foreach ($this->getPermissionSet() as $permittedUrl) {
       
   261 	        if ($this->permissionMatchesRequest($permittedUrl, $requestUrl, $resourceType, $requiredPermission)) {
       
   262 	            // This matches, append signature data
       
   263 	            $parsedPermittedUrl = parse_url($permittedUrl);
       
   264 
       
   265 	            if (strpos($requestUrl, '?') === false) {
       
   266 	                $requestUrl .= '?';
       
   267 	            } else {
       
   268 	                $requestUrl .= '&';
       
   269 	            }
       
   270 	            
       
   271 	            $requestUrl .= $parsedPermittedUrl['query'];
       
   272 
       
   273 	            // Return url
       
   274 	            return $requestUrl;
       
   275 	        }
       
   276 	    }
       
   277 	    
       
   278 	    // Return url, will be unsigned...
       
   279 	    return $requestUrl;
       
   280 	}
       
   281     
       
   282 	/**
       
   283 	 * Sign request with credentials
       
   284 	 *
       
   285 	 * @param string $httpVerb HTTP verb the request will use
       
   286 	 * @param string $path Path for the request
       
   287 	 * @param string $queryString Query string for the request
       
   288 	 * @param array $headers x-ms headers to add
       
   289 	 * @param boolean $forTableStorage Is the request for table storage?
       
   290 	 * @param string $resourceType Resource type
       
   291 	 * @param string $requiredPermission Required permission
       
   292 	 * @param mixed  $rawData Raw post data
       
   293 	 * @return array Array of headers
       
   294 	 */
       
   295 	public function signRequestHeaders(
       
   296 		$httpVerb = Zend_Http_Client::GET,
       
   297 		$path = '/',
       
   298 		$queryString = '',
       
   299 		$headers = null,
       
   300 		$forTableStorage = false,
       
   301 		$resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN,
       
   302 		$requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ,
       
   303 		$rawData = null
       
   304 	) {
       
   305 	    return $headers;
       
   306 	}
       
   307 }