diff --git commit_restrictions/commit_restrictions.module commit_restrictions/commit_restrictions.module
index 7fe66db..2fa39de 100644
--- commit_restrictions/commit_restrictions.module
+++ commit_restrictions/commit_restrictions.module
@@ -9,86 +9,98 @@
  */
 
 /**
- * Implementation of hook_form_alter(): Add commit restriction settings
- * to the add/edit repository form of the Version Control API module.
+ * Implementation of hook_form_FORM_ID_alter().
  */
-function commit_restrictions_form_alter(&$form, &$form_state, $form_id) {
-  if ($form['#id'] == 'versioncontrol-repository-form') {
-    $backends = versioncontrol_get_backends();
-    $backend_capabilities = $backends[$form['#vcs']]->capabilities;
-    $restrictions = array();
-
-    if (isset($form['#repository']) && !empty($form['#repository']['data']['commit_restrictions'])) {
-      $restrictions = $form['#repository']['data']['commit_restrictions'];
-    }
+function commit_restrictions_form_versioncontrol_repository_form_alter(&$form, &$form_state) {
+  // Add commit restriction settings to the add/edit repository form
 
-    if (in_array(VERSIONCONTROL_CAPABILITY_COMMIT_RESTRICTIONS, $backend_capabilities)) {
-      $form['commit_restrictions']['allowed_paths'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Freely accessible paths'),
-        '#description' => t('A space-separated list of PHP regular expressions for directories or files that will always be granted commit access to everyone, no matter what other commit restrictions are imposed. Example: "@.*\.(po|pot)$@ @^/contributions/(docs|sandbox|tricks)/@"'),
-        '#default_value' => isset($restrictions['allowed_paths'])
-          ? implode(' ', $restrictions['allowed_paths'])
-          : '',
-        '#size' => 60,
-        '#weight' => 10,
-      );
-      $form['commit_restrictions']['deny_undefined_paths'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Deny access to all other paths'),
-        '#description' => t('If this is enabled, no paths other than the ones given above will be granted commit access, except if there is an exception that specifically allows the commit to happen.'),
-        '#default_value' => isset($restrictions['deny_undefined_paths'])
-          ? FALSE
-          : $restrictions['deny_undefined_paths'],
-        '#weight' => 11,
-      );
-      $form['commit_restrictions']['forbidden_paths'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Forbidden paths'),
-        '#description' => t('A space-separated list of PHP regular expressions for directories or files that will be denied access to everyone, except if there is an exception that specifically allows the commit to happen. Example: "@^/contributions/profiles.*(?&lt;!\.profile|\.txt)$@ @^.*\.(gz|tgz|tar|zip)$@"'),
-        '#default_value' => isset($restrictions['forbidden_paths'])
-          ? implode(' ', $restrictions['forbidden_paths'])
-          : '',
-        '#size' => 60,
-        '#weight' => 12,
-      );
-    }
-    if (in_array(VERSIONCONTROL_CAPABILITY_BRANCH_TAG_RESTRICTIONS, $backend_capabilities)) {
-      $form['branch_tag_restrictions'] = array(
-        '#type' => 'fieldset',
-        '#title' => t('Branch and tag restrictions'),
-        '#collapsible' => TRUE,
-        '#collapsed' => TRUE,
-        '#weight' => 7,
-      );
-      $form['branch_tag_restrictions']['valid_branch_tag_paths'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Allowed paths for branches and tags'),
-        '#description' => t('A space-separated list of PHP regular expressions for directories or files where it will be possible to create branches and tags. If empty, branches and tags may be created anywhere in the repository. Example: "@^(/[^/]+)?/(modules|themes|theme-engines|docs|translations)/@"'),
-        '#default_value' => isset($restrictions['valid_branch_tag_paths'])
-          ? implode(' ', $restrictions['valid_branch_tag_paths'])
-          : '',
-        '#size' => 60,
-      );
-      $form['branch_tag_restrictions']['valid_branches'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Valid branches'),
-        '#description' => t('A space-separated list of PHP regular expressions for allowed branch names. If empty, all branch names will be allowed. Example: "@^HEAD$@ @^DRUPAL-5(--[2-9])?$@ @^DRUPAL-6--[1-9]$@"'),
-        '#default_value' => isset($restrictions['valid_branches'])
-          ? implode(' ', $restrictions['valid_branches'])
-          : '',
-        '#size' => 60,
-      );
-      $form['branch_tag_restrictions']['valid_tags'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Valid tags'),
-        '#description' => t('A space-separated list of PHP regular expressions for allowed tag names. If empty, all tag names will be allowed. Example: "@^DRUPAL-[56]--(\d+)-(\d+)(-[A-Z0-9]+)?$@"'),
-        '#default_value' => isset($restrictions['valid_tags'])
-          ? implode(' ', $restrictions['valid_tags'])
-          : '',
-        '#size' => 60,
-      );
-    }
+  $backends = versioncontrol_get_backends();
+  $backend_capabilities = $backends[$form['#vcs']]->capabilities;
+  $restrictions = array();
+
+  if (isset($form['#repository']) && !empty($form['#repository']->data['commit_restrictions'])) {
+    $restrictions = $form['#repository']->data['commit_restrictions'];
+  }
+
+  $backend_can_restrict_commits = in_array(VERSIONCONTROL_CAPABILITY_COMMIT_RESTRICTIONS, $backend_capabilities);
+  $backend_can_restrict_tags    = in_array(VERSIONCONTROL_CAPABILITY_BRANCH_TAG_RESTRICTIONS, $backend_capabilities);
+
+  if ($backend_can_restrict_commits || $backend_can_restrict_tags) {
+    $form['commit_restrictions'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Commit restrictions'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#weight' => 10,
+    );
+  }
+
+  if ($backend_can_restrict_commits) {
+    $form['commit_restrictions']['allowed_paths'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Freely accessible paths'),
+      '#description' => t('A space-separated list of PHP regular expressions for directories or files that will always be granted commit access to everyone, no matter what other commit restrictions are imposed. Example: "@.*\.(po|pot)$@ @^/contributions/(docs|sandbox|tricks)/@"'),
+      '#default_value' => isset($restrictions['allowed_paths'])
+      ? implode(' ', $restrictions['allowed_paths'])
+      : '',
+      '#size' => 60,
+      '#weight' => 10,
+    );
+    $form['commit_restrictions']['deny_undefined_paths'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Deny access to all other paths'),
+      '#description' => t('If this is enabled, no paths other than the ones given above will be granted commit access, except if there is an exception that specifically allows the commit to happen.'),
+      '#default_value' => isset($restrictions['deny_undefined_paths'])
+      ? FALSE
+      : $restrictions['deny_undefined_paths'],
+      '#weight' => 11,
+    );
+    $form['commit_restrictions']['forbidden_paths'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Forbidden paths'),
+      '#description' => t('A space-separated list of PHP regular expressions for directories or files that will be denied access to everyone, except if there is an exception that specifically allows the commit to happen. Example: "@^/contributions/profiles.*(?&lt;!\.profile|\.txt)$@ @^.*\.(gz|tgz|tar|zip)$@"'),
+      '#default_value' => isset($restrictions['forbidden_paths'])
+      ? implode(' ', $restrictions['forbidden_paths'])
+      : '',
+      '#size' => 60,
+      '#weight' => 12,
+    );
+  }
+  if ($backend_can_restrict_tags) {
+    $form['branch_tag_restrictions'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Branch and tag restrictions'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#weight' => 7,
+    );
+    $form['branch_tag_restrictions']['valid_branch_tag_paths'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Allowed paths for branches and tags'),
+      '#description' => t('A space-separated list of PHP regular expressions for directories or files where it will be possible to create branches and tags. If empty, branches and tags may be created anywhere in the repository. Example: "@^(/[^/]+)?/(modules|themes|theme-engines|docs|translations)/@"'),
+      '#default_value' => isset($restrictions['valid_branch_tag_paths'])
+      ? implode(' ', $restrictions['valid_branch_tag_paths'])
+      : '',
+      '#size' => 60,
+    );
+    $form['branch_tag_restrictions']['valid_branches'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Valid branches'),
+      '#description' => t('A space-separated list of PHP regular expressions for allowed branch names. If empty, all branch names will be allowed. Example: "@^HEAD$@ @^DRUPAL-5(--[2-9])?$@ @^DRUPAL-6--[1-9]$@"'),
+      '#default_value' => isset($restrictions['valid_branches'])
+      ? implode(' ', $restrictions['valid_branches'])
+      : '',
+      '#size' => 60,
+    );
+    $form['branch_tag_restrictions']['valid_tags'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Valid tags'),
+      '#description' => t('A space-separated list of PHP regular expressions for allowed tag names. If empty, all tag names will be allowed. Example: "@^DRUPAL-[56]--(\d+)-(\d+)(-[A-Z0-9]+)?$@"'),
+      '#default_value' => isset($restrictions['valid_tags'])
+      ? implode(' ', $restrictions['valid_tags'])
+      : '',
+      '#size' => 60,
+    );
   }
 }
 
diff --git includes/VersioncontrolOperation.php includes/VersioncontrolOperation.php
index 35b8788..3b05f04 100644
--- includes/VersioncontrolOperation.php
+++ includes/VersioncontrolOperation.php
@@ -121,12 +121,6 @@ abstract class VersioncontrolOperation extends VersioncontrolEntity {
     'delete' => array('nested' => TRUE),
   );
 
-  /**
-   * Error messages used mainly to get descriptions of errors at
-   * hasWriteAccess().
-   */
-  private static $error_messages = array();
-
   public function loadItemRevisions($ids = array(), $conditions = array(), $options = array()) {
     $conditions['repo_id'] = $this->repo_id;
     $conditions['vc_op_id'] = $this->vc_op_id;
@@ -300,152 +294,6 @@ abstract class VersioncontrolOperation extends VersioncontrolEntity {
   }
 
   /**
-   * Retrieve the list of access errors.
-   *
-   * If versioncontrol_has_commit_access(), versioncontrol_has_branch_access()
-   * or versioncontrol_has_tag_access() returned FALSE, you can use this function
-   * to retrieve the list of error messages from the various access checks.
-   * The error messages do not include trailing linebreaks, it is expected that
-   * those are inserted by the caller.
-   */
-  private function getAccessErrors() {
-    return self::$error_messages;
-  }
-
-  /**
-   * Set the list of access errors.
-   */
-  private function setAccessErrors($new_messages) {
-    if (isset($new_messages)) {
-      self::$error_messages = $new_messages;
-    }
-  }
-
-  /**
-   * Determine if a commit, branch or tag operation may be executed or not.
-   * Call this function inside a pre-commit hook.
-   *
-   * @param $operation
-   *   A single operation array like the ones returned by
-   *   versioncontrol_get_operations(), but leaving out on a few details that
-   *   will instead be determined by this function. This array describes
-   *   the operation that is about to happen. Here's the allowed elements:
-   *
-   *   - 'type': The type of the operation - one of the
-   *        VERSIONCONTROL_OPERATION_{COMMIT,BRANCH,TAG} constants.
-   *   - 'repository': The repository where this operation occurs,
-   *        given as a structured array, like the return value
-   *        of versioncontrol_get_repository().
-   *        You can either pass this or 'repo_id'.
-   *   - 'repo_id': The repository where this operation occurs, given as a simple
-   *        integer id. You can either pass this or 'repository'.
-   *   - 'uid': The Drupal user id of the committer. Passing this is optional -
-   *        if it isn't set, this function will determine the uid.
-   *   - 'username': The system specific VCS username of the committer.
-   *   - 'message': The log message for the commit, tag or branch operation.
-   *        If a version control system doesn't support messages for the current
-   *        operation type, this element must not be set. Operations with
-   *        log messages that are set but empty will be denied access.
-   *
-   *   - 'labels': An array of branches or tags that will be affected by this
-   *        operation. Branch and tag operations are known to only affect one
-   *        branch or tag, so for these there will be only one element (with 0
-   *        as key) in 'labels'. Commits might affect any number of branches,
-   *        including none. Commits that emulate branches and/or tags (like
-   *        in Subversion, where they're not a native concept) can also include
-   *        add/delete/move operations for labels, as detailed below.
-   *        Mind that the main development branch - e.g. 'HEAD', 'trunk'
-   *        or 'master' - is also considered a branch. Each element in 'labels'
-   *        is a VersioncontrolLabel(VersioncontrolBranch VersioncontrolTag)
-   *
-   * @param $item_revisions
-   *   A structured array containing the exact details of what is about to happen
-   *   to each item in this commit. The structure of this array is the same as
-   *   the return value of VersioncontrolOperation::getItems() - that is,
-   *   elements for 'type', 'path', 'revision', 'action', 'source_items' and
-   *   'replaced_item' - but doesn't include the 'item_revision_id' element as
-   *   there's no relation to the database yet.
-   *
-   *   The 'action', 'source_items', 'replaced_item' and 'revision' elements
-   *   of each item are optional and may be left unset.
-   *
-   * @return
-   *   TRUE if the operation may happen, or FALSE if not.
-   *   If FALSE is returned, you can retrieve the concerning error messages
-   *   by calling versioncontrol_get_access_errors().
-   */
-  protected function hasWriteAccess($operation, $item_revisions) {
-
-    // If we can't determine this operation's repository,
-    // we can't really allow the operation in the first place.
-    if (!isset($operation['repository'])) {
-      switch ($operation['type']) {
-      case VERSIONCONTROL_OPERATION_COMMIT:
-        $type = t('commit');
-        break;
-      case VERSIONCONTROL_OPERATION_BRANCH:
-        $type = t('branch');
-        break;
-      case VERSIONCONTROL_OPERATION_TAG:
-        $type = t('tag');
-        break;
-      }
-      $this->setAccessErrors(array(t(
-        '** ERROR: Version Control API cannot determine a repository
-        ** for the !commit-branch-or-tag information given by the VCS backend.',
-        array('!commit-branch-or-tag' => $type)
-      )));
-      return FALSE;
-    }
-
-    // If the user doesn't have commit access at all, we can't allow this as well.
-    $repo_data = $operation->repository->data['versioncontrol'];
-
-    if (!$repo_data['allow_unauthorized_access']) {
-
-      if (!$operation->repository->isAccountAuthorized($operation->uid)) {
-        $this->setAccessErrors(array(t(
-          '** ERROR: !user does not have commit access to this repository.',
-          array('!user' => $operation->committer)
-        )));
-        return FALSE;
-      }
-    }
-
-    // Don't let people do empty log messages, that's as evil as it gets.
-    if (isset($operation['message']) && empty($operation['message'])) {
-      $this->setAccessErrors(array(
-        t('** ERROR: You have to provide a log message.'),
-      ));
-      return FALSE;
-    }
-
-    // Also see if other modules have any objections.
-    $error_messages = array();
-
-    foreach (module_implements('versioncontrol_write_access') as $module) {
-      $function = $module .'_versioncontrol_write_access';
-
-      // If at least one hook_versioncontrol_write_access returns TRUE,
-      // the commit goes through. (This is for admin or sandbox exceptions.)
-      $outcome = $function($operation, $item_revisions);
-      if ($outcome === TRUE) {
-        return TRUE;
-      }
-      else { // if !TRUE, $outcome is required to be an array with error messages
-        $error_messages = array_merge($error_messages, $outcome);
-      }
-    }
-
-    // Let the operation fail if there's more than zero error messages.
-    if (!empty($error_messages)) {
-    $this->setAccessErrors($error_messages);
-      return FALSE;
-    }
-    return TRUE;
-  }
-
-  /**
    * Convinience method to call backend analogue one.
    *
    * @param $format
diff --git includes/VersioncontrolRepository.php includes/VersioncontrolRepository.php
index 5193943..a4dca6a 100644
--- includes/VersioncontrolRepository.php
+++ includes/VersioncontrolRepository.php
@@ -96,10 +96,10 @@ abstract class VersioncontrolRepository implements VersioncontrolEntityInterface
   /**
    * An array describing the plugins that will be used for this repository.
    *
-   * The current plugin types(array keys) are:
-   * - author_mapper
-   * - committer_mapper
-   * - auth_handler
+   * The current plugin types(array keys and expected values) are:
+   * - author_mapper => (string) name
+   * - committer_mapper => (string) name
+   * - auth_handlers => (array) list of names as strings
    *
    * @var array
    */
@@ -118,6 +118,12 @@ abstract class VersioncontrolRepository implements VersioncontrolEntityInterface
     'delete' => array('nested' => TRUE),
   );
 
+  /**
+   * Store any errors messages about authorization as the output of
+   * VersioncontrolAuthHandlerInterface::getErrorMessages().
+   */
+  protected $authErrorMessages = array();
+
   public function __construct($backend = NULL) {
     if ($backend instanceof VersioncontrolBackend) {
       $this->backend = $backend;
@@ -407,17 +413,33 @@ abstract class VersioncontrolRepository implements VersioncontrolEntityInterface
     return new $class_name();
   }
 
-  public function getAuthHandler() {
-    if (!isset($this->pluginInstances['auth_handler'])) {
+  public function getAuthHandlers() {
+    ctools_include('plugins');
+
+    if (!isset($this->pluginInstances['auth_handlers'])) {
       // If no plugin is set, use the free-for-all plugin
-      if (empty($this->plugins['auth_handler'])) {
+      if (empty($this->plugins['auth_handlers'])) {
         // FIXME temporarily writing to a db-recorded field like this is very hacky
-        $this->plugins['auth_handler'] = 'ffa';
+        $this->plugins['auth_handlers'] = array('ffa');
+      }
+      $plugin_instances = array();
+      foreach ($this->plugins['auth_handlers'] as $plugin_name) {
+        $plugin = ctools_get_plugins('versioncontrol', 'vcs_auth', $plugin_name);
+        if (!is_array($plugin)) {
+          throw new Exception("Attempted to get a plugin of type 'vcs_auth' named '$plugin_name', but no such plugin could be found.", E_WARNING);
+          return FALSE;
+        }
+        $class_name = ctools_plugin_get_class($plugin, 'handler');
+        if (!class_exists($class_name)) {
+          throw new Exception("Plugin '$plugin_name' of type 'vcs_auth' does not contain a valid class name in handler slot 'handler'", E_WARNING);
+          return FALSE;
+        }
+        $plugin_instances[$plugin_name] = new $class_name;
+        $plugin_instances[$plugin_name]->setRepository($this);
       }
-      $this->pluginInstances['auth_handler'] = $this->getPluginClass('auth_handler', 'vcs_auth', 'handler');
-      $this->pluginInstances['auth_handler']->setRepository($this);
+      $this->pluginInstances['auth_handlers'] = $plugin_instances;
     }
-    return $this->pluginInstances['auth_handler'];
+    return $this->pluginInstances['auth_handlers'];
   }
 
   public function getAuthorMapper() {
@@ -447,6 +469,79 @@ abstract class VersioncontrolRepository implements VersioncontrolEntityInterface
     return $this->pluginInstances['committer_mapper'];
   }
 
+  public function getAuthErrorMessages() {
+    return $this->authErrorMessages;
+  }
+
+  public function authAccess($uid) {
+    foreach ($this->getAuthHandlers() as $auth_handler) {
+      if (!$auth_handler->authAccess($uid)) {
+        $this->authErrorMessages = $auth_handler->getErrorMessages();
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  public function authBranchCreate($uid, VersioncontrolBranch $branch) {
+    foreach ($this->getAuthHandlers() as $auth_handler) {
+      if (!$auth_handler->authBranchCreate($uid, $branch)) {
+        $this->authErrorMessages = $auth_handler->getErrorMessages();
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  public function authBranchDelete($uid, VersioncontrolBranch $branch) {
+    foreach ($this->getAuthHandlers() as $auth_handler) {
+      if (!$auth_handler->authBranchDelete($uid, $branch)) {
+        $this->authErrorMessages = $auth_handler->getErrorMessages();
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  public function authBranchUpdate($uid, VersioncontrolBranch $branch) {
+    foreach ($this->getAuthHandlers() as $auth_handler) {
+      if (!$auth_handler->authBranchUpdate($uid, $branch)) {
+        $this->authErrorMessages = $auth_handler->getErrorMessages();
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  public function authTagCreate($uid, VersioncontrolTag $tag) {
+    foreach ($this->getAuthHandlers() as $auth_handler) {
+      if (!$auth_handler->authTagCreate($uid, $tag)) {
+        $this->authErrorMessages = $auth_handler->getErrorMessages();
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  public function authTagDelete($uid, VersioncontrolTag $tag) {
+    foreach ($this->getAuthHandlers() as $auth_handler) {
+      if (!$auth_handler->authTagDelete($uid, $tag)) {
+        $this->authErrorMessages = $auth_handler->getErrorMessages();
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  public function authTagUpdate($uid, VersioncontrolTag $tag) {
+    foreach ($this->getAuthHandlers() as $auth_handler) {
+      if (!$auth_handler->authTagUpdate($uid, $tag)) {
+        $this->authErrorMessages = $auth_handler->getErrorMessages();
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
 
   //ArrayAccess interface implementation FIXME soooooooo deprecated
   public function offsetExists($offset) {
diff --git includes/interfaces.inc includes/interfaces.inc
index 88b8722..792df68 100644
--- includes/interfaces.inc
+++ includes/interfaces.inc
@@ -226,11 +226,14 @@ interface VersioncontrolAuthHandlerInterface {
    *
    * @param int $uid
    *   The uid of the Drupal user to be checked.
+   * @param VersioncontrolBranch $branch
+   *   The VersioncontrolBranch object representing the branch against which
+   *   authorization checks should be made.
    *
    * @return bool
    *   Boolean indicating access approved (TRUE) or denied (FALSE)
    */
-  public function authBranchCreate($uid);
+  public function authBranchCreate($uid, VersioncontrolBranch $branch);
 
   /**
    * Determine whether the specified user has access to delete the specified
@@ -268,10 +271,14 @@ interface VersioncontrolAuthHandlerInterface {
    *
    * @param int $uid
    *   The uid of the Drupal user to be checked.
+   * @param VersioncontrolTag $tag
+   *   The VersioncontrolTag object representing the tag against which
+   *   authorization checks should be made.
+   *
    * @return bool
    *   Boolean indicating access approved (TRUE) or denied (FALSE)
    */
-  public function authTagCreate($uid);
+  public function authTagCreate($uid, VersioncontrolTag $tag);
 
   /**
    * Determine whether the specified user has access to delete the specified
diff --git includes/plugins/vcs_auth/VersioncontrolAuthHandlerFFA.class.php includes/plugins/vcs_auth/VersioncontrolAuthHandlerFFA.class.php
index 59157fc..fead4ff 100644
--- includes/plugins/vcs_auth/VersioncontrolAuthHandlerFFA.class.php
+++ includes/plugins/vcs_auth/VersioncontrolAuthHandlerFFA.class.php
@@ -7,7 +7,7 @@ class VersioncontrolAuthHandlerFFA implements VersioncontrolAuthHandlerInterface
     return TRUE;
   }
 
-  public function authBranchCreate($uid) {
+  public function authBranchCreate($uid, VersioncontrolBranch $branch) {
     return TRUE;
   }
   public function authBranchDelete($uid, VersioncontrolBranch $branch) {
@@ -16,7 +16,7 @@ class VersioncontrolAuthHandlerFFA implements VersioncontrolAuthHandlerInterface
   public function authBranchUpdate($uid, VersioncontrolBranch $branch) {
     return TRUE;
   }
-  public function authTagCreate($uid) {
+  public function authTagCreate($uid, VersioncontrolTag $tag) {
     return TRUE;
   }
   public function authTagDelete($uid, VersioncontrolTag $tag) {
diff --git includes/plugins/vcs_auth/VersioncontrolAuthHandlerMappedAccounts.class.php includes/plugins/vcs_auth/VersioncontrolAuthHandlerMappedAccounts.class.php
index dd12902..f3dee7e 100644
--- includes/plugins/vcs_auth/VersioncontrolAuthHandlerMappedAccounts.class.php
+++ includes/plugins/vcs_auth/VersioncontrolAuthHandlerMappedAccounts.class.php
@@ -189,7 +189,7 @@ class VersioncontrolAuthHandlerMappedAccounts implements VersioncontrolAuthHandl
     }
   }
 
-  public function authBranchCreate($uid) {
+  public function authBranchCreate($uid, VersioncontrolBranch $branch) {
     $base = $this->baseAuth($uid);
     if ($base == self::DENY) {
       // Zero access, deny.
@@ -222,7 +222,7 @@ class VersioncontrolAuthHandlerMappedAccounts implements VersioncontrolAuthHandl
     }
     return $access;
   }
-  public function authTagCreate($uid) {
+  public function authTagCreate($uid, VersioncontrolTag $tag) {
     $base = $this->baseAuth($uid);
     if ($base == self::DENY) {
       // Zero access, deny.
diff --git includes/plugins/vcs_auth/account.inc includes/plugins/vcs_auth/account.inc
index bb01820..6fbe23e 100644
--- includes/plugins/vcs_auth/account.inc
+++ includes/plugins/vcs_auth/account.inc
@@ -1,7 +1,7 @@
 <?php
 
 $plugin = array(
-  'title' => t('Free For All (unrestricted write access)'),
+  'title' => t('Account (restricted write access)'),
   'handler' => array(
     'class' => 'VersioncontrolAuthHandlerMappedAccounts',
   ),
diff --git tests/VersioncontrolAccountAuthPlugin.test tests/VersioncontrolAccountAuthPlugin.test
index 22ed5ab..1abf911 100644
--- tests/VersioncontrolAccountAuthPlugin.test
+++ tests/VersioncontrolAccountAuthPlugin.test
@@ -37,7 +37,7 @@ class VersioncontrolAccountAuthPlugin extends VersioncontrolTestCase {
 
     $repo_data = array(
       'plugins' => array(
-        'auth_handler' => 'account'
+        'auth_handlers' => array('account')
       ),
     );
 
@@ -107,7 +107,7 @@ class VersioncontrolAccountAuthPlugin extends VersioncontrolTestCase {
   }
 
   public function testMappedAccountsAuthPluginCrud() {
-    foreach ($this->repos as $repo) {
+    foreach ($this->repos as $backend_machine_name => $repo) {
       // Manually instantiate the plugin for the create portion
       $class_name = ctools_plugin_load_class('versioncontrol', 'vcs_auth', 'account', 'handler');
       $authplug = new $class_name();
@@ -121,7 +121,7 @@ class VersioncontrolAccountAuthPlugin extends VersioncontrolTestCase {
 
       // Now load the plugin using the provided method and retrieve the user data,
       // ensure it's what we sent in
-      $db_authplug = $repo->getAuthHandler();
+      $db_authplug = reset($repo->getAuthHandlers());
       $db_data = $db_authplug->getUserData($super_user->uid);
       $at_input = array_diff($super_user_data, $db_data);
       $this->assertTrue(empty($at_input), 'Authentication account database data is included on provided data');
@@ -132,7 +132,7 @@ class VersioncontrolAccountAuthPlugin extends VersioncontrolTestCase {
       $this->assertTrue(empty($at_db), 'Authentication account provided data is included on database data');
 
       // Now try test  logic
-      $authplug = $repo->getAuthHandler();
+      $authplug = reset($repo->getAuthHandlers());
       $branches = $repo->loadBranches(array(
         $this->branches[$repo->repo_id][0]->label_id,
         $this->branches[$repo->repo_id][1]->label_id,
@@ -148,8 +148,10 @@ class VersioncontrolAccountAuthPlugin extends VersioncontrolTestCase {
       // global
       $this->assertTrue($authplug->authAccess($super_user->uid), 'global auth validate correctly');
       // branches
-      $this->assertFalse($authplug->authBranchCreate($super_user->uid), 'branch create validate correctly');
-      $this->assertFalse($authplug->authTagCreate($super_user->uid), 'tag create validate correctly');
+      $test_branch = $this->versioncontrolCreateBranch($backend_machine_name, array(), FALSE);
+      $this->assertFalse($authplug->authBranchCreate($super_user->uid, $test_branch), 'branch create validate correctly');
+      $test_tag = $this->versioncontrolCreateTag($backend_machine_name, array(), FALSE);
+      $this->assertFalse($authplug->authTagCreate($super_user->uid, $test_tag), 'tag create validate correctly');
       $this->assertTrue($authplug->authBranchUpdate($super_user->uid, $this->branches[$repo->repo_id][0]), 'granular branch update validate correctly');
       $this->assertTrue($authplug->authBranchDelete($super_user->uid, $this->branches[$repo->repo_id][0]), 'granular branch delete validate correctly');
       $this->assertTrue($authplug->authBranchUpdate($super_user->uid, $this->branches[$repo->repo_id][1]), 'granular branch update validate correctly');
diff --git tests/VersioncontrolRepositoryUnitTestingTestCase.test tests/VersioncontrolRepositoryUnitTestingTestCase.test
index 23470ae..762fb15 100644
--- tests/VersioncontrolRepositoryUnitTestingTestCase.test
+++ tests/VersioncontrolRepositoryUnitTestingTestCase.test
@@ -39,7 +39,7 @@ class VersioncontrolRepositoryUnitTestingTestCase extends VersioncontrolTestCase
       'updated' => 0,
       'locked' => 0,
       'data' => array(),
-      'plugins' => array('auth_handler' => 'ffa', 'author_mapper' => 'simple_name', 'committer_mapper' => 'simple_mail'),
+      'plugins' => array('auth_handlers' => array('ffa'), 'author_mapper' => 'simple_name', 'committer_mapper' => 'simple_mail'),
     );
     $repo = $this->testBackend->buildEntity('repo', $data);
     $repo->insert();
@@ -88,7 +88,7 @@ class VersioncontrolRepositoryUnitTestingTestCase extends VersioncontrolTestCase
       'updated' => time(),
       //TODO $repo->update_method
       'locked' => TRUE,
-      'plugins' => array('auth_handler' => 'account') + $repo['plugins'],
+      'plugins' => array('auth_handlers' => array('account')) + $repo['plugins'],
     );
 
     $repo->name = $data['name'];
diff --git tests/VersioncontrolTestCase.test tests/VersioncontrolTestCase.test
index 8d409e6..dc59dbf 100644
--- tests/VersioncontrolTestCase.test
+++ tests/VersioncontrolTestCase.test
@@ -132,7 +132,7 @@ abstract class VersioncontrolTestCase extends DrupalWebTestCase {
    * @param string $backend_name
    * @param array  $data
    */
-  public function versioncontrolCreateRepository($backend_name = 'test', $data = array()) {
+  public function versioncontrolCreateRepository($backend_name = 'test', $data = array(), $insert=TRUE) {
     static $i = 0;
     $default_data = array(
       'name' => 'test_repo_' . ++$i,
@@ -146,7 +146,7 @@ abstract class VersioncontrolTestCase extends DrupalWebTestCase {
       'plugins' => array(),
     );
     $default_plugins = array(
-      'auth_handler' => 'ffa',
+      'auth_handlers' => array('ffa'),
       'author_mapper' => 'simple_mail',
       'committer_mapper' => 'simple_mail',
     );
@@ -159,13 +159,15 @@ abstract class VersioncontrolTestCase extends DrupalWebTestCase {
     }
     $backend = $this->backends[$backend_name];
     $repo = $backend->buildEntity('repo', $data);
-    $repo->insert();
-    $this->assertTrue(isset($repo->repo_id) && is_numeric($repo->repo_id), t('VersioncontrolRepository::insert() properly populates a new repository object with an integer repo_id.'));
+    if ($insert) {
+      $repo->insert();
+      $this->assertTrue(isset($repo->repo_id) && is_numeric($repo->repo_id), t('VersioncontrolRepository::insert() properly populates a new repository object with an integer repo_id.'));
+    }
 
     return $repo;
   }
 
-  public function versioncontrolCreateLabel($type, $backend_name = 'test', $data = array()) {
+  public function versioncontrolCreateLabel($type, $backend_name = 'test', $data = array(), $insert=TRUE) {
     $default_data = array(
       'name' => $this->randomName(32),
       'data' => array(),
@@ -180,24 +182,30 @@ abstract class VersioncontrolTestCase extends DrupalWebTestCase {
       }
     }
     $label = $backend->buildEntity($type, $data);
-    $label->insert();
+    if ($insert) {
+      $label->insert();
+    }
 
     return $label;
   }
 
-  public function versioncontrolCreateBranch($backend_name = 'test', $data = array()) {
-    $label = $this->versioncontrolCreateLabel('branch', $backend_name, $data);
-    $this->assertTrue(isset($label->label_id) && is_numeric($label->label_id), t('VersioncontrolBranch::insert() properly populates a new repository object with an integer label_id.'));
+  public function versioncontrolCreateBranch($backend_name = 'test', $data = array(), $insert=TRUE) {
+    $label = $this->versioncontrolCreateLabel('branch', $backend_name, $data, $insert);
+    if ($insert) {
+      $this->assertTrue(isset($label->label_id) && is_numeric($label->label_id), t('VersioncontrolBranch::insert() properly populates a new repository object with an integer label_id.'));
+    }
     return $label;
   }
 
-  public function versioncontrolCreateTag($backend_name = 'test', $data = array()) {
-    $label = $this->versioncontrolCreateLabel('tag', $backend_name, $data);
-    $this->assertTrue(isset($label->label_id) && is_numeric($label->label_id), t('VersioncontrolTag::insert() properly populates a new repository object with an integer label_id.'));
+  public function versioncontrolCreateTag($backend_name = 'test', $data = array(), $insert=TRUE) {
+    $label = $this->versioncontrolCreateLabel('tag', $backend_name, $data, $insert);
+    if ($insert) {
+      $this->assertTrue(isset($label->label_id) && is_numeric($label->label_id), t('VersioncontrolTag::insert() properly populates a new repository object with an integer label_id.'));
+    }
     return $label;
   }
 
-  public function versioncontrolCreateOperation($backend_name = 'test', $data = array()) {
+  public function versioncontrolCreateOperation($backend_name = 'test', $data = array(), $insert=TRUE) {
     static $i = 0;
     $name = $this->randomName(7);
     $default_data = array(
@@ -222,13 +230,15 @@ abstract class VersioncontrolTestCase extends DrupalWebTestCase {
       }
     }
     $operation = $backend->buildEntity('operation', $data);
-    $operation->insert();
-    $this->assertTrue(isset($operation->vc_op_id) && is_numeric($operation->vc_op_id), t('VersioncontrolOperation::insert() properly populates a new repository object with an integer vc_op_id.'));
+    if ($insert) {
+      $operation->insert();
+      $this->assertTrue(isset($operation->vc_op_id) && is_numeric($operation->vc_op_id), t('VersioncontrolOperation::insert() properly populates a new repository object with an integer vc_op_id.'));
+    }
 
     return $operation;
   }
 
-  public function versioncontrolCreateItem($backend_name = 'test', $data = array()) {
+  public function versioncontrolCreateItem($backend_name = 'test', $data = array(), $insert=TRUE) {
     static $i = 0;
     $default_data = array(
       'path' => sprintf('/%s/%s.inc', $this->randomName(4), $this->randomName(4)),
@@ -253,8 +263,10 @@ abstract class VersioncontrolTestCase extends DrupalWebTestCase {
       $data['vc_op_id'] = $operation->vc_op_id;
     }
     $item = $backend->buildEntity('item', $data);
-    $item->insert();
-    $this->assertTrue(isset($item->item_revision_id) && is_numeric($item->item_revision_id), t('VersioncontrolItem::insert() properly populates a new repository object with an integer item_revision_id.'));
+    if ($insert) {
+      $item->insert();
+      $this->assertTrue(isset($item->item_revision_id) && is_numeric($item->item_revision_id), t('VersioncontrolItem::insert() properly populates a new repository object with an integer item_revision_id.'));
+    }
 
     return $item;
   }
diff --git versioncontrol.admin.inc versioncontrol.admin.inc
index 66bb4e7..9087cc8 100644
--- versioncontrol.admin.inc
+++ versioncontrol.admin.inc
@@ -340,6 +340,23 @@ function versioncontrol_admin_repository_edit(&$form_state, $repository, $vcs =
     '#options' => array(0 => '<em>' . t('Use Author mapping plugin') . '</em>') + versioncontrol_user_mapping_methods_get_names(),
   );
 
+  $form['user_authentication'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('User authentication'),
+    '#description' => t('Versioncontrol can authenticate/validate VCS information based on its entities and the user trying to perform the VCS operation. If the authentication is called from the VCS hooks it can prevent inserting undesired data.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#weight' => 5,
+  );
+
+  $form['user_authentication']['authentication_handlers'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Authentication handlers'),
+    '#description' => t('The list of authentication methods tha can be used. If more than one is selected, they will be processed one after the other to get a final answer about the auth question.'),
+    '#default_value' => $repository_exists ? $repository->plugins['auth_handlers'] : array(),
+    '#options' => versioncontrol_auth_handlers_get_names(),
+  );
+
   if ($repository_exists && isset($repository->data['versioncontrol']['registration_message'])) {
     $current_registration_message = $repository->data['versioncontrol']['registration_message'];
   }
@@ -383,22 +400,6 @@ function versioncontrol_admin_repository_edit(&$form_state, $repository, $vcs =
   $backend_capabilities = $backends[$form['#vcs']]->capabilities;
 
   if (in_array(VERSIONCONTROL_CAPABILITY_COMMIT_RESTRICTIONS, $backend_capabilities)) {
-    $form['commit_restrictions'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Commit restrictions'),
-      '#collapsible' => TRUE,
-     '#collapsed' => TRUE,
-      '#weight' => 10,
-    );
-    $form['commit_restrictions']['allow_unauthorized_access'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Allow repository access to unknown or unauthorized committers'),
-      '#description' => 'If this is enabled, users can commit to this repository even if no association of the VCS account to the Drupal user is known (assuming that no other commit restrictions apply). If it is disabled, only known and authorized users may commit. This setting only works if the appropriate pre-commit/pre-branch/pre-tag hook script is set up for this repository.',
-      '#default_value' => $repository_exists
-                          ? $repository->data['versioncontrol']['allow_unauthorized_access']
-                          : FALSE,
-      '#weight' => 0,
-    );
   }
 
   if ($repository_exists) {
@@ -509,6 +510,7 @@ function versioncontrol_admin_repository_edit_submit($form, &$form_state) {
     $repository->plugins              = array(
       'author_mapper' => $form_state['values']['author_mapper'],
       'committer_mapper' => $form_state['values']['committer_mapper'],
+      'auth_handlers' => $form_state['values']['authentication_handlers'],
     );
   }
   else {
@@ -522,6 +524,7 @@ function versioncontrol_admin_repository_edit_submit($form, &$form_state) {
       'plugins' => array(
         'author_mapper' => $form_state['values']['author_mapper'],
         'committer_mapper' => $form_state['values']['committer_mapper'],
+        'auth_handlers' => $form_state['values']['authentication_handlers'],
       ),
     );
     $repository = $backends[$form['#vcs']]->buildEntity('repo', $repository);
@@ -534,11 +537,6 @@ function versioncontrol_admin_repository_edit_submit($form, &$form_state) {
     'url_handler'          => new VersioncontrolRepositoryUrlHandler($repository, $repository_urls),
   );
 
-  if (isset($form_state['values']['allow_unauthorized_access'])) {
-    $repository->data['versioncontrol']['allow_unauthorized_access'] =
-      (bool) $form_state['values']['allow_unauthorized_access'];
-  }
-
   // Let other modules alter the repository array.
   foreach (module_implements('versioncontrol_repository_submit') as $module) {
     $function = $module .'_versioncontrol_repository_submit';
diff --git versioncontrol.api.php versioncontrol.api.php
index 6c7c31d..107e426 100644
--- versioncontrol.api.php
+++ versioncontrol.api.php
@@ -195,134 +195,6 @@ function hook_versioncontrol_operation_labels($op, $operation, $labels) {
   }
 }
 
-
-/**
- * Restrict, ignore or explicitly allow a commit, branch or tag operation
- * for a repository that is connected to the Version Control API
- * by VCS specific hook scripts.
- *
- * @param $operation
- *   A single operation array like the ones returned by
- *   versioncontrol_get_operations(), but leaving out on a few details that
- *   will instead be determined by this function. This array describes
- *   the operation that is about to happen. As it's not committed yet,
- *   it's also not in the database yet, which means that any information
- *   retrieval functions won't work on this operation array.
- *   It also means there's no 'vc_op_id', 'revision' and 'date' elements like
- *   in regular operation arrays. The 'message' element will not be set
- *   if the VCS doesn't support log messages for the current operation
- *   (e.g., most version control systems don't have branch messages).
- *
- *   Summed up, here's what this array contains for sure:
- *
- *   - 'type': The type of the operation - one of the
- *        VERSIONCONTROL_OPERATION_{COMMIT,BRANCH,TAG} constants.
- *   - 'repository': The repository where this operation occurs,
- *        given as a structured array, like the return value
- *        of versioncontrol_get_repository().
- *   - 'uid': The Drupal user id of the committer.
- *   - 'username': The system specific VCS username of the committer.
- *
- *   - 'labels': An array of branches or tags that will be affected by this
- *        operation. Branch and tag operations are known to only affect one
- *        branch or tag, so for these there will be only one element (with 0
- *        as key) in 'labels'. Commits might affect any number of branches,
- *        including none. Commits that emulate branches and/or tags (like
- *        in Subversion, where they're not a native concept) can also include
- *        add/delete/move operations for labels, as detailed below.
- *        Mind that the main development branch - e.g. 'HEAD', 'trunk'
- *        or 'master' - is also considered a branch. Each element in 'labels'
- *        is a structured array with the following keys:
- *
- *        - 'name': The branch or tag name (a string).
- *        - 'action': Specifies what happened to this label in this operation.
- *             For plain commits, this is always VERSIONCONTROL_ACTION_MODIFIED.
- *             For branch or tag operations (or commits that emulate those),
- *             it can be either VERSIONCONTROL_ACTION_ADDED or
- *             VERSIONCONTROL_ACTION_DELETED.
- *
- * @param $operation_items
- *   A structured array containing the exact details of what is about to happen
- *   to each item in this commit. The structure of this array is the same as
- *   the return value of VersioncontrolOperation::getItems() - that is,
- *   elements for 'type', 'path' and 'revision' - but doesn't include
- *   the 'item_revision_id' element as there's no relation to the database yet.
- *
- *   The 'action', 'source_items', 'replaced_item' and 'revision' elements
- *   of each item are optional for the VCS backend and may be left unset.
- *
- * @return
- *   An array with error messages (without trailing newlines) if the operation
- *   should not be allowed, or an empty array if you're indifferent,
- *   or TRUE if the operation should be allowed no matter what other
- *   write access callbacks say.
- *
- * @ingroup Operations
- * @ingroup Commit access
- * @ingroup Target audience: Commit access modules
- */
-function hook_versioncontrol_write_access($operation, $operation_items) {
-  // Only allow users with a registered Drupal user account to commit.
-  if ($operation['uid'] != 0) {
-    $user = user_load(array('uid' => $operation['uid']));
-  }
-  if (!$user) {
-    $error_message = t(
-"** ERROR: no Drupal user matches !vcs user '!user'.
-** Please contact a !vcs administrator for help.",
-      array('!vcs' => $operation->repository->getBackend()->name, '!user' => $operation->committer)
-    );
-    return array($error_message); // disallow the commit with an explanation
-  }
-
-  // Mind that also commits normally have labels, except for stuff like
-  // Subversion when the user commits outside of the trunk/branches/tags
-  // directories. Let's say we want to prevent such commits.
-  if (empty($operation['labels'])) {
-    $error_message = t("** ERROR: It is not allowed to commit without a branch or tag!");
-    return array($error_message);
-  }
-
-  // If an empty array is returned then that means we're indifferent:
-  // allow the operation if nobody else has objections.
-  $error_messages = array();
-
-  // Restrict disallowed branches and tags.
-  $valid_labels = array(
-    VERSIONCONTROL_LABEL_BRANCH => array('@^HEAD$@', '@^DRUPAL-5(--[2-9])?$@', '@^DRUPAL-6--[1-9]$@'),
-    VERSIONCONTROL_LABEL_TAG => array('@^DRUPAL-[56]--(\d+)-(\d+)(-[A-Z0-9]+)?$@'),
-  );
-
-  foreach ($operation['labels'] as $label) {
-    if ($label['type'] == VERSIONCONTROL_LABEL_TAG
-        && $label['action'] == VERSIONCONTROL_ACTION_DELETED) {
-      continue; // no restrictions, even invalid tags should be allowed to be deleted
-    }
-
-    // Make sure that the assigned branch or tag name is allowed.
-    $valid = FALSE;
-
-    foreach ($valid_labels[$label['type']] as $valid_label_regexp) {
-      if (preg_match($valid_label_regexp, $label['name'])) {
-        $valid = TRUE;
-        break;
-      }
-    }
-    if (!$valid) {
-      // No regexps match this label, so deny it.
-      $error_messages[] = t('** ERROR: the !name !labeltype is not allowed in this repository.', array(
-        '!name' => $label['name'],
-        '!labeltype' => ($label['type'] == VERSIONCONTROL_LABEL_BRANCH)
-                        ? t('branch')
-                        : t('tag'),
-      ));
-    }
-  }
-
-  return $error_messages;
-}
-
-
 /**
  * Extract repository data from the repository edit/add form's submitted
  * values, and add it to the @p $repository array. Later, that array will be
diff --git versioncontrol.install versioncontrol.install
index 9e42652..77172df 100644
--- versioncontrol.install
+++ versioncontrol.install
@@ -1164,3 +1164,20 @@ function versioncontrol_update_6312() {
 
   return $ret;
 }
+
+/**
+ * Remove allow_unauthorized_access from repository data.
+ */
+function versioncontrol_update_6313() {
+  $ret = array();
+  $result = db_query("SELECT repo_id, data FROM {versioncontrol_repositories}");
+
+  while ($row = db_fetch_object($result)) {
+    $data = unserialize($row->data);
+    unset($data['versioncontrol']['allow_unauthorized_access']);
+    $data = serialize($row->data);
+    db_query('UPDATE {versioncontrol_repositories} SET data = %s WHERE repo_id = %d', $row->data, $row->repo_id);
+  }
+
+  return $ret;
+}
diff --git versioncontrol.module versioncontrol.module
index d0bf064..8a86309 100644
--- versioncontrol.module
+++ versioncontrol.module
@@ -1002,3 +1002,18 @@ function versioncontrol_user_mapping_methods_get_names() {
   asort($names);
   return $names;
 }
+
+/**
+ * Load the names of all 'auth_handlers' for use at forms.
+ */
+function versioncontrol_auth_handlers_get_names() {
+  ctools_include('plugins');
+
+  $names = array();
+  foreach (ctools_get_plugins('versioncontrol', 'vcs_auth') as $name => $plugin) {
+    $names[$name] = $plugin['title'];
+  }
+
+  asort($names);
+  return $names;
+}
diff --git versioncontrol_account_status/includes/versioncontrol_plugins/vcs_auth/VersioncontrolAuthHandlerAccountStatus.class.php versioncontrol_account_status/includes/versioncontrol_plugins/vcs_auth/VersioncontrolAuthHandlerAccountStatus.class.php
new file mode 100644
index 0000000..87e6c57
--- /dev/null
+++ versioncontrol_account_status/includes/versioncontrol_plugins/vcs_auth/VersioncontrolAuthHandlerAccountStatus.class.php
@@ -0,0 +1,80 @@
+<?php
+
+class VersioncontrolAuthHandlerAccountStatus implements VersioncontrolAuthHandlerInterface {
+  /**
+   * Boolean indicating whether the object has already run its build routine.
+   *
+   * @var bool
+   */
+  protected $built = FALSE;
+
+  /**
+   * An array of error message strings returned by
+   * VersioncontrolAuthHandlerMappedAccounts::getErrorMessages().
+   *
+   * @var array
+   */
+  protected $errors = array();
+
+  public function setRepository(VersioncontrolRepository $repository) {
+    if ($this->repository !== $repository) {
+      throw new Exception('Cannot attach different repositories to a single VersioncontrolAuthHandlerAccountStatus instance. Instanciate a new object.', E_RECOVERABLE_ERROR);
+    }
+    $this->repository = $repository;
+    $this->build();
+  }
+
+  protected function build() {
+    if ($this->built) {
+      return; // already built, bail out
+    }
+    if (!$this->repository instanceof VersioncontrolRepository) {
+      throw new Exception('Cannot build the account status object until a repository has been attached.');
+    }
+
+    // Retrieve the base auth data
+    $conditions = array(
+      'repo_id' => $this->repository->repo_id,
+      'status' => VERSIONCONTROL_ACCOUNT_STATUS_APPROVED,
+    );
+    $this->userAccounts = versioncontrol_account_status_get($conditions);
+
+    $this->built = TRUE;
+  }
+
+  public function hasAccountApproved() {
+    // At least one account aproved to pass
+    if (!empty($this->userAccounts)) {
+      return TRUE;
+    }
+    $this->errors[] = t('The user do not still have an account approved on this repository');
+    return FALSE;
+  }
+
+  public function authAccess($uid) {
+    return $this->hasAccountApproved();
+  }
+
+  public function authBranchCreate($uid, VersioncontrolBranch $branch) {
+    return $this->hasAccountApproved();
+  }
+  public function authBranchDelete($uid, VersioncontrolBranch $branch) {
+    return $this->hasAccountApproved();
+  }
+  public function authBranchUpdate($uid, VersioncontrolBranch $branch) {
+    return $this->hasAccountApproved();
+  }
+  public function authTagCreate($uid, VersioncontrolTag $tag) {
+    return $this->hasAccountApproved();
+  }
+  public function authTagDelete($uid, VersioncontrolTag $tag) {
+    return $this->hasAccountApproved();
+  }
+  public function authTagUpdate($uid, VersioncontrolTag $tag) {
+    return $this->hasAccountApproved();
+  }
+
+  public function getErrorMessages() {
+    return $this->errors;
+  }
+}
diff --git versioncontrol_account_status/includes/versioncontrol_plugins/vcs_auth/account_status.inc versioncontrol_account_status/includes/versioncontrol_plugins/vcs_auth/account_status.inc
new file mode 100644
index 0000000..4d7240e
--- /dev/null
+++ versioncontrol_account_status/includes/versioncontrol_plugins/vcs_auth/account_status.inc
@@ -0,0 +1,9 @@
+<?php
+// $Id$
+
+$plugin = array(
+  'title' => t('Account status (only let pass if the user has an account)'),
+  'handler' => array(
+    'class' => 'VersioncontrolAuthHandlerAccountStatus',
+  ),
+);
diff --git versioncontrol_account_status/versioncontrol_account_status.module versioncontrol_account_status/versioncontrol_account_status.module
index cfb7737..dd26a86 100644
--- versioncontrol_account_status/versioncontrol_account_status.module
+++ versioncontrol_account_status/versioncontrol_account_status.module
@@ -1780,3 +1780,12 @@ function versioncontrol_account_status_views_api() {
     'path' => drupal_get_path('module', 'versioncontrol_account_status'). '/includes',
   );
 }
+
+/**
+ * Implementation of ctools hook_ctools_plugin_directory().
+ */
+function versioncontrol_account_status_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'versioncontrol') {
+    return "includes/versioncontrol_plugins/$plugin";
+  }
+}
