Last active
June 9, 2017 01:54
-
-
Save clrockwell/b17a83d61972ee403c1dccaf68af1ea5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace Drupal\require_login\EventSubscriber; | |
| use Drupal\Component\Serialization\Json; | |
| use Drupal\Core\Config\ConfigFactory; | |
| use Drupal\Core\Path\PathValidator; | |
| use Drupal\Core\Routing\CurrentRouteMatch; | |
| use Drupal\Core\Session\AccountInterface; | |
| use Drupal\Core\Url; | |
| use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; | |
| use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; | |
| use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | |
| use Symfony\Component\HttpKernel\KernelEvents; | |
| use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |
| use Symfony\Component\HttpKernel\Event\GetResponseEvent; | |
| use Symfony\Component\HttpFoundation\RedirectResponse; | |
| use Drupal\Component\Utility\Xss; | |
| /** | |
| * Subscribe to kernal request event to check authentication. | |
| */ | |
| class RequireLoginSubscriber implements EventSubscriberInterface { | |
| protected $configFactory; | |
| protected $lang; | |
| protected $path; | |
| protected $aliased_path; | |
| protected $config; | |
| protected $auth_path; | |
| protected $pathValidator; | |
| protected $account; | |
| protected $routeMatch; | |
| public function __construct( | |
| ConfigFactory $configFactory, | |
| PathValidator $pathValidator, | |
| AccountInterface $account, | |
| CurrentRouteMatch $routeMatch | |
| ) { | |
| $this->routeMatch = $routeMatch; | |
| $this->configFactory = $configFactory; | |
| $this->pathValidator = $pathValidator; | |
| $this->account = $account; | |
| $this->lang = \Drupal::languageManager()->getCurrentLanguage()->getId(); | |
| $this->path = \Drupal::service('path.current')->getPath(); | |
| $this->aliased_path = trim(\Drupal::service('path.alias_manager')->getAliasByPath($this->path, $this->lang)); | |
| $this->auth_path = Xss::filterAdmin($this->configFactory->get('require_login.config')->get('auth_path')); | |
| } | |
| /** | |
| * Checks whether redirect should be handled by KernelEvents::REQUEST subscriber | |
| * | |
| * @return bool | |
| * Returns TRUE if user is authenticated and FALSE otherwise. | |
| */ | |
| public function pathIsExcluded() { | |
| // This is not a path the user has access to, let the Exception Subscriber deal with it. | |
| if (!$this->pathValidator->isValid($this->path)) { | |
| return TRUE; | |
| } | |
| if ($this->isDefaultExcluded()) { | |
| return TRUE; | |
| } | |
| if ($this->isAdminExcluded()) { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| * Check current path against admin configurable exclusion paths, including | |
| * a custom login path, if defined. | |
| * | |
| * @return bool TRUE if page is excluded, FALSE if not | |
| */ | |
| public function isAdminExcluded() { | |
| $page_settings = $this->configFactory->get('system.site')->get('page'); | |
| $exclude_paths = explode(PHP_EOL, $this->configFactory->get('require_login.config')->get('excluded_paths')); | |
| // If alternate login path is defined, add to exclude. | |
| if ($this->auth_path) { | |
| $exclude_paths[] = $this->auth_path; | |
| } | |
| foreach ($exclude_paths as $key => $exclude_path) { | |
| if ($exclude_path == '<front>') { | |
| $front_path = \Drupal::service('path.alias_manager')->getAliasByPath($page_settings['front'], $this->lang); | |
| $exclude_paths[$key] = '/' . trim($front_path, '/ '); | |
| } | |
| } | |
| if (\Drupal::service('path.matcher')->matchPath($this->aliased_path, implode(PHP_EOL, $exclude_paths))) { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| * Check current route against some system defined routes. | |
| * | |
| * @return bool TRUE if page is excluded, FALSE if not | |
| */ | |
| public function isDefaultExcluded() { | |
| // Various checks to determine exceptions for current page. Returns TRUE | |
| // when at least one check has evaluated as TRUE. | |
| $checks[] = function_exists('drupal_is_cli') && drupal_is_cli(); | |
| $route_name = $this->routeMatch->getRouteName(); | |
| if (isset($route_name)) { | |
| $route_checks = [ | |
| ($route_name == 'system.cron'), | |
| // Update. | |
| ($route_name == 'system.db_update'), | |
| // Timezone. | |
| ($route_name == 'system.timezone'), | |
| // User Pages. | |
| ($route_name == 'user.login' || $route_name == 'user.register' || $route_name == 'user.pass'), | |
| // API | |
| ($route_name == 'user.login.http'), | |
| // Twilio | |
| ($route_name == 'realty_beacon_twilio.twilio_incoming_sms_receiveSms'), | |
| // Twilio Voice | |
| ($route_name == 'realty_beacon_twilio.twilio_incoming_voice_controller_receiveVoiceCall'), | |
| ]; | |
| $checks = array_merge($checks, $route_checks); | |
| } | |
| foreach ($checks as $check) { | |
| if ($check) { | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| * Get a user defined login path, or the system route. | |
| * | |
| * @return string path to a login page | |
| */ | |
| public function getAuthenticationPath() { | |
| $path = $this->auth_path ? $this->auth_path : Url::fromRoute('user.login')->toString(); | |
| return $path . '?destination=' . $this->path; | |
| } | |
| /** | |
| * If a user is not logged in and hits a 404 or 403, redirect them to | |
| * the login page. | |
| * | |
| * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event | |
| */ | |
| public function handleRequestException(GetResponseEvent $event) { | |
| // For now, only deal with Not Found and Access Denied | |
| $exception = $event->getException(); | |
| if (!($exception instanceof AccessDeniedHttpException) && !($exception instanceof NotFoundHttpException)) { | |
| return; | |
| } | |
| $format = $event->getRequest()->get('_format'); | |
| if ($format == 'json') { | |
| // API Request | |
| $access_denied = Json::encode([ | |
| 'error' => 'access denied', | |
| 'error_code' => 403, | |
| 'message' => 'Access denied for authentication method, please revalidate your user', | |
| ]); | |
| throw new AccessDeniedHttpException($access_denied); | |
| } | |
| $this->performRedirect($event); | |
| return; | |
| } | |
| /** | |
| * Set a message and redirect to login page. | |
| * | |
| * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event | |
| */ | |
| public function performRedirect(GetResponseEvent $event) { | |
| $message = Xss::filterAdmin($this->configFactory->get('require_login.config')->get('deny_message')); | |
| if (!empty($message)) { | |
| drupal_set_message($message, 'warning'); | |
| } | |
| // Prepare authentication redirect path. | |
| $redirect = $this->getAuthenticationPath(); | |
| $event->setResponse((new RedirectResponse($redirect))->send()); | |
| } | |
| /** | |
| * Passes off GetResponseEvent to appropriate method only after ensuring | |
| * user is not already logged in. | |
| * | |
| * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event | |
| * @return bool | |
| */ | |
| public function requireLoginDelegateEventDuty(GetResponseEvent $event) { | |
| // If the account isn't anonymous there is nothing else to do here. | |
| if (!$this->account->isAnonymous()) { | |
| return TRUE; | |
| } | |
| if ($event instanceof GetResponseForExceptionEvent) { | |
| $this->handleRequestException($event); | |
| } | |
| // If these are pages that should be ignored there is nothing else to do here. | |
| if ($this->pathIsExcluded()) { | |
| return TRUE; | |
| } | |
| if ($event instanceof GetResponseEvent) { | |
| $this->performRedirect($event); | |
| } | |
| return TRUE; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public static function getSubscribedEvents() { | |
| $events[KernelEvents::REQUEST][] = ['requireLoginDelegateEventDuty']; | |
| $events[KernelEvents::EXCEPTION][] = ['requireLoginDelegateEventDuty']; | |
| return $events; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment