/** * Handles digest authentication. * * @param EventInterface $event An EventInterface instance */ public function handle(EventInterface $event) { $request = $event->get('request'); if (!($header = $request->server->get('PHP_AUTH_DIGEST'))) { return; } $digestAuth = new DigestData($header); if (null !== ($token = $this->securityContext->getToken())) { if ($token->isImmutable()) { return; } if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && (string) $token === $digestAuth->getUsername()) { return; } } if (null !== $this->logger) { $this->logger->debug(sprintf('Digest Authorization header received from user agent: %s', $header)); } try { $digestAuth->validateAndDecode($this->authenticationEntryPoint->getKey(), $this->authenticationEntryPoint->getRealmName()); } catch (BadCredentialsException $e) { $this->fail($event, $request, $e); return; } try { $user = $this->provider->loadUserByUsername($digestAuth->getUsername()); if (null === $user) { throw new AuthenticationServiceException('AuthenticationDao returned null, which is an interface contract violation'); } $serverDigestMd5 = $digestAuth->calculateServerDigest($user->getPassword(), $request->getMethod()); } catch (UsernameNotFoundException $notFound) { $this->fail($event, $request, new BadCredentialsException(sprintf('Username %s not found.', $digestAuth->getUsername()))); return; } if ($serverDigestMd5 !== $digestAuth->getResponse()) { if (null !== $this->logger) { $this->logger->debug(sprintf("Expected response: '%s' but received: '%s'; is AuthenticationDao returning clear text passwords?", $serverDigestMd5, $digestAuth->getResponse())); } $this->fail($event, $request, new BadCredentialsException('Incorrect response')); return; } if ($digestAuth->isNonceExpired()) { $this->fail($event, $request, new NonceExpiredException('Nonce has expired/timed out.')); return; } if (null !== $this->logger) { $this->logger->debug(sprintf('Authentication success for user "%s" with response "%s"', $digestAuth->getUsername(), $digestAuth->getResponse())); } $this->securityContext->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey)); }
/** * Handles digest authentication. * * @param GetResponseEvent $event A GetResponseEvent instance * * @throws AuthenticationServiceException */ public function handle(GetResponseEvent $event) { $request = $event->getRequest(); if (!($header = $request->server->get('PHP_AUTH_DIGEST'))) { return; } $digestAuth = new DigestData($header); if (null !== ($token = $this->tokenStorage->getToken())) { if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $digestAuth->getUsername()) { return; } } if (null !== $this->logger) { $this->logger->debug('Digest Authorization header received from user agent.', array('header' => $header)); } try { $digestAuth->validateAndDecode($this->authenticationEntryPoint->getKey(), $this->authenticationEntryPoint->getRealmName()); } catch (BadCredentialsException $e) { $this->fail($event, $request, $e); return; } try { $user = $this->provider->loadUserByUsername($digestAuth->getUsername()); if (null === $user) { throw new AuthenticationServiceException('Digest User provider returned null, which is an interface contract violation'); } $serverDigestMd5 = $digestAuth->calculateServerDigest($user->getPassword(), $request->getMethod()); } catch (UsernameNotFoundException $e) { $this->fail($event, $request, new BadCredentialsException(sprintf('Username %s not found.', $digestAuth->getUsername()))); return; } if ($serverDigestMd5 !== $digestAuth->getResponse()) { if (null !== $this->logger) { $this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse())); } $this->fail($event, $request, new BadCredentialsException('Incorrect response')); return; } if ($digestAuth->isNonceExpired()) { $this->fail($event, $request, new NonceExpiredException('Nonce has expired/timed out.')); return; } if (null !== $this->logger) { $this->logger->info('Digest authentication successful.', array('username' => $digestAuth->getUsername(), 'received' => $digestAuth->getResponse())); } $this->tokenStorage->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey)); }
private function calculateServerDigest($username, $realm, $password, $key, $nc, $cnonce, $qop, $method, $uri) { $time = microtime(true); $nonce = base64_encode($time . ':' . md5($time . ':' . $key)); $response = md5(md5($username . ':' . $realm . ':' . $password) . ':' . $nonce . ':' . $nc . ':' . $cnonce . ':' . $qop . ':' . md5($method . ':' . $uri)); $digest = sprintf('username="******", realm="%s", nonce="%s", uri="%s", cnonce="%s", nc=%s, qop="%s", response="%s"', $username, $realm, $nonce, $uri, $cnonce, $nc, $qop, $response); $digestAuth = new DigestData($digest); $this->assertEquals($digestAuth->getResponse(), $digestAuth->calculateServerDigest($password, $method)); }