diff --git a/libs/client/ClientAPI.hpp b/libs/client/ClientAPI.hpp
index e4752476e16e4534172596a25a45ba2b498a85e5..92a967c346c708bf1344b502049917a18f5ca3fe 100644
--- a/libs/client/ClientAPI.hpp
+++ b/libs/client/ClientAPI.hpp
@@ -11,7 +11,8 @@
 namespace cta {
 
 /**
- * Abstract class that specifies the client ClientAPI of the CERN Tape Archive project.
+ * Abstract class that specifies the client ClientAPI of the CERN Tape Archive
+ * project.
  */
 class ClientAPI {
 public:
@@ -21,6 +22,66 @@ public:
    */
   virtual ~ClientAPI() throw() = 0;
 
+  /**
+   * Creates the specified administrator.
+   *
+   * @param requester The identity of the user requesting the creation of the
+   * administrator.
+   * @param admin The identity of the administrator.
+   */
+  virtual void createAdminUser(
+    const UserIdentity &requester,
+    const UserIdentity &admin) = 0;
+
+  /**
+   * Deletes the specified administrator.
+   *
+   * @param requester The identity of the user requesting the deletion of the
+   * administrator.
+   * @param admin The identity of the administrator.
+   */
+  virtual void deleteAdminUser(
+    const UserIdentity &requester,
+    const UserIdentity &admin) = 0;
+
+  /**
+   * Returns the current list of administrators.
+   *
+   * @param requester The identity of the user requesting the list.
+   */
+  virtual std::list<UserIdentity> getAdminUsers(const UserIdentity &requester)
+   const = 0;
+
+  /**
+   * Creates the specified administration host.
+   *
+   * @param requester The identity of the user requesting the creation of the
+   * administration host.
+   * @param adminHost The network name of the administration host.
+   */
+  virtual void createAdminHost(
+    const UserIdentity &requester,
+    const std::string &adminHost) = 0;
+
+  /**
+   * Deletes the specified administration host.
+   *
+   * @param requester The identity of the user requesting the deletion of the
+   * administration host.
+   * @param adminHost The network name of the administration host.
+   */
+  virtual void deleteAdminHost(
+    const UserIdentity &requester,
+    const std::string &adminHost) = 0;
+
+  /**
+   * Returns the current list of administration hosts.
+   *
+   * @param requester The identity of the user requesting the list.
+   */
+  virtual std::list<std::string> getAdminHosts(const UserIdentity &requester)
+   const  = 0;
+
   /**
    * Creates the specified storage class.
    *
@@ -49,8 +110,7 @@ public:
   /**
    * Gets the current list of storage classes in lexicographical order.
    *
-   * @param requester The identity of the user requesting list of storage
-   * classes.
+   * @param requester The identity of the user requesting list.
    * @return The current list of storage classes in lexicographical order.
    */
   virtual std::list<StorageClass> getStorageClasses(
diff --git a/libs/client/MockClientAPI.cpp b/libs/client/MockClientAPI.cpp
index cc5bdb2c6b15e97309c4217f2afaaab3cdcc27e2..f39d9e8ffe0bdadaf7b1516a22ac573e9b24c41d 100644
--- a/libs/client/MockClientAPI.cpp
+++ b/libs/client/MockClientAPI.cpp
@@ -1,5 +1,5 @@
-#include "MockClientAPI.hpp"
 #include "Exception.hpp"
+#include "MockClientAPI.hpp"
 
 #include <sstream>
 
@@ -15,6 +15,54 @@ cta::MockClientAPI::MockClientAPI() {
 cta::MockClientAPI::~MockClientAPI() throw() {
 }
 
+//------------------------------------------------------------------------------
+// createAdminUser
+//------------------------------------------------------------------------------
+void cta::MockClientAPI::createAdminUser(
+  const UserIdentity &requester,
+  const UserIdentity &admin) {
+}
+  
+//------------------------------------------------------------------------------
+// deleteAdminUser
+//------------------------------------------------------------------------------
+void cta::MockClientAPI::deleteAdminUser(
+  const UserIdentity &requester,
+  const UserIdentity &admin) {
+}
+  
+//------------------------------------------------------------------------------
+// getAdminUsers
+//------------------------------------------------------------------------------
+std::list<cta::UserIdentity> cta::MockClientAPI::getAdminUsers(
+  const UserIdentity &requester) const {
+  return m_adminUsers;
+}
+
+//------------------------------------------------------------------------------
+// createAdminHost
+//------------------------------------------------------------------------------
+void cta::MockClientAPI::createAdminHost(
+  const UserIdentity &requester,
+  const std::string &adminHost) {
+}
+
+//------------------------------------------------------------------------------
+// deleteAdminHost
+//------------------------------------------------------------------------------
+void cta::MockClientAPI::deleteAdminHost(
+  const UserIdentity &requester,
+  const std::string &adminHost) {
+}
+  
+//------------------------------------------------------------------------------
+// getAdminHosts
+//------------------------------------------------------------------------------
+std::list<std::string> cta::MockClientAPI::getAdminHosts(
+  const UserIdentity &requester) const {
+  return m_adminHosts;
+}
+
 //------------------------------------------------------------------------------
 // createStorageClass
 //------------------------------------------------------------------------------
@@ -175,6 +223,11 @@ void cta::MockClientAPI::checkPathDoesContainConsecutiveSlashes(
 // getEnclosingDirPath
 //------------------------------------------------------------------------------
 std::string cta::MockClientAPI::getEnclosingDirPath(const std::string &path) {
+  const std::string::size_type last_slash_idx = path.find_last_of('/');
+  if(std::string::npos == last_slash_idx) {
+    throw Exception("Path does not contain a slash");
+  }
+  return path.substr(0, last_slash_idx);
 }
 
 //------------------------------------------------------------------------------
diff --git a/libs/client/MockClientAPI.hpp b/libs/client/MockClientAPI.hpp
index edb18152364a7f7d61fa791cfc49048224b17345..324e8482d976bca6d045b5a41518f0f3c6541c35 100644
--- a/libs/client/MockClientAPI.hpp
+++ b/libs/client/MockClientAPI.hpp
@@ -22,6 +22,64 @@ public:
    */
   ~MockClientAPI() throw();
 
+  /**
+   * Creates the specified administrator.
+   *
+   * @param requester The identity of the user requesting the creation of the
+   * administrator.
+   * @param admin The identity of the administrator.
+   */
+  void createAdminUser(
+    const UserIdentity &requester,
+    const UserIdentity &admin);
+
+  /**
+   * Deletes the specified administrator.
+   *
+   * @param requester The identity of the user requesting the deletion of the
+   * administrator.
+   * @param admin The identity of the administrator.
+   */
+  void deleteAdminUser(
+    const UserIdentity &requester,
+    const UserIdentity &admin);
+
+  /**
+   * Returns the current list of administrators.
+   *
+   * @param requester The identity of the user requesting the list.
+   */
+  std::list<UserIdentity> getAdminUsers(const UserIdentity &requester) const;
+
+  /**
+   * Creates the specified administration host.
+   *
+   * @param requester The identity of the user requesting the creation of the
+   * administration host.
+   * @param adminHost The network name of the administration host.
+   */
+  void createAdminHost(
+    const UserIdentity &requester,
+    const std::string &adminHost);
+
+  /**
+   * Deletes the specified administration host.
+   *
+   * @param requester The identity of the user requesting the deletion of the
+   * administration host.
+   * @param adminHost The network name of the administration host.
+   */
+  void deleteAdminHost(
+    const UserIdentity &requester,
+    const std::string &adminHost);
+
+  /**
+   * Returns the current list of administration hosts.
+   *
+   * @param requester The identity of the user requesting the list.
+   */
+  std::list<std::string> getAdminHosts(const UserIdentity &requester) const;
+
   /**
    * Creates the specified storage class.
    *
@@ -50,8 +108,7 @@ public:
   /**
    * Gets the current list of storage classes in lexicographical order.
    *
-   * @param requester The identity of the user requesting list of storage
-   * classes.
+   * @param requester The identity of the user requesting the list.
    * @return The current list of storage classes in lexicographical order.
    */
   std::list<StorageClass> getStorageClasses(
@@ -103,7 +160,17 @@ public:
     const std::list<std::string> &srcUrls,
     std::string dst);
 
-private:
+protected:
+
+  /**
+   * The current list of administrators.
+   */
+  std::list<UserIdentity> m_adminUsers;
+
+  /**
+   * The current list of administration hosts.
+   */
+  std::list<std::string> m_adminHosts;
 
   /**
    * The current list of storage classes.
diff --git a/libs/client/MockClientAPITest.cpp b/libs/client/MockClientAPITest.cpp
index f5aa2410d5d2fba9dce48caef5d91348dbda6ce5..0f06e71693005d8a44cc19f4bd669abffbd30a4f 100644
--- a/libs/client/MockClientAPITest.cpp
+++ b/libs/client/MockClientAPITest.cpp
@@ -1,4 +1,4 @@
-#include "MockClientAPI.hpp"
+#include "TestingMockClientAPI.hpp"
 
 #include <gtest/gtest.h>
 
@@ -14,11 +14,209 @@ protected:
   }
 };
 
+TEST_F(cta_client_MockClientAPITest, createAdminUser_new) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const UserIdentity requester;
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_TRUE(adminUsers.empty());
+  }
+
+  const uint16_t adminUser1Uid = 1234;
+  const uint16_t adminUser1Gid = 5678;
+  const UserIdentity adminUser1(adminUser1Uid, adminUser1Gid, "");
+  ASSERT_NO_THROW(api.createAdminUser(requester, adminUser1));
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_EQ(1, adminUsers.size());
+
+    ASSERT_EQ(adminUser1Uid, adminUsers.front().uid);
+    ASSERT_EQ(adminUser1Gid, adminUsers.front().gid);
+  }
+}
+
+TEST_F(cta_client_MockClientAPITest, createAdminUser_already_existing) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const UserIdentity requester;
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_TRUE(adminUsers.empty());
+  }
+
+  const uint16_t adminUser1Uid = 1234;
+  const uint16_t adminUser1Gid = 5678;
+  const UserIdentity adminUser1(adminUser1Uid, adminUser1Gid, "");
+  ASSERT_NO_THROW(api.createAdminUser(requester, adminUser1));
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_EQ(1, adminUsers.size());
+
+    ASSERT_EQ(adminUser1Uid, adminUsers.front().uid);
+    ASSERT_EQ(adminUser1Gid, adminUsers.front().gid);
+  }
+
+  ASSERT_THROW(api.createAdminUser(requester, adminUser1), std::exception);
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_EQ(1, adminUsers.size());
+  }
+}
+
+TEST_F(cta_client_MockClientAPITest, deleteAdminUser_existing) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const UserIdentity requester;
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_TRUE(adminUsers.empty());
+  }
+
+  const uint16_t adminUser1Uid = 1234;
+  const uint16_t adminUser1Gid = 5678;
+  const UserIdentity adminUser1(adminUser1Uid, adminUser1Gid, "");
+  ASSERT_NO_THROW(api.createAdminUser(requester, adminUser1));
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_EQ(1, adminUsers.size());
+
+    ASSERT_EQ(adminUser1Uid, adminUsers.front().uid);
+    ASSERT_EQ(adminUser1Gid, adminUsers.front().gid);
+  }
+
+  ASSERT_NO_THROW(api.deleteAdminUser(requester, adminUser1));
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_TRUE(adminUsers.empty());
+  }
+}
+
+TEST_F(cta_client_MockClientAPITest, deleteAdminUser_non_existing) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const UserIdentity requester;
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_TRUE(adminUsers.empty());
+  } 
+  
+  const uint16_t adminUser1Uid = 1234;
+  const uint16_t adminUser1Gid = 5678;
+  const UserIdentity adminUser1(adminUser1Uid, adminUser1Gid, "");
+  ASSERT_THROW(api.deleteAdminUser(requester, adminUser1), std::exception);
+
+  {
+    std::list<UserIdentity> adminUsers;
+    ASSERT_NO_THROW(adminUsers = api.getAdminUsers(requester));
+    ASSERT_TRUE(adminUsers.empty());
+  }
+}
+
+TEST_F(cta_client_MockClientAPITest, createAdminHost_new) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const UserIdentity requester;
+
+  {
+    std::list<std::string> adminHosts;
+    ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester));
+    ASSERT_TRUE(adminHosts.empty());
+  }
+
+  const std::string adminHost1 = "adminHost1";
+  ASSERT_NO_THROW(api.createAdminHost(requester, adminHost1));
+
+  {
+    std::list<std::string> adminHosts;
+    ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester));
+    ASSERT_EQ(1, adminHosts.size());
+
+    ASSERT_EQ(adminHost1, adminHosts.front());
+  }
+}
+
+TEST_F(cta_client_MockClientAPITest, deleteAdminHost_existing) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const UserIdentity requester;
+
+  {
+    std::list<std::string> adminHosts;
+    ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester));
+    ASSERT_TRUE(adminHosts.empty());
+  }
+
+  const std::string adminHost1 = "adminHost1";
+  ASSERT_NO_THROW(api.createAdminHost(requester, adminHost1));
+
+  {
+    std::list<std::string> adminHosts;
+    ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester));
+    ASSERT_EQ(1, adminHosts.size());
+
+    ASSERT_EQ(adminHost1, adminHosts.front());
+  }
+
+  ASSERT_NO_THROW(api.deleteAdminHost(requester, adminHost1));
+
+  {
+    std::list<std::string> adminHosts;
+    ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester));
+    ASSERT_TRUE(adminHosts.empty());
+  }
+}
+
+TEST_F(cta_client_MockClientAPITest, deleteAdminHost_non_existing) {
+  using namespace cta;
+
+  TestingMockClientAPI api;
+  const UserIdentity requester;
+  
+  {
+    std::list<std::string> adminHosts;
+    ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester));
+    ASSERT_TRUE(adminHosts.empty());
+  }
+
+  const std::string adminHost1 = "adminHost1";
+  ASSERT_THROW(api.deleteAdminHost(requester, adminHost1), std::exception);
+
+  {
+    std::list<std::string> adminHosts;
+    ASSERT_NO_THROW(adminHosts = api.getAdminHosts(requester));
+    ASSERT_TRUE(adminHosts.empty());
+  }
+}
+
 TEST_F(cta_client_MockClientAPITest, createStorageClass_new) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
 
   {
     std::list<StorageClass> storageClasses;
@@ -45,8 +243,8 @@ TEST_F(cta_client_MockClientAPITest, createStorageClass_new) {
 TEST_F(cta_client_MockClientAPITest, createStorageClass_already_existing) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
 
   {
     std::list<StorageClass> storageClasses;
@@ -76,8 +274,8 @@ TEST_F(cta_client_MockClientAPITest, createStorageClass_already_existing) {
 TEST_F(cta_client_MockClientAPITest, createStorageClass_lexicographical_order) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
 
   {
     std::list<StorageClass> storageClasses;
@@ -108,8 +306,8 @@ TEST_F(cta_client_MockClientAPITest, createStorageClass_lexicographical_order) {
 TEST_F(cta_client_MockClientAPITest, deleteStorageClass_existing) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
 
   {
     std::list<StorageClass> storageClasses;
@@ -144,8 +342,8 @@ TEST_F(cta_client_MockClientAPITest, deleteStorageClass_existing) {
 TEST_F(cta_client_MockClientAPITest, deleteStorageClass_non_existing) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
 
   {
     std::list<StorageClass> storageClasses;
@@ -166,8 +364,8 @@ TEST_F(cta_client_MockClientAPITest, deleteStorageClass_non_existing) {
 TEST_F(cta_client_MockClientAPITest, getDirectoryContents_root_dir_is_empty) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
   const std::string dirPath = "/";
 
   DirectoryIterator itor;
@@ -178,8 +376,8 @@ TEST_F(cta_client_MockClientAPITest, getDirectoryContents_root_dir_is_empty) {
 TEST_F(cta_client_MockClientAPITest, createDirectory_empty_string) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
   const std::string dirPath = "";
 
   ASSERT_THROW(api.createDirectory(requester, dirPath), std::exception);
@@ -188,8 +386,8 @@ TEST_F(cta_client_MockClientAPITest, createDirectory_empty_string) {
 TEST_F(cta_client_MockClientAPITest, createDirectory_consecutive_slashes) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
   const std::string dirPath = "//";
 
   ASSERT_THROW(api.createDirectory(requester, dirPath), std::exception);
@@ -198,8 +396,8 @@ TEST_F(cta_client_MockClientAPITest, createDirectory_consecutive_slashes) {
 TEST_F(cta_client_MockClientAPITest, createDirectory_invalid_chars) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
   const std::string dirPath = "/grandparent/?parent";
   
   ASSERT_THROW(api.createDirectory(requester, dirPath), std::exception);
@@ -208,11 +406,23 @@ TEST_F(cta_client_MockClientAPITest, createDirectory_invalid_chars) {
 TEST_F(cta_client_MockClientAPITest, createDirectory_top_level) {
   using namespace cta;
 
-  MockClientAPI api;
-  UserIdentity requester;
+  TestingMockClientAPI api;
+  const UserIdentity requester;
   const std::string dirPath = "/grandparent";
   
   ASSERT_NO_THROW(api.createDirectory(requester, dirPath));
+
+  DirectoryIterator itor;
+
+  ASSERT_NO_THROW(itor = api.getDirectoryContents(requester, "/"));
+
+  ASSERT_TRUE(itor.hasMore());
+
+  DirectoryEntry entry;
+
+  ASSERT_NO_THROW(entry = itor.next());
+
+  ASSERT_EQ(std::string("grandparent"), entry.name);
 }
 
 } // namespace unitTests
diff --git a/libs/client/UserIdentity.cpp b/libs/client/UserIdentity.cpp
index 161633fc23d0f5a9cd2cc7dec75d84deee03d39b..66a02e5d4e3ec071a51a4bd437678ec6f97d1bda 100644
--- a/libs/client/UserIdentity.cpp
+++ b/libs/client/UserIdentity.cpp
@@ -12,7 +12,11 @@ cta::UserIdentity::UserIdentity() throw():
 //------------------------------------------------------------------------------
 // constructor
 //------------------------------------------------------------------------------
-cta::UserIdentity::UserIdentity(const uint32_t uid, const uint32_t gid) throw():
+cta::UserIdentity::UserIdentity(
+  const uint32_t uid,
+  const uint32_t gid,
+  const std::string &host) throw():
   uid(uid),
-  gid(gid) {
+  gid(gid),
+  host(host) {
 }
diff --git a/libs/client/UserIdentity.hpp b/libs/client/UserIdentity.hpp
index 77e75daadaa1e5ebbb5bf32e1ad0d1a12a2659e7..1b9d36ec15bd98789d72550f7b3b81884e8b03fa 100644
--- a/libs/client/UserIdentity.hpp
+++ b/libs/client/UserIdentity.hpp
@@ -37,8 +37,10 @@ struct UserIdentity {
    *
    * @param uid The user ID of the user.
    * @param gid The group ID of the user.
+   * @param host The host from which the user is communicating.
    */
-  UserIdentity(const uint32_t uid, const uint32_t gid) throw();
+  UserIdentity(const uint32_t uid, const uint32_t gid, const std::string &host)
+    throw();
 
 }; // struct UserIdentity
 
diff --git a/objectstore/RecallJob.hpp b/objectstore/RecallJob.hpp
index 43ff8be78a54823da364f047f35bff35547be77d..c2fe8da886ab91628b39bbcd70af25e0b5e09372 100644
--- a/objectstore/RecallJob.hpp
+++ b/objectstore/RecallJob.hpp
@@ -41,4 +41,4 @@ public:
   }
 };
  
-}}
\ No newline at end of file
+}}