You are here

LdapSsoBrowserTest.php in LDAP Single Sign On 8.4

File

tests/src/Functional/LdapSsoBrowserTest.php
View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\ldap_sso\Functional;

use Behat\Mink\Session;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\ldap_servers\LdapUserAttributesInterface;
use Drupal\Tests\BrowserTestBase;

/**
 * Test redirection behaviour with SSO enabled.
 *
 * @group ldap_sso
 */
class LdapSsoBrowserTest extends BrowserTestBase {

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'language',
    'user',
    'externalauth',
    'ldap_servers',
    'ldap_servers_dummy',
    'ldap_sso',
    'ldap_authentication',
    'ldap_user',
    'node',
    'path',
    'path_alias',
    'ldap_sso_dummy_ldap',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    parent::setUp();
    $this
      ->drupalCreateContentType([
      'type' => 'page',
    ]);

    // Create a node for front page.
    $node_front = $this
      ->drupalCreateNode();

    // Create a node with a random alias.
    $this->nodeWithAlias = $this
      ->drupalCreateNode([
      'type' => 'page',
      'status' => 1,
      'path' => '/' . $this
        ->randomMachineName(),
    ]);

    // Configure 'node' as front page.
    $this
      ->config('system.site')
      ->set('page.front', '/node/' . $node_front
      ->id())
      ->save();

