File indexing completed on 2025-01-26 05:25:28
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Service_WindowsAzure 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract 0024 */ 0025 // require_once 'Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php'; 0026 0027 /** 0028 * @category Zend 0029 * @package Zend_Service_WindowsAzure 0030 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0031 * @license http://framework.zend.com/license/new-bsd New BSD License 0032 */ 0033 class Zend_Service_WindowsAzure_Credentials_SharedAccessSignature 0034 extends Zend_Service_WindowsAzure_Credentials_CredentialsAbstract 0035 { 0036 /** 0037 * Permission set 0038 * 0039 * @var array 0040 */ 0041 protected $_permissionSet = array(); 0042 0043 /** 0044 * Creates a new Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance 0045 * 0046 * @param string $accountName Account name for Windows Azure 0047 * @param string $accountKey Account key for Windows Azure 0048 * @param boolean $usePathStyleUri Use path-style URI's 0049 * @param array $permissionSet Permission set 0050 */ 0051 public function __construct( 0052 $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, 0053 $accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, 0054 $usePathStyleUri = false, $permissionSet = array() 0055 ) { 0056 parent::__construct($accountName, $accountKey, $usePathStyleUri); 0057 $this->_permissionSet = $permissionSet; 0058 } 0059 0060 /** 0061 * Get permission set 0062 * 0063 * @return array 0064 */ 0065 public function getPermissionSet() 0066 { 0067 return $this->_permissionSet; 0068 } 0069 0070 /** 0071 * Set permisison set 0072 * 0073 * Warning: fine-grained permissions should be added prior to coarse-grained permissions. 0074 * For example: first add blob permissions, end with container-wide permissions. 0075 * 0076 * Warning: the signed access signature URL must match the account name of the 0077 * Zend_Service_WindowsAzure_Credentials_Zend_Service_WindowsAzure_Credentials_SharedAccessSignature instance 0078 * 0079 * @param array $value Permission set 0080 * @return void 0081 */ 0082 public function setPermissionSet($value = array()) 0083 { 0084 foreach ($value as $url) { 0085 if (strpos($url, $this->_accountName) === false) { 0086 // require_once 'Zend/Service/WindowsAzure/Exception.php'; 0087 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.'); 0088 } 0089 } 0090 $this->_permissionSet = $value; 0091 } 0092 0093 /** 0094 * Create signature 0095 * 0096 * @param string $path Path for the request 0097 * @param string $resource Signed resource - container (c) - blob (b) 0098 * @param string $permissions Signed permissions - read (r), write (w), delete (d) and list (l) 0099 * @param string $start The time at which the Shared Access Signature becomes valid. 0100 * @param string $expiry The time at which the Shared Access Signature becomes invalid. 0101 * @param string $identifier Signed identifier 0102 * @return string 0103 */ 0104 public function createSignature( 0105 $path = '/', 0106 $resource = 'b', 0107 $permissions = 'r', 0108 $start = '', 0109 $expiry = '', 0110 $identifier = '' 0111 ) { 0112 // Determine path 0113 if ($this->_usePathStyleUri) { 0114 $path = substr($path, strpos($path, '/')); 0115 } 0116 0117 // Add trailing slash to $path 0118 if (substr($path, 0, 1) !== '/') { 0119 $path = '/' . $path; 0120 } 0121 0122 // Build canonicalized resource string 0123 $canonicalizedResource = '/' . $this->_accountName; 0124 /*if ($this->_usePathStyleUri) { 0125 $canonicalizedResource .= '/' . $this->_accountName; 0126 }*/ 0127 $canonicalizedResource .= $path; 0128 0129 // Create string to sign 0130 $stringToSign = array(); 0131 $stringToSign[] = $permissions; 0132 $stringToSign[] = $start; 0133 $stringToSign[] = $expiry; 0134 $stringToSign[] = $canonicalizedResource; 0135 $stringToSign[] = $identifier; 0136 0137 $stringToSign = implode("\n", $stringToSign); 0138 $signature = base64_encode(hash_hmac('sha256', $stringToSign, $this->_accountKey, true)); 0139 0140 return $signature; 0141 } 0142 0143 /** 0144 * Create signed query string 0145 * 0146 * @param string $path Path for the request 0147 * @param string $queryString Query string for the request 0148 * @param string $resource Signed resource - container (c) - blob (b) 0149 * @param string $permissions Signed permissions - read (r), write (w), delete (d) and list (l) 0150 * @param string $start The time at which the Shared Access Signature becomes valid. 0151 * @param string $expiry The time at which the Shared Access Signature becomes invalid. 0152 * @param string $identifier Signed identifier 0153 * @return string 0154 */ 0155 public function createSignedQueryString( 0156 $path = '/', 0157 $queryString = '', 0158 $resource = 'b', 0159 $permissions = 'r', 0160 $start = '', 0161 $expiry = '', 0162 $identifier = '' 0163 ) { 0164 // Parts 0165 $parts = array(); 0166 if ($start !== '') { 0167 $parts[] = 'st=' . urlencode($start); 0168 } 0169 $parts[] = 'se=' . urlencode($expiry); 0170 $parts[] = 'sr=' . $resource; 0171 $parts[] = 'sp=' . $permissions; 0172 if ($identifier !== '') { 0173 $parts[] = 'si=' . urlencode($identifier); 0174 } 0175 $parts[] = 'sig=' . urlencode($this->createSignature($path, $resource, $permissions, $start, $expiry, $identifier)); 0176 0177 // Assemble parts and query string 0178 if ($queryString != '') { 0179 $queryString .= '&'; 0180 } 0181 $queryString .= implode('&', $parts); 0182 0183 return $queryString; 0184 } 0185 0186 /** 0187 * Permission matches request? 0188 * 0189 * @param string $permissionUrl Permission URL 0190 * @param string $requestUrl Request URL 0191 * @param string $resourceType Resource type 0192 * @param string $requiredPermission Required permission 0193 * @return string Signed request URL 0194 */ 0195 public function permissionMatchesRequest( 0196 $permissionUrl = '', 0197 $requestUrl = '', 0198 $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN, 0199 $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ 0200 ) { 0201 // Build requirements 0202 $requiredResourceType = $resourceType; 0203 if ($requiredResourceType == Zend_Service_WindowsAzure_Storage::RESOURCE_BLOB) { 0204 $requiredResourceType .= Zend_Service_WindowsAzure_Storage::RESOURCE_CONTAINER; 0205 } 0206 0207 // Parse permission url 0208 $parsedPermissionUrl = parse_url($permissionUrl); 0209 0210 // Parse permission properties 0211 $permissionParts = explode('&', $parsedPermissionUrl['query']); 0212 0213 // Parse request url 0214 $parsedRequestUrl = parse_url($requestUrl); 0215 0216 // Check if permission matches request 0217 $matches = true; 0218 foreach ($permissionParts as $part) { 0219 list($property, $value) = explode('=', $part, 2); 0220 0221 if ($property == 'sr') { 0222 $matches = $matches && (strpbrk($value, $requiredResourceType) !== false); 0223 } 0224 0225 if ($property == 'sp') { 0226 $matches = $matches && (strpbrk($value, $requiredPermission) !== false); 0227 } 0228 } 0229 0230 // Ok, but... does the resource match? 0231 $matches = $matches && (strpos($parsedRequestUrl['path'], $parsedPermissionUrl['path']) !== false); 0232 0233 // Return 0234 return $matches; 0235 } 0236 0237 /** 0238 * Sign request URL with credentials 0239 * 0240 * @param string $requestUrl Request URL 0241 * @param string $resourceType Resource type 0242 * @param string $requiredPermission Required permission 0243 * @return string Signed request URL 0244 */ 0245 public function signRequestUrl( 0246 $requestUrl = '', 0247 $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN, 0248 $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ 0249 ) { 0250 // Look for a matching permission 0251 foreach ($this->getPermissionSet() as $permittedUrl) { 0252 if ($this->permissionMatchesRequest($permittedUrl, $requestUrl, $resourceType, $requiredPermission)) { 0253 // This matches, append signature data 0254 $parsedPermittedUrl = parse_url($permittedUrl); 0255 0256 if (strpos($requestUrl, '?') === false) { 0257 $requestUrl .= '?'; 0258 } else { 0259 $requestUrl .= '&'; 0260 } 0261 0262 $requestUrl .= $parsedPermittedUrl['query']; 0263 0264 // Return url 0265 return $requestUrl; 0266 } 0267 } 0268 0269 // Return url, will be unsigned... 0270 return $requestUrl; 0271 } 0272 0273 /** 0274 * Sign request with credentials 0275 * 0276 * @param string $httpVerb HTTP verb the request will use 0277 * @param string $path Path for the request 0278 * @param string $queryString Query string for the request 0279 * @param array $headers x-ms headers to add 0280 * @param boolean $forTableStorage Is the request for table storage? 0281 * @param string $resourceType Resource type 0282 * @param string $requiredPermission Required permission 0283 * @param mixed $rawData Raw post data 0284 * @return array Array of headers 0285 */ 0286 public function signRequestHeaders( 0287 $httpVerb = Zend_Http_Client::GET, 0288 $path = '/', 0289 $queryString = '', 0290 $headers = null, 0291 $forTableStorage = false, 0292 $resourceType = Zend_Service_WindowsAzure_Storage::RESOURCE_UNKNOWN, 0293 $requiredPermission = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ, 0294 $rawData = null 0295 ) { 0296 return $headers; 0297 } 0298 }