AuthenticationSubscriber.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. namespace Drupal\Core\EventSubscriber;
  3. use Drupal\Core\Authentication\AuthenticationProviderFilterInterface;
  4. use Drupal\Core\Authentication\AuthenticationProviderChallengeInterface;
  5. use Drupal\Core\Authentication\AuthenticationProviderInterface;
  6. use Drupal\Core\Session\AccountProxyInterface;
  7. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  8. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  9. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
  10. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  11. use Symfony\Component\HttpKernel\HttpKernelInterface;
  12. use Symfony\Component\HttpKernel\KernelEvents;
  13. /**
  14. * Authentication subscriber.
  15. *
  16. * Trigger authentication during the request.
  17. */
  18. class AuthenticationSubscriber implements EventSubscriberInterface {
  19. /**
  20. * Authentication provider.
  21. *
  22. * @var \Drupal\Core\Authentication\AuthenticationProviderInterface
  23. */
  24. protected $authenticationProvider;
  25. /**
  26. * Authentication provider filter.
  27. *
  28. * @var \Drupal\Core\Authentication\AuthenticationProviderFilterInterface|null
  29. */
  30. protected $filter;
  31. /**
  32. * Authentication challenge provider.
  33. *
  34. * @var \Drupal\Core\Authentication\AuthenticationProviderChallengeInterface|null
  35. */
  36. protected $challengeProvider;
  37. /**
  38. * Account proxy.
  39. *
  40. * @var \Drupal\Core\Session\AccountProxyInterface
  41. */
  42. protected $accountProxy;
  43. /**
  44. * Constructs an authentication subscriber.
  45. *
  46. * @param \Drupal\Core\Authentication\AuthenticationProviderInterface $authentication_provider
  47. * An authentication provider.
  48. * @param \Drupal\Core\Session\AccountProxyInterface $account_proxy
  49. * Account proxy.
  50. */
  51. public function __construct(AuthenticationProviderInterface $authentication_provider, AccountProxyInterface $account_proxy) {
  52. $this->authenticationProvider = $authentication_provider;
  53. $this->filter = ($authentication_provider instanceof AuthenticationProviderFilterInterface) ? $authentication_provider : NULL;
  54. $this->challengeProvider = ($authentication_provider instanceof AuthenticationProviderChallengeInterface) ? $authentication_provider : NULL;
  55. $this->accountProxy = $account_proxy;
  56. }
  57. /**
  58. * Authenticates user on request.
  59. *
  60. * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
  61. * The request event.
  62. *
  63. * @see \Drupal\Core\Authentication\AuthenticationProviderInterface::authenticate()
  64. */
  65. public function onKernelRequestAuthenticate(GetResponseEvent $event) {
  66. if ($event->getRequestType() === HttpKernelInterface::MASTER_REQUEST) {
  67. $request = $event->getRequest();
  68. if ($this->authenticationProvider->applies($request)) {
  69. $account = $this->authenticationProvider->authenticate($request);
  70. if ($account) {
  71. $this->accountProxy->setAccount($account);
  72. return;
  73. }
  74. }
  75. // No account has been set explicitly, initialize the timezone here.
  76. date_default_timezone_set(drupal_get_user_timezone());
  77. }
  78. }
  79. /**
  80. * Denies access if authentication provider is not allowed on this route.
  81. *
  82. * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
  83. * The request event.
  84. */
  85. public function onKernelRequestFilterProvider(GetResponseEvent $event) {
  86. if (isset($this->filter) && $event->getRequestType() === HttpKernelInterface::MASTER_REQUEST) {
  87. $request = $event->getRequest();
  88. if ($this->authenticationProvider->applies($request) && !$this->filter->appliesToRoutedRequest($request, TRUE)) {
  89. throw new AccessDeniedHttpException('The used authentication method is not allowed on this route.');
  90. }
  91. }
  92. }
  93. /**
  94. * Respond with a challenge on access denied exceptions if appropriate.
  95. *
  96. * On a 403 (access denied), if there are no credentials on the request, some
  97. * authentication methods (e.g. basic auth) require that a challenge is sent
  98. * to the client.
  99. *
  100. * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
  101. * The exception event.
  102. */
  103. public function onExceptionSendChallenge(GetResponseForExceptionEvent $event) {
  104. if (isset($this->challengeProvider) && $event->getRequestType() === HttpKernelInterface::MASTER_REQUEST) {
  105. $request = $event->getRequest();
  106. $exception = $event->getException();
  107. if ($exception instanceof AccessDeniedHttpException && !$this->authenticationProvider->applies($request) && (!isset($this->filter) || $this->filter->appliesToRoutedRequest($request, FALSE))) {
  108. $challenge_exception = $this->challengeProvider->challengeException($request, $exception);
  109. if ($challenge_exception) {
  110. $event->setException($challenge_exception);
  111. }
  112. }
  113. }
  114. }
  115. /**
  116. * {@inheritdoc}
  117. */
  118. public static function getSubscribedEvents() {
  119. // The priority for authentication must be higher than the highest event
  120. // subscriber accessing the current user. Especially it must be higher than
  121. // LanguageRequestSubscriber as LanguageManager accesses the current user if
  122. // the language module is enabled.
  123. $events[KernelEvents::REQUEST][] = ['onKernelRequestAuthenticate', 300];
  124. // Access check must be performed after routing.
  125. $events[KernelEvents::REQUEST][] = ['onKernelRequestFilterProvider', 31];
  126. $events[KernelEvents::EXCEPTION][] = ['onExceptionSendChallenge', 75];
  127. return $events;
  128. }
  129. }