    /** @var \Drupal\Core\Entity\EntityTypeManager $manager */
    $manager = $this->container
      ->get('entity_type.manager');
    $server = $manager
      ->getStorage('ldap_server')
      ->create([
      'id' => 'test',
      'timeout' => 30,
      'encryption' => 'none',
      'address' => 'example',
      'port' => 963,
      'basedn' => [
        'ou=people,dc=hogwarts,dc=edu',
      ],
      'user_attr' => 'cn',
      'unique_persistent_attr' => 'uid',
      'status' => TRUE,
      'mail_attr' => 'mail',
    ]);
    $server
      ->save();
    $this
      ->config('ldap_authentication.settings')
      ->set('sids', [
      $server
        ->id(),
    ])
      ->set('excludeIfTextInDn', [])
      ->set('allowOnlyIfTextInDn', [])
      ->save();
    $this
      ->config('ldap_user.settings')
      ->set('acctCreation', LdapUserAttributesInterface::ACCOUNT_CREATION_LDAP_BEHAVIOUR)
      ->set('drupalAcctProvisionServer', $server
      ->id())
      ->set('ldapUserSyncMappings', [
      'drupal' => [],
      'ldap' => [],
    ])
      ->set('drupalAcctProvisionTriggers', [
      LdapUserAttributesInterface::PROVISION_DRUPAL_USER_ON_USER_AUTHENTICATION,
      LdapUserAttributesInterface::PROVISION_DRUPAL_USER_ON_USER_ON_MANUAL_CREATION,
      LdapUserAttributesInterface::PROVISION_DRUPAL_USER_ON_USER_UPDATE_CREATE,
    ])
      ->save();
    $this
      ->config('ldap_sso.settings')
      ->set('seamlessLogin', TRUE)
      ->set('ssoExcludedHosts', [])
      ->set('ssoExcludedPaths', [])
      ->set('ssoSplitUserRealm', FALSE)
      ->set('ssoVariable', 'REMOTE_USER')
      ->save();
    $this->container
      ->get('config.factory')
      ->reset();
  }

  /**
   * Test logout no redirection.
   */
  public function testExclusions() : void {

    // Do not redirect on excluded path.
    $url = $this
      ->buildUrl(Url::fromRoute('user.login'), [
      'absolute' => TRUE,
    ]);
    $session = $this
      ->getWithoutRedirect($url);
    self::assertEquals($url, $session
      ->getCurrentUrl());
    self::assertNull($session
      ->getResponseHeader('Location'));
    self::assertEquals(200, $session
      ->getStatusCode());

    // Do not redirect when we have just logged out.
    $url = $this
      ->buildUrl(Url::fromRoute('<front>'), [
      'absolute' => TRUE,
    ]);
    $session = $this
      ->getSession();
    $session
      ->getDriver()
      ->getClient()
      ->followRedirects(FALSE);
    $session
      ->setCookie('sso_stop', 'sso_stop');
    $this
      ->prepareRequest();
    $session
      ->visit($url);
    self::assertEquals($url, $session
      ->getCurrentUrl());
    self::assertEquals('', (string) $session
      ->getResponseHeader('Location'));
    self::assertEquals(200, $session
      ->getStatusCode());
  }

  /**
   * Test seamless disabled.
   */
  public function testSeamlessDisabled() : void {
    $this
      ->config('ldap_sso.settings')
      ->set('seamlessLogin', FALSE)
      ->save();
    $destination = $this
      ->config('system.site')
      ->get('page.front');
    $this
      ->getWithoutRedirect($destination);
    $session = $this
      ->getSession();
    self::assertStringContainsString($destination, $session
      ->getCurrentUrl());
    self::assertEquals(200, $session
      ->getStatusCode());
  }

  /**
   * Test authentication on all valid paths via <front>.
   *
   * Note that this test cannot accurately guarantee the correct behavior of the
   * seamless login. To be definitively correct the webserver would need to
   * contain the REMOTE_USER variable only on /user/login/sso (the most common
   * mixed configuration). The test module ldap_sso_dummy_ldap does so at the
   * application level and a restart of the web request in the application would
   * give a different result than an actual request. Therefore the redirect with
   * cookie is still used, even though it has been a source of errors and loops
   * in the past.
   *
   * @todo This test should additionally test redirect loops prevented by
   *   the stop_sso cookie.
   */
  public function testSeamless() : void {
    $url = $this
      ->buildUrl(Url::fromRoute('<front>'), [
      'absolute' => TRUE,
    ]);
    $this
      ->drupalGet($url);
    self::assertStringContainsString('You have been successfully authenticated', $this
      ->getSession()
      ->getPage()
      ->getContent());

    // @todo Consider improving redirect from "node/1" to "/".
    $destination = $this
      ->config('system.site')
      ->get('page.front');
    self::assertStringContainsString($destination, $this
      ->getSession()
      ->getCurrentUrl());
    self::assertEquals(200, $this
      ->getSession()
      ->getStatusCode());
  }

  /**
   * Same as above with language prefixes.
   */
  public function testNodeLanguagePrefix() : void {
    $fr = ConfigurableLanguage::createFromLangcode('fr');
    $fr
      ->save();
    $this
      ->rebuildContainer();

    /** @var \Drupal\Core\Language\LanguageManager $language_manager */
    $language_manager = $this->container
      ->get('language_manager');
    self::assertCount(2, $language_manager
      ->getLanguages());
    $this->container
      ->get('state')
      ->set('ldap_sso_username_test_override', 'hpotter');
    $url = $this
      ->buildUrl(Url::fromRoute('entity.node.canonical', [
      'node' => 1,
    ], [
      'absolute' => TRUE,
      'language' => $language_manager
        ->getLanguage('fr'),
    ]));
    self::assertStringContainsString('/fr/node/1', $url);
    $this
      ->drupalGet($url);
    self::assertStringContainsString('You have been successfully authenticated', $this
      ->getSession()
      ->getPage()
      ->getContent());
    self::assertEquals($url, $this
      ->getSession()
      ->getCurrentUrl());
    self::assertEquals(200, $this
      ->getSession()
      ->getStatusCode());
  }

  /**
   * GET Request without redirect.
   *
   * @param string $url
   *   URL.
   *
   * @return \Behat\Mink\Session
   *   Session.
   */
  private function getWithoutRedirect(string $url) : Session {
    $session = $this
      ->getSession();
    $session
      ->getDriver()
      ->getClient()
      ->followRedirects(FALSE);
    $this
      ->prepareRequest();
    $session
      ->visit($url);
    return $session;
  }

}

Classes

Namesort descending Description
LdapSsoBrowserTest Test redirection behaviour with SSO enabled.