1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-02-22 17:57:46 +03:00

Feature #687: Add DB persistence to ACL rules

This commit is contained in:
Carlos Martín 2011-06-27 18:41:16 +02:00
parent 94d1615e58
commit c1a0fa6f7d
5 changed files with 313 additions and 64 deletions

View File

@ -22,28 +22,69 @@
using namespace std;
class AclManager : public ObjectSQL
/**
* This class manages the ACL rules and the authorization engine
*/
class AclManager : public Callbackable
{
public:
AclManager(){};
AclManager(SqlDB * _db)
:db(_db)
{};
~AclManager();
/**
* Loads the ACL rule set from the DB
* @return 0 on success.
*/
int start();
/* ---------------------------------------------------------------------- */
/* Rule management */
/* ---------------------------------------------------------------------- */
/**
* Takes an authorization request and checks if any rule in the ACL
* authorizes the operation.
*
* @param uid The user ID requesting to be authorized
* @param user_groups Set of group IDs that the user is part of
* @param obj_type The object over which the operation will be performed
* @param obj_id The object ID
* @param obj_gid The object's group ID
* @param op The operation to be authorized
* @return true if the authorization is granted by any rule
*/
const bool authorize(int uid, const set<int> &user_groups,
AuthRequest::Object obj_type, int obj_id, int obj_gid,
AuthRequest::Operation op);
/* ---------------------------------------------------------------------- */
/**
* Adds a new rule to the ACL rule set
*
* @param user 64 bit ID and flags
* @param resource 64 bit ID and flags
* @param rights 64 bit flags
* @param error_str Returns the error reason, if any
* @return 0 on success
*/
int add_rule(long long user, long long resource, long long rights,
string& error_str);
/* ---------------------------------------------------------------------- */
/**
* Deletes a rule from the ACL rule set
*
* @param user 64 bit ID and flags
* @param resource 64 bit ID and flags
* @param rights 64 bit flags
* @param error_str Returns the error reason, if any
* @return 0 on success
*/
int del_rule(long long user, long long resource, long long rights,
string& error_str);
@ -52,55 +93,71 @@ public:
/* ---------------------------------------------------------------------- */
/**
* Callback function to unmarshall a PoolObjectSQL
* Bootstraps the database table(s) associated to the ACL Manager
*/
static void bootstrap(SqlDB * _db)
{
ostringstream oss(db_bootstrap);
_db->exec(oss);
};
/* ---------------------------------------------------------------------- */
/**
* Dumps the rule set in XML format.
* @param oss The output stream to dump the rule set contents
* @return 0 on success
*/
int dump(ostringstream& oss);
private:
multimap<long long, AclRule*> acl_rules;
// ----------------------------------------
// DataBase implementation variables
// ----------------------------------------
/**
* Pointer to the database.
*/
SqlDB * db;
static const char * table;
static const char * db_names;
static const char * db_bootstrap;
/**
* Callback function to unmarshall the ACL rules
* @param num the number of columns read from the DB
* @param names the column names
* @param vaues the column values
* @return 0 on success
*/
int select_cb(void *nil, int num, char **values, char **names)
{
if ( (!values[0]) || (num != 1) )
{
return -1;
}
// TODO: from_xml
return 0;
};
int select_cb(void *nil, int num, char **values, char **names);
/**
* Reads the ACL rule set from the database.
* @param db pointer to the db
* @return 0 on success
*/
int select(SqlDB *db)
{
return 0;
};
int select();
int insert(SqlDB*, std::string&)
{
return 0;
};
/**
* Inserts the ACL rule in the database.
* @param rule to insert
* @return 0 on success
*/
int insert(AclRule * rule);
int update(SqlDB*)
{
return 0;
};
int drop(SqlDB*)
{
return 0;
};
/* ---------------------------------------------------------------------- */
int dump(ostringstream& oss);
private:
multimap<long long, AclRule*> acl_rules;
/**
* Drops an ACL rule from the database
* @param rule to drop
* @return 0 on success
*/
int drop(AclRule * rule);
};
#endif /*ACL_MANAGER_H*/

View File

@ -23,6 +23,10 @@
using namespace std;
/**
* An ACL Rule is composed of three 64 bit numbers: user, resource and rights.
* These attributes store a combination of IDs and flags
*/
class AclRule
{
public:
@ -61,25 +65,59 @@ public:
return user < other.user;
};
/**
* Returns a human readable string for this rule
*
* @return a human readable string for this rule
*/
string to_str() const;
/**
* Function to print the object into a string in XML format
*
* @param xml the resulting XML string
* @return a reference to the generated string
*/
string& to_xml(string& xml) const;
/**
* Returns the 32 less significant bits of the user long long attribute
*
* @return the user or group ID
*/
int user_id() const
{
return user;
};
/**
* Returns the 64 bit user attribute with the ID cleared (the 32 less
* significant bits are set to 0)
*
* @return the user flags
*/
long long user_code() const
{
return user & 0xFFFFFFFF00000000LL;
};
/**
* Returns the 32 less significant bits of the resource long long attribute
*
* @return the resource ID
*/
int resource_id() const
{
return resource;
};
/**
* Returns the 64 bit resource attribute with the ID cleared (the 32 less
* significant bits are set to 0)
*
* @return the resource flags
*/
long long resource_code() const
{
return resource & 0xFFFFFFFF00000000LL;
@ -90,17 +128,19 @@ private:
friend class AclManager;
/**
*
* 64 bit integer holding a user ID in the 32 less significant bits,
* and a flag indicating the kind of ID in the other 32
*/
long long user;
/**
*
* 64 bit integer holding an object ID in the 32 less significant bits,
* and flags indicanting the kind of ID and object in the other 32
*/
long long resource;
/**
*
* 64 bit integer containing the rights flags
*/
long long rights;
};

