initial import of finished admin api

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40410
This commit is contained in:
David Anderson 2007-01-29 04:19:14 +00:00
parent 7a8d164b25
commit c66632776f
4 changed files with 657 additions and 11 deletions

View File

@ -26,8 +26,10 @@ AdminCache::AdminCache()
m_pStrings = new BaseStringTable(1024);
m_pMemory = m_pStrings->GetMemTable();
m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID;
m_FreeUserList = m_FirstUser = m_LastUser = INVALID_ADMIN_ID;
m_pGroups = sm_trie_create();
m_pCacheFwd = NULL;
m_FirstGroup = -1;
}
AdminCache::~AdminCache()
@ -52,6 +54,13 @@ AdminCache::~AdminCache()
delete m_pStrings;
}
void AdminCache::OnSourceModStartup(bool late)
{
RegisterAuthIdentType("steam");
RegisterAuthIdentType("name");
RegisterAuthIdentType("ip");
}
void AdminCache::OnSourceModAllInitialized()
{
m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell);
@ -196,6 +205,51 @@ void AdminCache::DumpCommandOverrideCache(OverrideType type)
}
}
AdminId AdminCache::CreateAdmin(const char *name)
{
AdminId id;
AdminUser *pUser;
if (m_FreeUserList != INVALID_ADMIN_ID)
{
pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList);
assert(pUser->magic == USR_MAGIC_UNSET);
id = m_FreeUserList;
m_FreeUserList = pUser->next_user;
} else {
id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser);
pUser->grp_size = 0;
pUser->grp_table = -1;
pUser->auth_size = 0;
pUser->auth_table = -1;
}
memset(pUser->flags, 0, sizeof(pUser->flags));
memset(pUser->eflags, 0, sizeof(pUser->flags));
pUser->grp_count = 0;
pUser->auth_count = 0;
pUser->password = -1;
pUser->magic = USR_MAGIC_SET;
if (m_FirstUser == INVALID_ADMIN_ID)
{
m_FirstUser = id;
m_LastUser = id;
} else {
AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
pPrev->next_user = id;
pUser->prev_user = m_LastUser;
m_LastUser = id;
}
if (name && name[0] != '\0')
{
pUser->nameidx = m_pStrings->AddString(name);
}
return id;
}
GroupId AdminCache::AddGroup(const char *group_name)
{
if (sm_trie_retrieve(m_pGroups, group_name, NULL))
@ -222,7 +276,6 @@ GroupId AdminCache::AddGroup(const char *group_name)
pGroup->next_grp = INVALID_GROUP_ID;
pGroup->pCmdGrpTable = NULL;
pGroup->pCmdTable = NULL;
pGroup->nameidx = m_pStrings->AddString(group_name);
memset(pGroup->addflags, 0, sizeof(AdminFlag) * AdminFlags_TOTAL);
if (m_FirstGroup == INVALID_GROUP_ID)
@ -238,6 +291,8 @@ GroupId AdminCache::AddGroup(const char *group_name)
m_LastGroup = id;
}
pGroup->nameidx = m_pStrings->AddString(group_name);
sm_trie_insert(m_pGroups, group_name, (void *)id);
return id;
@ -498,6 +553,80 @@ bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideT
return true;
}
Trie *AdminCache::GetMethodByIndex(unsigned int index)
{
List<AuthMethod>::iterator iter;
for (iter=m_AuthMethods.begin();
iter!=m_AuthMethods.end();
iter++)
{
if (index-- == 0)
{
return (*iter).table;
}
}
return NULL;
}
bool AdminCache::InvalidateAdmin(AdminId id)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
AdminUser *pOther;
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return false;
}
/* Unlink from the dbl link list */
if (id == m_FirstUser && id == m_LastUser)
{
m_FirstUser = INVALID_ADMIN_ID;
m_LastUser = INVALID_ADMIN_ID;
} else if (id == m_FirstUser) {
m_FirstUser = pUser->next_user;
pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser);
pOther->prev_user = INVALID_ADMIN_ID;
} else if (id == m_LastUser) {
m_LastUser = pUser->prev_user;
pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
pOther->next_user = INVALID_ADMIN_ID;
} else {
pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user);
pOther->next_user = pUser->next_user;
pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user);
pOther->prev_user = pUser->prev_user;
}
/* Unlink from auth tables */
if (pUser->auth_count > 0)
{
UserAuth *pAuth = (UserAuth *)m_pMemory->GetAddress(pUser->auth_table);
Trie *pTrie;
for (unsigned int i=0; i<pUser->auth_count; i++)
{
pTrie = GetMethodByIndex(pAuth[i].index);
if (!pTrie)
{
continue;
}
sm_trie_delete(pTrie, m_pStrings->GetString(pAuth->identidx));
}
}
/* Clear table counts */
pUser->grp_count = 0;
pUser->auth_count = 0;
/* Link into free list */
pUser->magic = USR_MAGIC_UNSET;
pUser->next_user = m_FreeUserList;
m_FreeUserList = id;
return true;
}
void AdminCache::InvalidateGroup(GroupId id)
{
AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
@ -548,7 +677,44 @@ void AdminCache::InvalidateGroup(GroupId id)
pGroup->next_grp = m_FreeGroupList;
m_FreeGroupList = id;
/* :TODO: remove this group from any users */
int idx = m_FirstUser;
AdminUser *pUser;
int *table;
while (idx != INVALID_ADMIN_ID)
{
pUser = (AdminUser *)m_pMemory->GetAddress(idx);
if (pUser->grp_count > 0)
{
table = (int *)m_pMemory->GetAddress(pUser->grp_table);
for (unsigned int i=0; i<pUser->grp_count; i++)
{
if (table[i] == id)
{
/* We have to remove this entry */
for (unsigned int j=i+1; j<pUser->grp_count; j++)
{
/* Move everything down by one */
table[j-1] = table[j];
}
/* Decrease count */
pUser->grp_count--;
/* Recalculate effective flags */
memset(pUser->eflags, 0, sizeof(pUser->eflags));
for (unsigned int j=0; j<pUser->grp_count; j++)
{
pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]);
for (unsigned int k=0; k<AdminFlags_TOTAL; k++)
{
pUser->eflags[k] = (pUser->flags[k] || pOther->addflags[k]);
}
}
/* Break now, duplicates aren't allowed */
break;
}
}
}
idx = pUser->next_user;
}
}
void AdminCache::InvalidateGroupCache()
@ -580,7 +746,7 @@ void AdminCache::InvalidateGroupCache()
m_FirstGroup = INVALID_GROUP_ID;
m_LastGroup = INVALID_GROUP_ID;
/* :TODO: dump the admin cache */
InvalidateAdminCache(false);
/* Reset the memory table */
m_pMemory->Reset();
@ -596,6 +762,41 @@ void AdminCache::RemoveAdminListener(IAdminListener *pListener)
m_hooks.remove(pListener);
}
void AdminCache::RegisterAuthIdentType(const char *name)
{
if (sm_trie_retrieve(m_pAuthTables, name, NULL))
{
return;
}
Trie *pAuth = sm_trie_create();
AuthMethod method;
method.name.assign(name);
method.table = pAuth;
m_AuthMethods.push_back(method);
sm_trie_insert(m_pAuthTables, name, pAuth);
}
void AdminCache::InvalidateAdminCache(bool unlink_admins)
{
/* Wipe the identity cache first */
List<AuthMethod>::iterator iter;
for (iter=m_AuthMethods.begin();
iter!=m_AuthMethods.end();
iter++)
{
sm_trie_clear((*iter).table);
}
while (m_FirstUser != INVALID_ADMIN_ID)
{
InvalidateAdmin(m_FirstUser);
}
}
void AdminCache::DumpAdminCache(int cache_flags, bool rebuild)
{
if (cache_flags & ADMIN_CACHE_OVERRIDES)
@ -604,19 +805,19 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild)
DumpCommandOverrideCache(Override_CommandGroup);
}
if ((cache_flags & ADMIN_CACHE_ADMINS) ||
(cache_flags & ADMIN_CACHE_GROUPS))
{
/* Make sure the flag is set */
cache_flags |= ADMIN_CACHE_ADMINS;
/* :TODO: Dump admin cache */
}
/* This will auto-invalidate the admin cache */
if (cache_flags & ADMIN_CACHE_GROUPS)
{
InvalidateGroupCache();
}
/* If we only requested an admin rebuild, re-use the internal memory */
if ((cache_flags & ADMIN_CACHE_ADMINS) &&
!(cache_flags & ADMIN_CACHE_GROUPS))
{
InvalidateAdminCache(true);
}
if (rebuild)
{
List<IAdminListener *>::iterator iter;
@ -631,3 +832,236 @@ void AdminCache::DumpAdminCache(int cache_flags, bool rebuild)
m_pCacheFwd->Execute(&result);
}
}
const char *AdminCache::GetAdminName(AdminId id)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return NULL;
}
return m_pStrings->GetString(pUser->nameidx);
}
bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return false;
}
Trie *pTable;
if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
{
return false;
}
if (sm_trie_retrieve(pTable, ident, NULL))
{
return false;
}
return sm_trie_insert(pTable, ident, (void **)id);
}
AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
{
Trie *pTable;
if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
{
return INVALID_ADMIN_ID;
}
void *object;
if (!sm_trie_retrieve(pTable, identity, &object))
{
return INVALID_ADMIN_ID;
}
return (AdminId)object;
}
void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return;
}
if (flag < Admin_None
|| flag >= AdminFlags_TOTAL)
{
return;
}
pUser->flags[enabled] = false;
}
bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return false;
}
if (flag < Admin_None
|| flag >= AdminFlags_TOTAL)
{
return false;
}
if (mode == Access_Real)
{
return pUser->flags[flag];
} else if (mode == Access_Effective) {
return (pUser->flags[flag] || pUser->eflags[flag]);
}
return false;
}
unsigned int AdminCache::GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return 0;
}
unsigned int i = 0;
if (mode == Access_Real)
{
for (i=0; i<AdminFlags_TOTAL && i<total; i++)
{
flags[i] = pUser->flags[i];
}
} else if (mode == Access_Effective) {
for (i=0; i<AdminFlags_TOTAL && i<total; i++)
{
flags[i] = (pUser->flags[i] || pUser->eflags[i]);
}
}
return i;
}
bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return false;
}
AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
if (!pGroup || pGroup->magic != USR_MAGIC_SET)
{
return false;
}
int *table;
if (pUser->grp_count + 1 > pUser->grp_size)
{
int new_size = 0;
int tblidx;
if (pUser->grp_size == 0)
{
new_size = 2;
} else {
new_size = pUser->grp_size * 2;
}
/* Create and refresh pointers */
tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table);
pUser = (AdminUser *)m_pMemory->GetAddress(id);
pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
/* Copy old data if necessary */
if (pUser->grp_table != -1)
{
int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
memcpy(table, old_table, sizeof(int) * pUser->grp_count);
}
pUser->grp_table = tblidx;
pUser->grp_size = new_size;
} else {
table = (int *)m_pMemory->GetAddress(pUser->grp_table);
}
for (unsigned int i=0; i<pUser->grp_count; i++)
{
if (table[i] == gid)
{
return false;
}
}
table[pUser->grp_count] = gid;
pUser->grp_count++;
/* Compute new effective flags */
for (unsigned int i=Admin_None;
i<AdminFlags_TOTAL;
i++)
{
/* Only inherit flags additive flags we don't have */
if (!pUser->eflags[i])
{
pUser->eflags[i] = pGroup->addflags[i];
}
}
return true;
}
unsigned int AdminCache::GetAdminGroupCount(AdminId id)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return 0;
}
return pUser->grp_count;
}
GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count)
{
return INVALID_GROUP_ID;
}
int *table = (int *)m_pMemory->GetAddress(pUser->grp_table);
return table[index];
}
const char *AdminCache::GetAdminPassword(AdminId id)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return NULL;
}
return m_pStrings->GetString(pUser->password);
}
void AdminCache::SetAdminPassword(AdminId id, const char *password)
{
AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
if (!pUser || pUser->magic != USR_MAGIC_SET)
{
return;
}
pUser->password = m_pStrings->AddString(password);
}

