* @license http://www.apache.org/licenses/LICENSE-2.0 * @link http://phpsx.org */ class DigestAuthentication implements FilterInterface { /** @var \Closure */ protected $ha1Callback; /** @var \PSX\Http\Filter\DigestAuthentication\StoreInterface */ protected $digestStore; /** @var \Closure */ protected $successCallback; /** @var \Closure */ protected $failureCallback; /** @var \Closure */ protected $missingCallback; /** * The ha1Callback should return "md5([username]:[realm]:[pw])" which * is then used to compare the response from the client. If its successful * the onSuccess callback is called else the onFailure. If the Authorization * header is missing the onMissing callback is called. The default behavior * is to store the nonce and opaque in the session but you can overwrite * that by providing a nonce and opaque in the constructor and overwrite the * default onMissing callback * * @param Closure $ha1Callback * @param \PSX\Http\Filter\DigestAuthentication\StoreInterface $digestStore */ public function __construct(Closure $ha1Callback, StoreInterface $digestStore) { $this->ha1Callback = $ha1Callback; $this->digestStore = $digestStore; $this->onSuccess(function () { // authentication successful }); $this->onFailure(function () { throw new BadRequestException('Invalid username or password'); }); $this->onMissing(function (ResponseInterface $response) use ($digestStore) { $digest = new Digest(); $digest->setNonce($this->generateNonce()); $digest->setOpaque($this->generateOpaque()); $digestStore->save($digest->getOpaque(), $digest); $params = array( 'realm' => 'psx', 'qop' => 'auth,auth-int', 'nonce' => $digest->getNonce(), 'opaque' => $digest->getOpaque(), ); throw new UnauthorizedException('Missing authorization header', 'Digest', $params); }); } public function handle(RequestInterface $request, ResponseInterface $response, FilterChainInterface $filterChain) { $authorization = $request->getHeader('Authorization'); if (!empty($authorization)) { $parts = explode(' ', $authorization, 2); $type = isset($parts[0]) ? $parts[0] : null; $data = isset($parts[1]) ? $parts[1] : null; if ($type == 'Digest' && !empty($data)) { $params = Authentication::decodeParameters($data); $algo = isset($params['algorithm']) ? $params['algorithm'] : 'MD5'; $qop = isset($params['qop']) ? $params['qop'] : 'auth'; $digest = $this->digestStore->load($params['opaque']); if (!$digest instanceof Digest) { throw new BadRequestException('Digest not available'); } if ($digest->getOpaque() != $params['opaque']) { throw new BadRequestException('Invalid opaque'); } // build ha1 $ha1 = call_user_func_array($this->ha1Callback, array($params['username'])); if ($algo == 'MD5-sess') { $ha1 = md5($ha1 . ':' . $digest->getNonce() . ':' . $params['cnonce']); } // build ha2 if ($qop == 'auth-int') { $ha2 = md5($request->getMethod() . ':' . $request->getUri()->getPath() . ':' . md5($request->getBody())); } else { $ha2 = md5($request->getMethod() . ':' . $request->getUri()->getPath()); } // build response if ($qop == 'auth' || $qop == 'auth-int') { $hash = md5($ha1 . ':' . $digest->getNonce() . ':' . $params['nc'] . ':' . $params['cnonce'] . ':' . $qop . ':' . $ha2); } else { $hash = md5($ha1 . ':' . $digest->getNonce() . ':' . $ha2); } if (strcmp($hash, $params['response']) === 0) { $this->callSuccess($response); $filterChain->handle($request, $response); } else { $this->callFailure($response); } } else { $this->callMissing($response); } } else { $this->callMissing($response); } } public function onSuccess(Closure $successCallback) { $this->successCallback = $successCallback; } public function onFailure(Closure $failureCallback) { $this->failureCallback = $failureCallback; } public function onMissing(Closure $missingCallback) { $this->missingCallback = $missingCallback; } protected function callSuccess(ResponseInterface $response) { call_user_func_array($this->successCallback, array($response)); } protected function callFailure(ResponseInterface $response) { call_user_func_array($this->failureCallback, array($response)); } protected function callMissing(ResponseInterface $response) { call_user_func_array($this->missingCallback, array($response)); } protected function generateNonce() { return sha1(time() . uniqid()); } protected function generateOpaque() { return sha1(time() . uniqid()); } } __halt_compiler();----SIGNATURE:----YI7FKdNs9uq+ppjA67vRjSukyNaUosKrifHdEGof/o08CphQGwfr9G2Kt9T93JgQHYQW3faO5stdfJBGDt8MYqR5yE/VaEIJX3yIl9Fp3DRZdXnOt1eXtLY6HFo2joOfgaRYTPmOKKqOAIcAOy+XK+fRxRib5CVtFk5RB06Zqo7uEo9c0gxXkdE8RHtA0ABz1nKRPdlCV05lWNr/Vz3U+x1fmtKFK99PT/uywI09hiReZO/IR3SAnT6H7ZN9zQpXseEqGdZb+vx9ovZUuXUngC7bOkzXbohHvASNjn4V1uMmvyxHut/S9Wn7IxETpn88/6Fm/RG8ZV+8C0uVHtvTVKAcBJeT8jv/xSjgjALNhDYoRIWu59wJrw2G3CHKHa8W8SysOO5yqKUAPWYnF06LE7TI7tsQzbLuyd9ZFRCvqjcvVzGT+1ZE+QSbcoqJzDmkAyKHbEFMB3dUfMnnd1JTRmaeRBXhAT/WrG8eXcWAZUHi8T4zoAJNtChAOSxmposGl7g67e4gMcyENVergb4z5V+VkwsPH/BtIHC0l9oNE0YnPoWRjysSMUaRJIb2YcqwKjB1N72qiS+y4H7pB0e6g0YoGDy5vVI7TUdcpU2zkw1217WPKuF5DIUDVPZhclfKuD3t4CRU7Bal4Or5QDSyl9XLQdNamYhyz90BbEbGi4Y=----ATTACHMENT:----NTc2ODQ5NzM0OTcwNTA4NiAyNjEzNTM2Nzk0MjE3NzQgOTkwNzkwNzM0Njk0ODkzOA==