* @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:----izbZPm0Vxh+UEXzb1gVwNuQNAG5RGRW7k9DLHbWk1RXyr6WOsaZdCdqfEfF8nlLAR9iiOwPXbV95czCs5BClTOjhflCsQk7Br1acnUPsQZlhLjA7FMnT1bxCY/s0yJ58V0sOcmrWw/yaUDuF+O9mlpjqagh7m22v4qG9WnmxR3YtTUqU9wzw/B1mhibQGv4l7dTgoqwQ9HApKmEuxQi4NDC0a9DjKuINBNTGZLzPFRpycGsPaFGPe9u6hFpnOXyKrFCFTJ5NoS7xbytabJmHotj0GSsCGdNYisFw6GkGrg2YtwCFs5qUWUgpRP7o1A5/7u5mMqkSUtxNo4CKlX8i76xn4MqpQVMOyHhTXd1u9a0s6wJ9NA4zQEaRmV9EoPvu2IJ918JWAdHGhx6wL9E/yZASJgPMS5eTCH7PcIkUrSQwJW760op5nqj7Twh5B3pTNNo0f83hZh9/ePxZDqFSFMZ8Q4s1wUATo+mGH2Kuz1gw9S46IVFSNXvCVG9I2bHqCH29SWusahKvWYJQfjfd8PibNiy6ZnvERwBXVLPYqr1mAxPQWUn3CS2CwkuElBZKrb16PuGaMhzLCWO/Ee3WARKG8TbUJZKFDq8Kvfs5hAzwXXdE2EJpxBXGo0rsIP9bUNFcay4b2Ft6qv29PgUN/7w/2wjtTu3mUZ8yeHnKhgI=----ATTACHMENT:----NzAyOTExMDkxOTQ5MzkwMyA2NzkxMzc2OTc3NDExNDkzIDM3NzMzOTQ3NjczNDg5NDA=