Вход Регистрация
Файл: library/Sabre/Sabre/HTTP/AWSAuth.php
Строк: 158
<?php

/**
 * HTTP AWS Authentication handler
 *
 * Use this class to leverage amazon's AWS authentication header
 * 
 * @package Sabre
 * @subpackage HTTP 
 * @version $Id$
 * @copyright Copyright (C) 2010 Rooftop Solutions. All rights reserved.
 * @author Evert Pot (http://www.rooftopsolutions.nl/) 
 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
 */
class Sabre_HTTP_AWSAuth extends Sabre_HTTP_AbstractAuth {

    
/**
     * The signature supplied by the HTTP client 
     * 
     * @var string 
     */
    
private $signature null;

    
/**
     * The accesskey supplied by the HTTP client 
     * 
     * @var string 
     */
    
private $accessKey null;

    
/**
     * An error code, if any
     *
     * This value will be filled with one of the ERR_* contants
     * 
     * @var int
     */
    
public $errorCode 0;

    const 
ERR_NOAWSHEADER 1;
    const 
ERR_MD5CHECKSUMWRONG 2;
    const 
ERR_INVALIDDATEFORMAT 3;
    const 
ERR_REQUESTTIMESKEWED 4;
    const 
ERR_INVALIDSIGNATURE 5;

    
/**
     * Gathers all information from the headers
     *
     * This method needs to be called prior to anything else.
     * 
     * @return bool 
     */
    
public function init() {

        
$authHeader $this->httpRequest->getHeader('Authorization');
        
$authHeader explode(' ',$authHeader);

        if (
$authHeader[0]!='AWS' || !isset($authHeader[1])) {
            
$this->errorCode self::ERR_NOAWSHEADER;
             return 
false;
        }

        list(
$this->accessKey,$this->signature) = explode(':',$authHeader[1]);

        return 
true;

    }

    
/**
     * Returns the username for the request 
     * 
     * @return string 
     */
    
public function getAccessKey() {

        return 
$this->accessKey;

    }

    
/**
     * Validates the signature based on the secretKey
     * 
     * @return bool 
     */
    
public function validate($secretKey) {

        
$contentMD5 $this->httpRequest->getHeader('Content-MD5');

        if (
$contentMD5) {
            
// We need to validate the integrity of the request
            
$body $this->httpRequest->getBody(true);
            
$this->httpRequest->setBody($body,true);
           
            if (
$contentMD5!=base64_encode(md5($body,true))) {
                
// content-md5 header did not match md5 signature of body
                
$this->errorCode self::ERR_MD5CHECKSUMWRONG;
                return 
false;
            }

        }

        if (!
$requestDate $this->httpRequest->getHeader('x-amz-date')) 
            
$requestDate $this->httpRequest->getHeader('Date');

        if (!
$this->validateRFC2616Date($requestDate)) 
            return 
false;

        
$amzHeaders $this->getAmzHeaders();

        
$signature base64_encode(
            
$this->hmacsha1($secretKey,
                
$this->httpRequest->getMethod() . "n" .
                
$contentMD5 "n" 
                
$this->httpRequest->getHeader('Content-type') . "n" .
                
$requestDate "n" .
                
$amzHeaders 
                
$this->httpRequest->getURI()
            )
        );

        if (
$this->signature != $signature) {

            
$this->errorCode self::ERR_INVALIDSIGNATURE;
            return 
false;

        }

        return 
true;

    }


    
/**
     * Returns an HTTP 401 header, forcing login
     *
     * This should be called when username and password are incorrect, or not supplied at all
     *
     * @return void
     */
    
public function requireLogin() {

        
$this->httpResponse->setHeader('WWW-Authenticate','AWS');
        
$this->httpResponse->sendStatus(401);

    }

    
/**
     * Makes sure the supplied value is a valid RFC2616 date.
     *
     * If we would just use strtotime to get a valid timestamp, we have no way of checking if a 
     * user just supplied the word 'now' for the date header.
     *
     * This function also makes sure the Date header is within 15 minutes of the operating 
     * system date, to prevent replay attacks.
     * 
     * @param string $dateHeader 
     * @return bool 
     */
    
protected function validateRFC2616Date($dateHeader) {

        
$patterns = array(
             
// Matches: Sun, 06 Nov 1994 08:49:37 GMT
             
'%a, %d %h %Y %H:%M:%S %z',
             
'%a, %d %h %Y %H:%M:%S %Z',
             
// Matches: Sunday, 06-Nov-94 08:49:37 GMT
             
'%A, %d-%h-%y %H:%M:%S %z',
             
'%A, %d-%h-%y %H:%M:%S %Z',
             
// Matches: Sun Nov  6 08:49:37 1994
            
'%a %h %e %H:%M:%S %Y'
         
);

        
$realDate 0;
        foreach(
$patterns as $pattern) {

            if (
$date_arr strptime($dateHeader,$pattern)) {
                
$realDate strtotime($dateHeader);
                break;
            }

        }

        
// Unknown format
        
if (!$realDate) {
            
$this->errorCode self::ERR_INVALIDDATEFORMAT;
            return 
false;
        }

        
$currentDate time();

        
// We allow 15 minutes around the current date/time
        
if ($realDate > ($currentDate + (60 15))) {
            
$this->errorCode self::ERR_REQUESTTIMESKEWED;
            return 
false;
        }

        if (
$realDate < ($currentDate - (60 15))) {
            
$this->errorCode self::ERR_REQUESTTIMESKEWED;
            return 
false;
        }

        return 
$realDate;

    }
    
    
/**
     * Returns a list of AMZ headers 
     * 
     * @return void
     */
    
protected function getAmzHeaders() {

        
$amzHeaders = array();
        
$headers $this->httpRequest->getHeaders();
        foreach(
$headers as $headerName => $headerValue) {
            if (
strpos(strtolower($headerName),'x-amz-')===0) {
                
$amzHeaders[strtolower($headerName)] = str_replace(array("rn"),array(' '),$headerValue) . "n";
            }
        }
        
ksort($amzHeaders);
       
        
$headerStr '';
        foreach(
$amzHeaders as $h=>$v) {
            
$headerStr.=$h.':'.$v;
        }

        return 
$headerStr;

    }

    
/**
     * Generates an HMAC-SHA1 signature 
     * 
     * @param string $key 
     * @param string $message 
     * @return string 
     */
    
private function hmacsha1($key$message) {

        
$blocksize=64;
        if (
strlen($key)>$blocksize)
            
$key=pack('H*'sha1($key));
        
$key=str_pad($key,$blocksize,chr(0x00));
        
$ipad=str_repeat(chr(0x36),$blocksize);
        
$opad=str_repeat(chr(0x5c),$blocksize);
        
$hmac pack('H*',sha1(($key^$opad).pack('H*',sha1(($key^$ipad).$message))));
        return 
$hmac;

    }

}
Онлайн: 0
Реклама