View File

@ -20,6 +20,24 @@
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * AclManager::table = "acl";
const char * AclManager::db_names = "user, resource, rights";
const char * AclManager::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
"acl (user BIGINT, resource BIGINT, rights BIGINT)";
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::start()
{
return select();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
AclManager::~AclManager()
{
multimap<long long, AclRule *>::iterator it;
@ -105,7 +123,8 @@ int AclManager::add_rule(long long user, long long resource, long long rights,
{
AclRule * rule = new AclRule(user, resource, rights);
ostringstream oss;
ostringstream oss;
int rc;
multimap<long long, AclRule *>::iterator it;
pair<multimap<long long, AclRule *>::iterator,
@ -143,6 +162,14 @@ int AclManager::add_rule(long long user, long long resource, long long rights,
}
*/
rc = insert(rule);
if ( rc != 0 )
{
error_str = "Error inserting rule in DB";
return -1;
}
acl_rules.insert( make_pair(rule->user, rule) );
return 0;
@ -156,29 +183,26 @@ int AclManager::del_rule(long long user, long long resource, long long rights,
{
multimap<long long, AclRule *>::iterator it;
pair<multimap<long long, AclRule *>::iterator,
multimap<long long, AclRule *>::iterator> index;
multimap<long long, AclRule *>::iterator> index;
int rc;
bool found = false;
index = acl_rules.equal_range( user );
for ( it = index.first; (it != index.second && !found); it++)
it = index.first;
while ( !found && it != index.second )
{
if ( it->second->resource == resource &&
it->second->rights == rights )
{
delete it->second;
acl_rules.erase( it );
found = ( it->second->resource == resource &&
it->second->rights == rights );
found = true;
if ( !found )
{
it++;
}
}
if ( found )
{
return 0;
}
else
if ( !found )
{
AclRule rule(user, resource, rights);
@ -188,6 +212,121 @@ int AclManager::del_rule(long long user, long long resource, long long rights,
return -1;
}
rc = drop( it->second );
if ( rc != 0 )
{
error_str = "SQL DB error";
return -1;
}
delete it->second;
acl_rules.erase( it );
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::select_cb(void *nil, int num, char **values, char **names)
{
if ( (num != 3) ||
(!values[0]) ||
(!values[1]) ||
(!values[2]) )
{
return -1;
}
ostringstream oss;
istringstream iss;
long long rule_values[3];
for ( int i = 0; i < 3; i++ )
{
iss.str( values[i] );
iss >> rule_values[i];
if ( iss.fail() == true )
{
return -1;
}
iss.clear();
}
// TODO: Use add_rule() instead, to check possible errors, or assume
// that anything that was stored into the DB is trustworthy?
AclRule * rule = new AclRule(rule_values[0], rule_values[1], rule_values[2]);
oss << "Loading ACL Rule " << rule->to_str();
NebulaLog::log("ACL",Log::DEBUG,oss);
acl_rules.insert( make_pair(rule->user, rule) );
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::select()
{
ostringstream oss;
int rc;
oss << "SELECT " << db_names << " FROM " << table;
set_callback(static_cast<Callbackable::Callback>(&AclManager::select_cb));
rc = db->exec(oss,this);
unset_callback();
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::insert(AclRule * rule)
{
ostringstream oss;
int rc;
// Construct the SQL statement to Insert
oss << "INSERT INTO " << table <<" ("<< db_names <<") VALUES ("
<< rule->user << ","
<< rule->resource << ","
<< rule->rights << ")";
rc = db->exec(oss);
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::drop(AclRule * rule)
{
ostringstream oss;
int rc;
oss << "DELETE FROM " << table << " WHERE "
<< "user=" << rule->user << "AND"
<< "resource=" << rule->resource << "AND"
<< "rights=" << rule->rights;
rc = db->exec(oss);
return rc;
}
/* -------------------------------------------------------------------------- */

View File

@ -16,7 +16,6 @@
#include "AclRule.h"
#include "AuthManager.h"
#include "NebulaLog.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -133,14 +132,13 @@ string& AclRule::to_xml(string& xml) const
oss <<
"<RULE>"
"<USER>" << hex << user << "</USER>" <<
"<RESOURCE>" << hex << resource << "</RESOURCE>" <<
"<RIGHTS>" << hex << rights << "</RIGHTS>" <<
"<USER>" << hex << user << "</USER>" <<
"<RESOURCE>" << hex << resource << "</RESOURCE>" <<
"<RIGHTS>" << hex << rights << "</RIGHTS>" <<
// TODO: Element DEBUG contains a human friendly string
"<DEBUG>" << to_str() << "</DEBUG>" <<
"</RULE>";
// TODO: Element DEBUG contains a human friendly string
"<DEBUG>" << to_str() << "</DEBUG>" <<
"</RULE>";
xml = oss.str();

View File

@ -247,6 +247,7 @@ void Nebula::start()
UserPool::bootstrap(db);
ImagePool::bootstrap(db);
VMTemplatePool::bootstrap(db);
AclManager::bootstrap(db);
}
}
catch (exception&)
@ -516,7 +517,21 @@ void Nebula::start()
}
// ---- ACL Manager ----
aclm = new AclManager();
try
{
aclm = new AclManager(db);
}
catch (bad_alloc&)
{
throw;
}
rc = aclm->start();
if ( rc != 0 )
{
throw runtime_error("Could not start the ACL Manager");
}
// ---- Image Manager ----
try