| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | namespace Acquia\Hmac; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | use Acquia\Hmac\Exception\InvalidSignatureException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | use Acquia\Hmac\Exception\KeyNotFoundException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | use Acquia\Hmac\Exception\MalformedRequestException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | use Acquia\Hmac\Exception\TimestampOutOfRangeException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | use Psr\Http\Message\RequestInterface; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 11 |  |  | class RequestAuthenticator implements RequestAuthenticatorInterface | 
            
                                                                        
                            
            
                                    
            
            
                | 12 |  |  | { | 
            
                                                                        
                            
            
                                    
            
            
                | 13 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 14 |  |  |      * @var \Acquia\Hmac\KeyLoaderInterface | 
            
                                                                        
                            
            
                                    
            
            
                | 15 |  |  |      *   The key loader. | 
            
                                                                        
                            
            
                                    
            
            
                | 16 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 17 |  |  |     protected $keyLoader; | 
            
                                                                        
                            
            
                                    
            
            
                | 18 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 19 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 20 |  |  |      * @var int|string | 
            
                                                                        
                            
            
                                    
            
            
                | 21 |  |  |      *   The amount of time drift requests can be made when compared to the server. | 
            
                                                                        
                            
            
                                    
            
            
                | 22 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 23 |  |  |     protected $expiry; | 
            
                                                                        
                            
            
                                    
            
            
                | 24 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 25 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 26 |  |  |      * @param \Acquia\Hmac\KeyLoaderInterface $keyLoader | 
            
                                                                        
                            
            
                                    
            
            
                | 27 |  |  |      *   A datastore used to locate secrets for corresponding IDs. | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 29 | 11 |  |     public function __construct(KeyLoaderInterface $keyLoader) | 
            
                                                                        
                            
            
                                    
            
            
                | 30 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 31 | 11 |  |         $this->keyLoader = $keyLoader; | 
            
                                                                        
                            
            
                                    
            
            
                | 32 | 11 |  |         $this->expiry    = '+15 min'; | 
            
                                                                        
                            
            
                                    
            
            
                | 33 | 11 |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 34 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 35 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 36 |  |  |      * {@inheritDoc} | 
            
                                                                        
                            
            
                                    
            
            
                | 37 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 38 | 11 |  |     public function authenticate(RequestInterface $request) | 
            
                                                                        
                            
            
                                    
            
            
                | 39 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 40 | 11 |  |         $authHeader = AuthorizationHeader::createFromRequest($request); | 
            
                                                                        
                            
            
                                    
            
            
                | 41 | 11 |  |         $signature = $authHeader->getSignature(); | 
            
                                                                        
                            
            
                                    
            
            
                | 42 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 43 |  |  |         // Check whether the timestamp is valid. | 
            
                                                                        
                            
            
                                    
            
            
                | 44 | 11 |  |         $comparison = $this->compareTimestamp($request, $this->expiry); | 
            
                                                                        
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 46 | 10 |  |         if (-1 == $comparison) { | 
            
                                                                        
                            
            
                                    
            
            
                | 47 | 1 |  |             throw new TimestampOutOfRangeException('Request is too old'); | 
            
                                                                        
                            
            
                                    
            
            
                | 48 | 9 |  |         } elseif (1 == $comparison) { | 
            
                                                                        
                            
            
                                    
            
            
                | 49 | 1 |  |             throw new TimestampOutOfRangeException('Request is too far in the future'); | 
            
                                                                        
                            
            
                                    
            
            
                | 50 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 52 |  |  |         // Load the API Key and sign the request. | 
            
                                                                        
                            
            
                                    
            
            
                | 53 | 8 |  |         if (!$key = $this->keyLoader->load($authHeader->getId())) { | 
            
                                                                        
                            
            
                                    
            
            
                | 54 | 1 |  |             throw new KeyNotFoundException('API key not found'); | 
            
                                                                        
                            
            
                                    
            
            
                | 55 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 57 |  |  |         // Generate the signature from the passed authorization header. | 
            
                                                                        
                            
            
                                    
            
            
                | 58 |  |  |         // If it matches the request signature, the request is authenticated. | 
            
                                                                        
                            
            
                                    
            
            
                | 59 | 7 |  |         $compareRequest = $request->withoutHeader('Authorization'); | 
            
                                                                        
                            
            
                                    
            
            
                | 60 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 61 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 62 | 7 |  |         $authHeaderBuilder = new AuthorizationHeaderBuilder($compareRequest, $key); | 
            
                                                                        
                            
            
                                    
            
            
                | 63 | 7 |  |         $authHeaderBuilder->setRealm($authHeader->getRealm()); | 
            
                                                                        
                            
            
                                    
            
            
                | 64 | 7 |  |         $authHeaderBuilder->setId($authHeader->getId()); | 
            
                                                                        
                            
            
                                    
            
            
                | 65 | 7 |  |         $authHeaderBuilder->setNonce($authHeader->getNonce()); | 
            
                                                                        
                            
            
                                    
            
            
                | 66 | 7 |  |         $authHeaderBuilder->setVersion($authHeader->getVersion()); | 
            
                                                                        
                            
            
                                    
            
            
                | 67 | 7 |  |         $authHeaderBuilder->setCustomHeaders($authHeader->getCustomHeaders()); | 
            
                                                                        
                            
            
                                    
            
            
                | 68 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 69 | 7 |  |         $compareAuthHeader = $authHeaderBuilder->getAuthorizationHeader(); | 
            
                                                                        
                            
            
                                    
            
            
                | 70 | 7 |  |         $compareSignature = $compareAuthHeader->getSignature(); | 
            
                                                                        
                            
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 72 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 73 | 7 |  |         if (!hash_equals($compareSignature, $signature)) { | 
            
                                                                        
                            
            
                                    
            
            
                | 74 | 1 |  |             throw new InvalidSignatureException('Signature not valid'); | 
            
                                                                        
                            
            
                                    
            
            
                | 75 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 76 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 77 | 6 |  |         return $key; | 
            
                                                                        
                            
            
                                    
            
            
                | 78 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 79 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 80 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 81 |  |  |      * Retrieves the current timestamp. | 
            
                                                                        
                            
            
                                    
            
            
                | 82 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 83 |  |  |      * This is provided as a method to allow mocking during unit tests. | 
            
                                                                        
                            
            
                                    
            
            
                | 84 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 85 |  |  |      * @return int | 
            
                                                                        
                            
            
                                    
            
            
                | 86 |  |  |      *   The current timestamp. | 
            
                                                                        
                            
            
                                    
            
            
                | 87 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 | 2 |  |     protected function getCurrentTimestamp() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |     { | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 90 | 2 |  |         return time(); | 
            
                                                                        
                                                                
            
                                    
            
            
                | 91 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 92 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 93 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 94 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 95 |  |  |      * {@inheritDoc} | 
            
                                                                        
                            
            
                                    
            
            
                | 96 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 97 |  |  |      * @throws \InvalidArgumentException | 
            
                                                                        
                            
            
                                    
            
            
                | 98 |  |  |      */ | 
            
                                                                        
                            
            
                                    
            
            
                | 99 | 11 |  |     protected function compareTimestamp(RequestInterface $request, $expiry) | 
            
                                                                        
                            
            
                                    
            
            
                | 100 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 101 | 11 |  |         if (!$request->hasHeader('X-Authorization-Timestamp')) { | 
            
                                                                        
                            
            
                                    
            
            
                | 102 | 1 |  |             throw new MalformedRequestException('Request is missing X-Authorization-Timestamp.', null, 0, $request); | 
            
                                                                        
                            
            
                                    
            
            
                | 103 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 104 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 105 | 10 |  |         $timestamp = (int) $request->getHeaderLine('X-Authorization-Timestamp'); | 
            
                                                                        
                            
            
                                    
            
            
                | 106 | 10 |  |         $current   = $this->getCurrentTimestamp(); | 
            
                                                                        
                            
            
                                    
            
            
                | 107 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 108 |  |  |         // Is the request too old? | 
            
                                                                        
                            
            
                                    
            
            
                | 109 | 10 |  |         $lowerLimit = $this->getExpiry($expiry, $timestamp); | 
            
                                                                        
                            
            
                                    
            
            
                | 110 | 10 |  |         if ($current > $lowerLimit) { | 
            
                                                                        
                            
            
                                    
            
            
                | 111 | 1 |  |             return -1; | 
            
                                                                        
                            
            
                                    
            
            
                | 112 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 113 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 114 |  |  |         // Is the request too far in the future? | 
            
                                                                        
                            
            
                                    
            
            
                | 115 | 9 |  |         $upperLimit = $this->getExpiry($expiry, $current); | 
            
                                                                        
                            
            
                                    
            
            
                | 116 | 9 |  |         if ($timestamp > $upperLimit) { | 
            
                                                                        
                            
            
                                    
            
            
                | 117 | 1 |  |             return 1; | 
            
                                                                        
                            
            
                                    
            
            
                | 118 |  |  |         } | 
            
                                                                        
                            
            
                                    
            
            
                | 119 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 120 |  |  |         // Timestamp is within the expected range. | 
            
                                                                        
                            
            
                                    
            
            
                | 121 | 8 |  |         return 0; | 
            
                                                                        
                            
            
                                    
            
            
                | 122 |  |  |     } | 
            
                                                                        
                            
            
                                    
            
            
                | 123 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 124 |  |  |     /** | 
            
                                                                        
                            
            
                                    
            
            
                | 125 |  |  |      * Retrieves the request expiry as a timestamp. | 
            
                                                                        
                            
            
                                    
            
            
                | 126 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 127 |  |  |      * @param int|string $expiry | 
            
                                                                        
                            
            
                                    
            
            
                | 128 |  |  |      *   The passed expiry. | 
            
                                                                        
                            
            
                                    
            
            
                | 129 |  |  |      * @param int $relativeTimestamp | 
            
                                                                        
                            
            
                                    
            
            
                | 130 |  |  |      *   The timestamp from which to base the expiry. | 
            
                                                                        
                            
            
                                    
            
            
                | 131 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 132 |  |  |      * @return int | 
            
                                                                        
                            
            
                                    
            
            
                | 133 |  |  |      *   The expiry as a timestamp. | 
            
                                                                        
                            
            
                                    
            
            
                | 134 |  |  |      * | 
            
                                                                        
                            
            
                                    
            
            
                | 135 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 | 10 |  |     protected function getExpiry($expiry, $relativeTimestamp) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 | 10 |  |         if (!is_int($expiry)) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 | 10 |  |             $expiry = strtotime($expiry, $relativeTimestamp); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 142 | 10 |  |         return $expiry; | 
            
                                                                        
                                                                
            
                                    
            
            
                | 143 |  |  |     } | 
            
                                                                        
                                                                
            
                                    
            
            
                | 144 |  |  | } | 
            
                                                                        
                                                                
            
                                    
            
            
                | 145 |  |  |  |