View File

@ -17,6 +17,7 @@
#include "sm_memtable.h"
#include <sm_trie.h>
#include <sh_list.h>
#include <sh_string.h>
#include <IAdminSystem.h>
#include "sm_globals.h"
#include <IForwardSys.h>
@ -25,6 +26,8 @@ using namespace SourceHook;
#define GRP_MAGIC_SET 0xDEADFADE
#define GRP_MAGIC_UNSET 0xFACEFACE
#define USR_MAGIC_SET 0xDEADFACE
#define USR_MAGIC_UNSET 0xFADEDEAD
struct AdminGroup
{
@ -44,6 +47,35 @@ struct AdminGroup
bool addflags[AdminFlags_TOTAL]; /* Additive flags */
};
struct AuthMethod
{
String name;
Trie *table;
};
struct UserAuth
{
unsigned int index; /* Index into auth table */
int identidx; /* Index into the string table */
};
struct AdminUser
{
int magic; /* Magic flag, for memory validation */
bool flags[AdminFlags_TOTAL]; /* Base flags */
bool eflags[AdminFlags_TOTAL]; /* Effective flags */
int nameidx; /* Name index */
int password; /* Password index */
unsigned int grp_count; /* Number of groups */
unsigned int grp_size; /* Size of groups table */
int grp_table; /* Group table itself */
int next_user; /* Next user in ze list */
int prev_user; /* Prev user in the list */
unsigned int auth_count; /* Number of auth methods */
unsigned int auth_size; /* Size of auth table */
int auth_table; /* Auth table itself */
};
class AdminCache :
public IAdminSystem,
public SMGlobalClass
@ -52,6 +84,7 @@ public:
AdminCache();
~AdminCache();
public: //SMGlobalClass
void OnSourceModStartup(bool late);
void OnSourceModAllInitialized();
void OnSourceModShutdown();
public: //IAdminSystem
@ -76,6 +109,21 @@ public: //IAdminSystem
void DumpAdminCache(int cache_flags, bool rebuild);
void AddAdminListener(IAdminListener *pListener);
void RemoveAdminListener(IAdminListener *pListener);
/** User stuff */
void RegisterAuthIdentType(const char *name);
AdminId CreateAdmin(const char *name);
const char *GetAdminName(AdminId id);
bool BindAdminIdentity(AdminId id, const char *auth, const char *ident);
virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled);
bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode);
unsigned int GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode);
bool AdminInheritGroup(AdminId id, GroupId gid);
unsigned int GetAdminGroupCount(AdminId id);
GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name);
void SetAdminPassword(AdminId id, const char *password);
const char *GetAdminPassword(AdminId id);
AdminId FindAdminByIdentity(const char *auth, const char *identity);
bool InvalidateAdmin(AdminId id);
private:
void _AddCommandOverride(const char *cmd, AdminFlag flag);
void _AddCommandGroupOverride(const char *group, AdminFlag flag);
@ -84,7 +132,9 @@ private:
void _UnsetCommandOverride(const char *cmd);
void _UnsetCommandGroupOverride(const char *group);
void InvalidateGroupCache();
void InvalidateAdminCache(bool unlink_admins);
void DumpCommandOverrideCache(OverrideType type);
Trie *GetMethodByIndex(unsigned int index);
public:
BaseStringTable *m_pStrings;
BaseMemTable *m_pMemory;
@ -95,7 +145,12 @@ public:
int m_FreeGroupList;
Trie *m_pGroups;
List<IAdminListener *> m_hooks;
List<AuthMethod> m_AuthMethods;
Trie *m_pAuthTables;
IForward *m_pCacheFwd;
int m_FirstUser;
int m_LastUser;
int m_FreeUserList;
};
extern AdminCache g_Admins;

