AuthenticationManager.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. namespace Drupal\Core\Authentication;
  3. use Drupal\Core\Routing\RouteMatch;
  4. use Symfony\Component\HttpFoundation\Request;
  5. /**
  6. * Manager for authentication.
  7. *
  8. * On each request, let all authentication providers try to authenticate the
  9. * user. The providers are iterated according to their priority and the first
  10. * provider detecting credentials for its method wins. No further provider will
  11. * get triggered.
  12. *
  13. * If no provider sets an active user then the user remains anonymous.
  14. */
  15. class AuthenticationManager implements AuthenticationProviderInterface, AuthenticationProviderFilterInterface, AuthenticationProviderChallengeInterface {
  16. /**
  17. * The authentication provider collector.
  18. *
  19. * @var \Drupal\Core\Authentication\AuthenticationCollectorInterface
  20. */
  21. protected $authCollector;
  22. /**
  23. * Creates a new authentication manager instance.
  24. *
  25. * @param \Drupal\Core\Authentication\AuthenticationCollectorInterface $auth_collector
  26. * The authentication provider collector.
  27. */
  28. public function __construct(AuthenticationCollectorInterface $auth_collector) {
  29. $this->authCollector = $auth_collector;
  30. }
  31. /**
  32. * {@inheritdoc}
  33. */
  34. public function applies(Request $request) {
  35. return (bool) $this->getProvider($request);
  36. }
  37. /**
  38. * {@inheritdoc}
  39. */
  40. public function authenticate(Request $request) {
  41. $provider_id = $this->getProvider($request);
  42. $provider = $this->authCollector->getProvider($provider_id);
  43. if ($provider) {
  44. return $provider->authenticate($request);
  45. }
  46. return NULL;
  47. }
  48. /**
  49. * {@inheritdoc}
  50. */
  51. public function appliesToRoutedRequest(Request $request, $authenticated) {
  52. $result = FALSE;
  53. if ($authenticated) {
  54. $result = $this->applyFilter($request, $authenticated, $this->getProvider($request));
  55. }
  56. else {
  57. foreach ($this->authCollector->getSortedProviders() as $provider_id => $provider) {
  58. if ($this->applyFilter($request, $authenticated, $provider_id)) {
  59. $result = TRUE;
  60. break;
  61. }
  62. }
  63. }
  64. return $result;
  65. }
  66. /**
  67. * {@inheritdoc}
  68. */
  69. public function challengeException(Request $request, \Exception $previous) {
  70. $provider_id = $this->getChallenger($request);
  71. if ($provider_id) {
  72. $provider = $this->authCollector->getProvider($provider_id);
  73. return $provider->challengeException($request, $previous);
  74. }
  75. }
  76. /**
  77. * Returns the id of the authentication provider for a request.
  78. *
  79. * @param \Symfony\Component\HttpFoundation\Request $request
  80. * The incoming request.
  81. *
  82. * @return string|null
  83. * The id of the first authentication provider which applies to the request.
  84. * If no application detects appropriate credentials, then NULL is returned.
  85. */
  86. protected function getProvider(Request $request) {
  87. foreach ($this->authCollector->getSortedProviders() as $provider_id => $provider) {
  88. if ($provider->applies($request)) {
  89. return $provider_id;
  90. }
  91. }
  92. }
  93. /**
  94. * Returns the ID of the challenge provider for a request.
  95. *
  96. * @param \Symfony\Component\HttpFoundation\Request $request
  97. * The incoming request.
  98. *
  99. * @return string|null
  100. * The ID of the first authentication provider which applies to the request.
  101. * If no application detects appropriate credentials, then NULL is returned.
  102. */
  103. protected function getChallenger(Request $request) {
  104. foreach ($this->authCollector->getSortedProviders() as $provider_id => $provider) {
  105. if (($provider instanceof AuthenticationProviderChallengeInterface) && !$provider->applies($request) && $this->applyFilter($request, FALSE, $provider_id)) {
  106. return $provider_id;
  107. }
  108. }
  109. }
  110. /**
  111. * Checks whether a provider is allowed on the given request.
  112. *
  113. * If no filter is registered for the given provider id, the default filter
  114. * is applied.
  115. *
  116. * @param \Symfony\Component\HttpFoundation\Request $request
  117. * The incoming request.
  118. * @param bool $authenticated
  119. * Whether or not the request is authenticated.
  120. * @param string $provider_id
  121. * The id of the authentication provider to check access for.
  122. *
  123. * @return bool
  124. * TRUE if provider is allowed, FALSE otherwise.
  125. */
  126. protected function applyFilter(Request $request, $authenticated, $provider_id) {
  127. $provider = $this->authCollector->getProvider($provider_id);
  128. if ($provider && ($provider instanceof AuthenticationProviderFilterInterface)) {
  129. $result = $provider->appliesToRoutedRequest($request, $authenticated);
  130. }
  131. else {
  132. $result = $this->defaultFilter($request, $provider_id);
  133. }
  134. return $result;
  135. }
  136. /**
  137. * Default implementation of the provider filter.
  138. *
  139. * Checks whether a provider is allowed as per the _auth option on a route. If
  140. * the option is not set or if the request did not match any route, only
  141. * providers from the global provider set are allowed.
  142. *
  143. * If no filter is registered for the given provider id, the default filter
  144. * is applied.
  145. *
  146. * @param \Symfony\Component\HttpFoundation\Request $request
  147. * The incoming request.
  148. * @param string $provider_id
  149. * The id of the authentication provider to check access for.
  150. *
  151. * @return bool
  152. * TRUE if provider is allowed, FALSE otherwise.
  153. */
  154. protected function defaultFilter(Request $request, $provider_id) {
  155. $route = RouteMatch::createFromRequest($request)->getRouteObject();
  156. $has_auth_option = isset($route) && $route->hasOption('_auth');
  157. if ($has_auth_option) {
  158. return in_array($provider_id, $route->getOption('_auth'));
  159. }
  160. else {
  161. return $this->authCollector->isGlobal($provider_id);
  162. }
  163. }
  164. }