8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

Implemented CORE-4607: Add support for having >1 UserManager in firebird.conf and use them from SQL

This commit is contained in:
alexpeshkoff 2014-12-24 14:50:03 +00:00
parent 9d7e0813f1
commit df0ecdac9a
13 changed files with 199 additions and 78 deletions

View File

@ -823,6 +823,28 @@ namespace Firebird
bool operator>=(const char_type* str) const {return compare(str) >= 0;}
bool operator> (const char_type* str) const {return compare(str) > 0;}
bool operator!=(const char_type* str) const {return different(str);}
bool getWord(StringType& from, const char* sep)
{
from.alltrim(sep);
size_type p = from.find_first_of(sep);
if (p == npos)
{
if (from.isEmpty())
{
*this = "";
return false;
}
*this = from;
from = "";
return true;
}
*this = from.substr(0, p);
from = from.substr(p);
from.ltrim(sep);
return true;
}
};
typedef StringBase<StringComparator> string;

View File

@ -50,6 +50,15 @@ Get::Get(Config* firebirdConf)
}
}
Get::Get(const char* plugName)
: GetPlugins<Firebird::IManagement>(IPluginManager::AuthUserManagement, plugName)
{
if (!hasData())
{
raise();
}
}
void UserData::clear(Firebird::IStatus*)
{
op = 0;

View File

@ -28,6 +28,7 @@
#include "../common/classes/ImplementHelper.h"
#include "../common/classes/GetPlugins.h"
#include "../common/classes/array.h"
#include "../common/classes/MetaName.h"
namespace Auth {
@ -218,6 +219,8 @@ public:
CharField database, dba, dbaPassword, role;
AuthenticationBlock authenticationBlock;
Firebird::MetaName plugin;
// deprecated
CharField group;
IntField u, g;
@ -252,6 +255,7 @@ class Get : public Firebird::GetPlugins<Firebird::IManagement>
{
public:
Get(Config* firebirdConf);
Get(const char* plugName);
};
int setGsecCode(int code, Firebird::IUser* iUser);

View File

@ -10259,6 +10259,8 @@ void CreateAlterUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
setCharField(userData->middle, middleName);
setCharField(userData->last, lastName);
setCharField(userData->com, comment);
if (plugin)
userData->plugin = *plugin;
if (adminRole.specified)
{
@ -10340,6 +10342,7 @@ void DropUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jr
userData->op = Auth::DEL_OPER;
userData->user.set(&s, text.c_str());
userData->user.setEntered(&s, 1);
userData->plugin = plugin;
check(&s);
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_DROP_USER,

View File

@ -1905,6 +1905,7 @@ public:
firstName(NULL),
middleName(NULL),
lastName(NULL),
plugin(NULL),
comment(NULL),
mode(md)
{ }
@ -1940,6 +1941,7 @@ public:
Firebird::string* firstName;
Firebird::string* middleName;
Firebird::string* lastName;
Firebird::MetaName* plugin;
Firebird::string* comment;
Nullable<bool> adminRole;
Nullable<bool> active;
@ -1962,10 +1964,13 @@ public:
class DropUserNode : public DdlNode
{
public:
DropUserNode(MemoryPool& p, const Firebird::MetaName& aName)
DropUserNode(MemoryPool& p, const Firebird::MetaName& aName, const Firebird::MetaName* aPlugin = NULL)
: DdlNode(p),
name(p, aName)
name(p, aName),
plugin(p)
{
if (aPlugin)
plugin = *aPlugin;
}
public:
@ -1981,6 +1986,7 @@ protected:
public:
Firebird::MetaName name;
Firebird::MetaName plugin;
};

View File

@ -4019,6 +4019,8 @@ drop_clause
{ $$ = newNode<DropSequenceNode>(*$2); }
| COLLATION symbol_collation_name
{ $$ = newNode<DropCollationNode>(*$2); }
| USER symbol_user_name USING PLUGIN valid_symbol_name
{ $$ = newNode<DropUserNode>(*$2, $5); }
| USER symbol_user_name
{ $$ = newNode<DropUserNode>(*$2); }
| PACKAGE symbol_package_name
@ -6202,6 +6204,8 @@ user_fixed_opt($node)
| REVOKE ADMIN ROLE { setClause($node->adminRole, "ADMIN ROLE", Nullable<bool>(false)); }
| ACTIVE { setClause($node->active, "ACTIVE/INACTIVE", Nullable<bool>(true)); }
| INACTIVE { setClause($node->active, "ACTIVE/INACTIVE", Nullable<bool>(false)); }
| USING PLUGIN valid_symbol_name
{ setClause($node->plugin, "USING PLUGIN", $3); }
;
%type user_var_opts(<createAlterUserNode>)

View File

@ -625,6 +625,7 @@
const USHORT f_sec_active = 4;
const USHORT f_sec_admin = 5;
const USHORT f_sec_comment = 6;
const USHORT f_sec_plugin = 7;
// Relation 44 (SEC$USER_ATTRIBUTES)

View File

@ -80,17 +80,17 @@ namespace
{
public:
explicit FillSnapshot(UserManagement* um)
: userManagement(um)
: userManagement(um), pos(0)
{ }
// IListUsers implementation
void list(IStatus* status, Firebird::IUser* user)
void list(IStatus* status, IUser* user)
{
try
{
userManagement->list(user);
userManagement->list(user, pos);
}
catch (const Firebird::Exception& ex)
catch (const Exception& ex)
{
ex.stuffException(status);
}
@ -98,6 +98,9 @@ namespace
private:
UserManagement* userManagement;
public:
unsigned pos;
};
class OldAttributes : public AutoIface<Api::IListUsersImpl<OldAttributes> >
@ -108,14 +111,14 @@ namespace
{ }
// IListUsers implementation
void list(IStatus* status, Firebird::IUser* data)
void list(IStatus* status, IUser* data)
{
try
{
value = data->attributes()->entered() ? data->attributes()->get() : "";
present = true;
}
catch (const Firebird::Exception& ex)
catch (const Exception& ex)
{
ex.stuffException(status);
}
@ -145,28 +148,97 @@ UserManagement::UserManagement(jrd_tra* tra)
: SnapshotData(*tra->tra_pool),
threadDbb(NULL),
commands(*tra->tra_pool),
manager(NULL)
managers(*tra->tra_pool),
plugins(*tra->tra_pool),
att(tra->tra_attachment)
{
Attachment* att = tra->tra_attachment;
if (!att || !att->att_user)
{
(Arg::Gds(isc_random) << "Unknown user name for given transaction").raise();
}
fb_assert(att->att_database && att->att_database->dbb_config.hasData());
Auth::Get getPlugin(att->att_database->dbb_config);
manager = getPlugin.plugin();
fb_assert(manager);
manager->addRef();
plugins = att->att_database->dbb_config->getPlugins(IPluginManager::AuthUserManagement);
}
IManagement* UserManagement::registerManager(Auth::Get& getPlugin, const char* plugName)
{
IManagement* manager = getPlugin.plugin();
fb_assert(manager);
// Start new management plugin ...
LocalStatus status;
UserIdInfo idInfo(att);
manager->start(&status, &idInfo);
if (status.getStatus() & IStatus::FB_HAS_ERRORS)
{
status_exception::raise(&status);
}
// ... and store it in cache
Manager& m(managers.add());
m.first = plugName;
m.second = manager;
manager->addRef();
return manager;
}
IManagement* UserManagement::getManager(const char* name)
{
// Determine required name
NoCaseString plugName;
NoCaseString p(plugins);
if (!(name && name[0])) // Use default plugin
plugName.getWord(p, " \t,;");
else
{
while (plugName.getWord(p, " \t,;"))
{
if (plugName == name)
break;
}
}
if (!plugName.hasData())
{
(Arg::Gds(isc_random) << "Missing requested management plugin").raise();
}
// Search for it in cache of already loaded plugins
for (unsigned i = 0; i < managers.getCount(); ++i)
{
if (plugName == managers[i].first.c_str())
return managers[i].second;
}
// We have new user manager plugin
Auth::Get getPlugin(plugName.c_str());
return registerManager(getPlugin, plugName.c_str());
}
void UserManagement::openAllManagers()
{
NoCaseString plugName;
NoCaseString p(plugins);
while (plugName.getWord(p, " \t,;"))
{
// Search for it in cache of already loaded plugins
bool flag = false;
for (unsigned i = 0; i < managers.getCount(); ++i)
{
if (plugName == managers[i].first.c_str())
{
flag = true;
break;
}
}
if (flag)
continue;
Auth::Get getPlugin(plugName.c_str());
registerManager(getPlugin, plugName.c_str());
}
}
UserManagement::~UserManagement()
@ -177,34 +249,37 @@ UserManagement::~UserManagement()
}
commands.clear();
if (manager)
for (unsigned i = 0; i < managers.getCount(); ++i)
{
LocalStatus status;
manager->rollback(&status);
PluginManagerInterfacePtr()->releasePlugin(manager);
manager = NULL;
if (status.getStatus() & IStatus::FB_HAS_ERRORS)
IManagement* manager = managers[i].second;
if (manager)
{
status_exception::raise(&status);
LocalStatus status;
manager->rollback(&status);
PluginManagerInterfacePtr()->releasePlugin(manager);
managers[i].second = NULL;
// if (status.getStatus() & IStatus::FB_HAS_ERRORS)
// status_exception::raise(&status);
}
}
}
void UserManagement::commit()
{
if (manager)
for (unsigned i = 0; i < managers.getCount(); ++i)
{
LocalStatus status;
manager->commit(&status);
if (status.getStatus() & IStatus::FB_HAS_ERRORS)
IManagement* manager = managers[i].second;
if (manager)
{
status_exception::raise(&status);
}
LocalStatus status;
manager->commit(&status);
if (status.getStatus() & IStatus::FB_HAS_ERRORS)
status_exception::raise(&status);
PluginManagerInterfacePtr()->releasePlugin(manager);
manager = NULL;
PluginManagerInterfacePtr()->releasePlugin(manager);
managers[i].second = NULL;
}
}
}
@ -219,8 +294,8 @@ USHORT UserManagement::put(Auth::DynamicUserData* userData)
return ret;
}
void UserManagement::checkSecurityResult(int errcode, Firebird::IStatus* status,
const char* userName, Firebird::IUser* user)
void UserManagement::checkSecurityResult(int errcode, IStatus* status,
const char* userName, IUser* user)
{
if (!errcode)
{
@ -256,14 +331,16 @@ void UserManagement::execute(USHORT id)
status_exception::raise(Arg::Gds(isc_random) << "Wrong job id passed to UserManagement::execute()");
}
if (!(manager && commands[id]))
{
// Already executed.
return;
}
if (!commands[id])
return; // Already executed
Auth::UserData* command = commands[id];
IManagement* manager = getManager(command->plugin.c_str());
if (!manager)
return; // Already commited
LocalStatus status;
Auth::UserData* command = commands[id];
if (command->attr.entered() || command->op == Auth::ADDMOD_OPER)
{
Auth::StackUserData cmd;
@ -372,7 +449,7 @@ void UserManagement::execute(USHORT id)
commands[id] = NULL;
}
void UserManagement::list(Firebird::IUser* u)
void UserManagement::list(IUser* u, unsigned cachePosition)
{
RecordBuffer* buffer = getData(rel_sec_users);
Record* record = buffer->getTempRecord();
@ -380,6 +457,11 @@ void UserManagement::list(Firebird::IUser* u)
int charset = CS_METADATA;
const MetaName& plugName(managers[cachePosition].first);
putField(threadDbb, record,
DumpField(f_sec_plugin, VALUE_STRING, static_cast<USHORT>(plugName.length()), plugName.c_str()),
charset);
if (u->userName()->entered())
{
putField(threadDbb, record,
@ -474,18 +556,22 @@ RecordBuffer* UserManagement::getList(thread_db* tdbb, jrd_rel* relation)
try
{
openAllManagers();
threadDbb = tdbb;
MemoryPool* const pool = threadDbb->getTransaction()->tra_pool;
allocBuffer(threadDbb, *pool, rel_sec_users);
allocBuffer(threadDbb, *pool, rel_sec_user_attributes);
FillSnapshot fillSnapshot(this);
for (FillSnapshot fillSnapshot(this); fillSnapshot.pos < managers.getCount(); ++fillSnapshot.pos)
{
LocalStatus status;
Auth::StackUserData u;
u.op = Auth::DIS_OPER;
LocalStatus status;
Auth::StackUserData u;
u.op = Auth::DIS_OPER;
int errcode = manager->execute(&status, &u, &fillSnapshot);
checkSecurityResult(errcode, &status, "Unknown", &u);
int errcode = managers[fillSnapshot.pos].second->execute(&status, &u, &fillSnapshot);
checkSecurityResult(errcode, &status, "Unknown", &u);
}
}
catch (const Exception&)
{

View File

@ -24,7 +24,7 @@
#define JRD_USER_MANAGEMENT_H
#include "firebird.h"
#include "../common/classes/array.h"
#include "../common/classes/objects_array.h"
#include "../common/classes/fb_string.h"
#include "../jrd/ibase.h"
#include "../jrd/Monitoring.h"
@ -67,13 +67,19 @@ public:
// return users list for SEC$USERS
RecordBuffer* getList(thread_db* tdbb, jrd_rel* relation);
// callback for users display
void list(Firebird::IUser* u);
void list(Firebird::IUser* u, unsigned cachePosition);
private:
thread_db* threadDbb;
Firebird::HalfStaticArray<Auth::DynamicUserData*, 8> commands;
Firebird::IManagement* manager;
typedef Firebird::Pair<Firebird::NonPooled<Firebird::MetaName, Firebird::IManagement*> > Manager;
Firebird::ObjectsArray<Manager> managers;
Firebird::NoCaseString plugins;
Attachment* att;
Firebird::IManagement* getManager(const char* name);
void openAllManagers();
Firebird::IManagement* registerManager(Auth::Get& getPlugin, const char* plugName);
static void checkSecurityResult(int errcode, Firebird::IStatus* status,
const char* userName, Firebird::IUser* user);
};

View File

@ -122,6 +122,7 @@
FIELD(fld_scn , nam_scn , dtype_long , sizeof(SLONG) , 0 , NULL , true)
FIELD(fld_specific_attr , nam_specific_attr , dtype_blob , BLOB_SIZE , isc_blob_text , NULL , true)
FIELD(fld_plugin_name , nam_plugin , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true)
FIELD(fld_r_type , nam_r_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true)
FIELD(fld_prc_type , nam_prc_type , dtype_short , sizeof(SSHORT) , 0 , NULL , true)
@ -183,7 +184,6 @@
FIELD(fld_map_name , nam_map_name , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false)
FIELD(fld_map_using , nam_map_using , dtype_text , 1 , dsc_text_type_metadata , NULL , false)
FIELD(fld_map_plugin , nam_map_plugin , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true)
FIELD(fld_map_db , nam_map_db , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , true)
FIELD(fld_map_from_type , nam_map_from_type , dtype_text , MAX_SQL_IDENTIFIER_LEN , dsc_text_type_metadata , NULL , false)
FIELD(fld_map_from , nam_map_from , dtype_text , 255 , dsc_text_type_metadata , NULL , true)

View File

@ -276,6 +276,8 @@ NAME("SEC$NAME_PART", nam_name_part)
NAME("SEC$ACTIVE", nam_sec_active)
NAME("SEC$ADMIN", nam_sec_admin)
NAME("SEC$DESCRIPTION", nam_sec_description)
NAME("RDB$PLUGIN", nam_plugin)
NAME("SEC$PLUGIN", nam_sec_plugin)
NAME("MON$ATTACHMENTS", nam_mon_attachments)
NAME("MON$ATTACHMENT_ID", nam_mon_att_id)

View File

@ -624,6 +624,7 @@ RELATION(nam_sec_users, rel_sec_users, ODS_12_0, rel_virtual)
FIELD(f_sec_active, nam_sec_active, fld_bool, 0, ODS_12_0)
FIELD(f_sec_admin, nam_sec_admin, fld_bool, 0, ODS_12_0)
FIELD(f_sec_comment, nam_sec_description, fld_description, 0, ODS_12_0)
FIELD(f_sec_plugin, nam_sec_plugin, fld_plugin_name, 0, ODS_12_0)
END_RELATION
// Relation 44 (SEC$USER_ATTRIBUTES)
@ -637,7 +638,7 @@ END_RELATION
RELATION(nam_auth_mapping, rel_auth_mapping, ODS_12_0, rel_persistent)
FIELD(f_map_name, nam_map_name, fld_map_name, 1, ODS_12_0)
FIELD(f_map_using, nam_map_using, fld_map_using, 1, ODS_12_0)
FIELD(f_map_plugin, nam_map_plugin, fld_map_plugin, 1, ODS_12_0)
FIELD(f_map_plugin, nam_map_plugin, fld_plugin_name, 1, ODS_12_0)
FIELD(f_map_db, nam_map_db, fld_map_db, 1, ODS_12_0)
FIELD(f_map_from_type, nam_map_from_type, fld_map_from_type, 1, ODS_12_0)
FIELD(f_map_from, nam_map_from, fld_map_from, 1, ODS_12_0)
@ -651,7 +652,7 @@ END_RELATION
RELATION(nam_sec_global_auth_mapping, rel_global_auth_mapping, ODS_12_0, rel_virtual)
FIELD(f_sec_map_name, nam_sec_map_name, fld_map_name, 0, ODS_12_0)
FIELD(f_sec_map_using, nam_sec_map_using, fld_map_using, 0, ODS_12_0)
FIELD(f_sec_map_plugin, nam_sec_map_plugin, fld_map_plugin, 0, ODS_12_0)
FIELD(f_sec_map_plugin, nam_sec_map_plugin, fld_plugin_name, 0, ODS_12_0)
FIELD(f_sec_map_db, nam_sec_map_db, fld_map_db, 0, ODS_12_0)
FIELD(f_sec_map_from_type, nam_sec_map_from_type, fld_map_from_type, 0, ODS_12_0)
FIELD(f_sec_map_from, nam_sec_map_from, fld_map_from, 0, ODS_12_0)

View File

@ -54,27 +54,6 @@ using namespace Firebird;
namespace
{
void splitWord(PathName& to, PathName& list)
{
list.alltrim(" \t");
PathName::size_type p = list.find_first_of(" \t,;");
if (p == PathName::npos)
{
if (list.isEmpty())
{
to = "";
return;
}
to = list;
list = "";
return;
}
to = list.substr(0, p);
list = list.substr(p);
list.ltrim(" \t,;");
}
void changeExtension(PathName& file, const char* newExt)
{
PathName::size_type p = file.rfind(PathUtils::dir_sep);
@ -874,10 +853,8 @@ namespace
MutexLockGuard g(plugins->mutex, FB_FUNCTION);
while (namesList.hasData())
while (currentName.getWord(namesList, " \t,;"))
{
splitWord(currentName, namesList);
// First check - may be currentName is present among already configured plugins
ConfiguredPlugin* tmp = NULL;
if (plugins->get(MapKey(interfaceType, currentName), tmp))