diff --git a/src/Drupal/DrupalExtension/Context/DrupalContext.php b/src/Drupal/DrupalExtension/Context/DrupalContext.php
index c48dd51..302fa96 100644
--- a/src/Drupal/DrupalExtension/Context/DrupalContext.php
+++ b/src/Drupal/DrupalExtension/Context/DrupalContext.php
@@ -204,34 +204,118 @@ class DrupalContext extends MinkContext implements DrupalAwareInterface {
   /**
    * Helper function to login the current user.
    */
-  public function login() {
-    // Check if logged in.
-    if ($this->loggedIn()) {
-      $this->logout();
+  public function userLogin() {
+    if (empty($this->user)) {
+      throw new Exception('User must be set before userLogin.');
     }
 
-    if (!$this->user) {
-      throw new \Exception('Tried to login without a user.');
+    $user = $this->whoami();
+    if (strtolower($user) == strtolower($this->user->name)) {
+      // Already logged in.
+      return;
     }
 
+    $page_element = $this->getSession()->getPage();
+    if (empty($page_element)) {
+      throw new Exception('Page not found.');
+    }
+    $user_account_text = $this->getDrupalText('user_account');
+    if ($user != $user_account_text) {
+      // Logout.
+      $this->getSession()->visit($this->locatePath('/logout'));
+    }
+
+    // Go to the user page.
     $this->getSession()->visit($this->locatePath('/user'));
-    $element = $this->getSession()->getPage();
-    $element->fillField($this->getDrupalText('username_field'), $this->user->name);
-    $element->fillField($this->getDrupalText('password_field'), $this->user->pass);
-    $submit = $element->findButton($this->getDrupalText('log_in'));
-    if (empty($submit)) {
-      throw new \Exception('No submit button at ' . $this->getSession()->getCurrentUrl());
+    // Get the page title.
+    $title_element = $page_element->findByID('page-title');
+    if (empty($title_element)) {
+      throw new Exception ('No page title found on "' . $this->getSession()->getCurrentUrl() . '".');
     }
 
-    // Log in.
-    $submit->click();
+    if ($title_element->getText() == $user_account_text) {
+      // If I see this, I'm not logged in at all so log in.
+      $this->login();
+      // Check that the login was successful.
+      $user = $this->whoami();
+      if (strtolower($user) == strtolower($this->user->name)) {
+        // Successfully logged in.
+        return;
+      }
+      throw new Exception('Not logged in.');
+    }
+    throw new Exception('Failed to reach the login page.');
+  }
 
-    if (!$this->loggedIn()) {
-      throw new \Exception("Failed to log in as user \"{$this->user->name}\" with role \"{$this->user->role}\".");
+  /**
+   * Helper function to fetch user passwords stored in behat.local.yml.
+   *
+   * @param string $type
+   *   The user type, e.g. drupal or git.
+   *
+   * @param string $name
+   *   The role to fetch the password for.
+   *
+   * @return string
+   *   The matching username/password or FALSE on error.
+   */
+  public function fetchUserPassword($type, $name) {
+    $property_name = $type . '_users';
+    try {
+      $property = $this->$property_name;
+      return $property[$name];
+    }
+    catch (Exception $e) {
+      throw new Exception("Non-existant user/password for $property_name:$name please check behat.local.yml.");
     }
   }
 
   /**
+   * Private function for the whoami step.
+   *
+   * This method is called within the context of a "Then"
+   * and as such, it should not do anything. However,
+   * standard Drupal offers no way to determine who the
+   * current user is, without going to the /user page.
+   *
+   * The solution to this, is for any site wanting tests
+   * that don't cause extra load, to write the current
+   * user name into every page, and to override
+   * DrupalContext::whoami() to return that page.
+   */
+  public function whoami() {
+    $page_element = $this->getSession()->getPage();
+    // Go to the user page.
+    $this->getSession()->visit($this->locatePath('/user'));
+    $title_element = $page_element->findByID('page-title');
+    if ($title_element) {
+      $page_title = $title_element->getText();
+      if ($page_title) {
+        return $page_title;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * Overrideable function for customizable login steps.
+   *
+   * This is generic enough and configurable enough for most sites.
+   * But it is also overrideable for those cases where the login page
+   * requires a bit more clicking.
+   */
+  public function login() {
+    $page_element = $this->getSession()->getPage();
+    $page_element->fillField($this->getDrupalText('username_field'), $this->user->name);
+    $page_element->fillField($this->getDrupalText('password_field'), $this->user->pass);
+    $submit = $page_element->findButton($this->getDrupalText('log_in'));
+    if (!$submit) {
+      throw new Exception('No submit button on "' . $this->getSession()->getCurrentUrl() . '".');
+    }
+    $submit->click();
+  }
+
+  /**
    * Helper function to logout.
    */
   public function logout() {
@@ -242,13 +326,7 @@ class DrupalContext extends MinkContext implements DrupalAwareInterface {
    * Determine if the a user is already logged in.
    */
   public function loggedIn() {
-    $session = $this->getSession();
-    $session->visit($this->locatePath('/'));
-
-    // If a logout link is found, we are logged in. While not perfect, this is
-    // how Drupal SimpleTests currently work as well.
-    $element = $session->getPage();
-    return $element->findLink($this->getDrupalText('log_out'));
+    return $this->whoami() != $this->getDrupalText('user_account');
   }
 
   /**
@@ -431,22 +509,37 @@ class DrupalContext extends MinkContext implements DrupalAwareInterface {
    */
 
   /**
-   * @Given /^I am an anonymous user$/
+   * @Given /^I am logged out$/
    * @Given /^I am not logged in$/
+   * @Given /^I logout$/
+   * @Given /^I am an [Aa]nonymous user$/
+   * @Given /^I am [Aa]nonymous$/
    */
-  public function iAmAnAnonymousUser() {
-    // Verify the user is logged out.
+  public function iLogout() {
     if ($this->loggedIn()) {
       $this->logout();
     }
   }
 
   /**
+   * @Then /^I should be logged out$/
+   * @Then /^I should be an [Aa]nonymous user$/
+   * @Then /^I should be [Aa]nonymous$/
+   */
+  public function iShouldBeLoggedOut() {
+    $user = $this->whoami();
+    if ($user != $this->getDrupalText('user_account')) {
+      throw new \Exception("Logged in as $user, but should be Anonymous.");
+    }
+  }
+
+  /**
    * Creates and authenticates a user with the given role via Drush.
    *
-   * @Given /^I am logged in as a user with the "(?P<role>[^"]*)" role$/
+   * @Given /^I login as a new "(?P<role>[^"]*)"$/
+   * @Given /^I login as a new "(?P<role>[^"]*)" user$/
    */
-  public function iAmLoggedInWithRole($role) {
+  public function iLoginAsANewUser($role) {
     // Check if a user with this role is already logged in.
     if ($this->user && isset($this->user->role) && $this->user->role == $role) {
       return TRUE;
@@ -460,7 +553,6 @@ class DrupalContext extends MinkContext implements DrupalAwareInterface {
     );
     $user->mail = "{$user->name}@example.com";
 
-
     // Create a new user.
     $this->getDriver()->userCreate($user);
 
@@ -474,12 +566,35 @@ class DrupalContext extends MinkContext implements DrupalAwareInterface {
     }
 
     // Login.
-    $this->login();
+    $this->userLogin();
 
     return TRUE;
   }
 
   /**
+   * Authenticates a role with a user and password from configuration.
+   *
+   * @Given /^I login as an existing "(?P<role>[^"]*)"$/
+   * @Given /^I login as an existing "(?P<role>[^"]*) user"$/
+   */
+  public function iLoginAsAUser($role) {
+    $user_password = $this->fetchUserPassword('drupal', $role);
+    if ($user_password) {
+      $login_info = explode('/', $user_password);
+      if ($login_info && count($login_info) == 2) {
+        $this->user = (object) array(
+          'name' => $login_info[0],
+          'pass' => $login_info[1],
+          'role' => $role,
+        );
+        return $this->userLogin();
+      }
+      throw new \Exception('Role not defined properly in behat.yml, expects username/password.');
+    }
+    throw new \Exception('Role not found in behat.yml.');
+  }
+
+  /**
    * @} End of defgroup "drupal extensions"
    */
 }
diff --git a/src/Drupal/DrupalExtension/Extension.php b/src/Drupal/DrupalExtension/Extension.php
index 8d16efc..f2b91f4 100644
--- a/src/Drupal/DrupalExtension/Extension.php
+++ b/src/Drupal/DrupalExtension/Extension.php
@@ -91,6 +91,9 @@ class Extension implements ExtensionInterface {
             scalarNode('username_field')->
               defaultValue('Username')->
             end()->
+            scalarNode('user_account')->
+              defaultValue('User Account')->
+            end()->
           end()->
         end()->
         // Drupal drivers.