View File

@ -39,6 +39,8 @@ public:
* begin at the first index again.
*/
void Reset();
private:
unsigned char *membase;
unsigned int size;

View File

@ -43,6 +43,8 @@
* 3] An override table - insertion and retrieval only.
* Individual groups can be invalidated entirely. It should be considered an expensive
* operation, since each admin needs to be patched up to not reference the group.
*
* For more information, see the SourceMod Development wiki.
*/
namespace SourceMod
@ -98,11 +100,25 @@ namespace SourceMod
Immunity_Global, /**< Immune from everyone (except root admins) */
};
/**
* @brief Defines user access modes.
*/
enum AccessMode
{
Access_Real, /**< Access the user has inherently */
Access_Effective, /**< Access the user has from their groups */
};
/**
* @brief Represents an index to one group.
*/
typedef int GroupId;
/**
* @brief Represents an index to one user entry.
*/
typedef int AdminId;
#define ADMIN_CACHE_OVERRIDES (1<<0)
#define ADMIN_CACHE_ADMINS (1<<1)
#define ADMIN_CACHE_GROUPS ((1<<2)|ADMIN_CACHE_ADMINS)
@ -112,6 +128,11 @@ namespace SourceMod
*/
#define INVALID_GROUP_ID -1
/**
* @brief Represents an invalid/nonexistant user or an erroneous operation.
*/
#define INVALID_ADMIN_ID -1
/**
* @brief Provides callbacks for admin cache operations.
*/
@ -315,6 +336,140 @@ namespace SourceMod
* @param pListener Pointer to an IAdminListener to remove.
*/
virtual void RemoveAdminListener(IAdminListener *pListener) =0;
/**
* @brief Registers an authentication identity type.
* Note: Default types are "steam," "name," and "ip."
*
* @param name String containing the type name.
*/
virtual void RegisterAuthIdentType(const char *name) =0;
/**
* @brief Creates a new user entry.
*
* @param name Name for this entry (does not have to be unique).
* Specify NULL for an anonymous admin.
* @return A new AdminId index.
*/
virtual AdminId CreateAdmin(const char *name) =0;
/**
* @brief Gets an admin's user name.
*
* @param id AdminId index for this admin.
* @return A string containing the admin's name, or NULL
* if the admin was created anonymously.
*/
virtual const char *GetAdminName(AdminId id) =0;
/**
* @brief Binds a user entry to a particular auth method.
* This bind must be unique.
*
* @param id AdminId index of the admin.
* @param auth Auth method to use.
* @param ident Identity string to bind to.
* @return True on success, false if auth method was not found,
* id was invalid, or ident was already taken.
*/
virtual bool BindAdminIdentity(AdminId id, const char *auth, const char *ident) =0;
/**
* @brief Sets whether or not a flag is enabled on an admin.
*
* @param id AdminId index of the admin.
* @param flag Admin flag to use.
* @param enabled True to enable, false to disable.
*/
virtual void SetAdminFlag(AdminId id, AdminFlag flag, bool enabled) =0;
/**
* @brief Returns whether or not a flag is enabled on an admin.
*
* @param id AdminId index of the admin.
* @param flag Admin flag to use.
* @param mode Access mode to check.
* @return True if enabled, false otherwise.
*/
virtual bool GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode) =0;
/**
* @brief Returns a bitarray of flags enabled on an admin.
*
* @param id AdminId index of the admin.
* @param flag Array to store flag bits in.
* @param total Maximum size of the flag array.
* @param mode Access mode to use.
* @return Number of flags written to the array.
*/
virtual unsigned int GetAdminFlags(AdminId id,
bool flags[],
unsigned int total,
AccessMode mode) =0;
/**
* @brief Adds a group to an admin's inherited group list.
* Any flags the group has will be added to the admin's effective flags.
*
* @param id AdminId index of the admin.
* @param gid GroupId index of the group.
* @return True on success, false on invalid input or duplicate membership.
*/
virtual bool AdminInheritGroup(AdminId id, GroupId gid) =0;
/**
* @brief Returns the number of groups this admin is a member of.
*
* @param id AdminId index of the admin.
* @return Number of groups this admin is a member of.
*/
virtual unsigned int GetAdminGroupCount(AdminId id) =0;
/**
* @brief Returns group information from an admin.
*
* @param id AdminId index of the admin.
* @param index Group number to retrieve, from 0 to N-1, where N
* is the value of GetAdminGroupCount(id).
* @param name Optional pointer to store the group's name.
* @return A GroupId index and a name pointer, or
* INVALID_GROUP_ID and NULL if an error occurred.
*/
virtual GroupId GetAdminGroup(AdminId id, unsigned int index, const char **name) =0;
/**
* @brief Sets a password on an admin.
*
* @param id AdminId index of the admin.
* @param passwd String containing the password.
*/
virtual void SetAdminPassword(AdminId id, const char *password) =0;
/**
* @brief Gets an admin's password.
*
* @param id AdminId index of the admin.
* @return Password of the admin, or NULL if none.
*/
virtual const char *GetAdminPassword(AdminId id) =0;
/**
* @brief Attempts to find an admin by an auth method and an identity.
*
* @param auth Auth method to try.
* @param identity Identity string to look up.
* @return An AdminId index if found, INVALID_ADMIN_ID otherwise.
*/
virtual AdminId FindAdminByIdentity(const char *auth, const char *identity) =0;
/**
* @brief Invalidates an admin from the cache so its resources can be re-used.
*
* @param id AdminId index to invalidate.
* @return True on success, false otherwise.
*/
virtual bool InvalidateAdmin(AdminId id) =0;
};
};