1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-30 22:50:10 +03:00

Feature #687: Add oid to ACL Rules, one.acl.delrule now expects that ID. Modify XML to look similar to a pool

This commit is contained in:
Carlos Martín 2011-06-29 18:41:49 +02:00
parent 3543b4c209
commit 165a8fb74b
8 changed files with 251 additions and 96 deletions

View File

@ -28,9 +28,7 @@ using namespace std;
class AclManager : public Callbackable
{
public:
AclManager(SqlDB * _db)
:db(_db)
{};
AclManager(SqlDB * _db);
~AclManager();
@ -69,7 +67,11 @@ public:
* @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
*
* @return the oid assigned to the rule on success,
* -1 if the rule exists,
* -2 if the rule is malformed,
* -3 if the DB insert failed
*/
int add_rule(long long user, long long resource, long long rights,
string& error_str);
@ -79,14 +81,11 @@ public:
/**
* 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 oid Rule id
* @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);
int del_rule(int oid, string& error_str);
/* ---------------------------------------------------------------------- */
/* DB management */
@ -112,8 +111,18 @@ public:
int dump(ostringstream& oss);
private:
/**
* ACL rules. Each rule is indexed by its 'user' long long attibute,
* several rules can apply to the same user
*/
multimap<long long, AclRule*> acl_rules;
/**
* Rules indexed by oid. Stores the same rules as acl_rules
*/
map<int, AclRule *> acl_rules_oids;
/**
* Gets all rules that apply to the user_req and, if any of them grants
* permission, returns true.
@ -146,12 +155,25 @@ private:
*/
SqlDB * db;
/**
* Last object ID assigned to a rule.
*/
int lastOID;
/**
* Tablename for the ACL rules
*/
static const char * table;
static const char * db_names;
static const char * db_bootstrap;
/**
* Inserts the last oid into the pool_control table
*/
void update_lastOID();
/**
* Callback function to unmarshall the ACL rules
* @param num the number of columns read from the DB
@ -177,10 +199,16 @@ private:
/**
* Drops an ACL rule from the database
* @param rule to drop
*
* @param oid Rule id
* @return 0 on success
*/
int drop(AclRule * rule);
int drop(int oid);
/**
* Callback to set the lastOID
*/
int init_cb(void *nil, int num, char **values, char **names);
};
#endif /*ACL_MANAGER_H*/

View File

@ -35,8 +35,8 @@ public:
static const long long GROUP_ID;
static const long long ALL_ID;
AclRule(long long _user, long long _resource, long long _rights):
user(_user), resource(_resource), rights(_rights)
AclRule(int _oid, long long _user, long long _resource, long long _rights):
oid(_oid), user(_user), resource(_resource), rights(_rights)
{
build_str();
};
@ -120,6 +120,11 @@ private:
friend class AclManager;
/**
* Rule unique identifier
*/
int oid;
/**
* 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

View File

@ -41,21 +41,10 @@ protected:
/* -------------------------------------------------------------------- */
virtual void request_execute(xmlrpc_c::paramList const& _paramList);
virtual void request_execute(xmlrpc_c::paramList const& _paramList) = 0;
/* -------------------------------------------------------------------- */
virtual int perform_operation(string& error_msg)
{
return 0;
};
/* -------------------------------------------------------------------- */
long long user;
long long resource;
long long rights;
AclManager * aclm;
};
@ -75,7 +64,7 @@ public:
~AclAddRule(){};
int perform_operation(string& error_msg);
void request_execute(xmlrpc_c::paramList const& _paramList);
};
/* ------------------------------------------------------------------------- */
@ -87,14 +76,14 @@ public:
AclDelRule():
RequestManagerAcl("AclDelRule",
"Deletes an existing ACL rule",
"A:ssss")
"A:si")
{
// TODO: auth_op ?
};
~AclDelRule(){};
int perform_operation(string& error_msg);
void request_execute(xmlrpc_c::paramList const& _paramList);
};
/* ------------------------------------------------------------------------- */

View File

@ -14,6 +14,8 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include <climits>
#include "AclManager.h"
#include "NebulaLog.h"
@ -22,10 +24,46 @@
const char * AclManager::table = "acl";
const char * AclManager::db_names = "user, resource, rights";
const char * AclManager::db_names = "oid, user, resource, rights";
const char * AclManager::db_bootstrap = "CREATE TABLE IF NOT EXISTS "
"acl (user BIGINT, resource BIGINT, rights BIGINT)";
"acl (oid INT PRIMARY KEY, user BIGINT, resource BIGINT, rights BIGINT)";
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::init_cb(void *nil, int num, char **values, char **names)
{
lastOID = -1;
if ( values[0] != 0 )
{
lastOID = atoi(values[0]);
}
return 0;
}
/* -------------------------------------------------------------------------- */
AclManager::AclManager(SqlDB * _db) :
db(_db), lastOID(-1)
{
ostringstream oss;
// TODO:
// pthread_mutex_init(&mutex, 0);
set_callback(static_cast<Callbackable::Callback> (&AclManager::init_cb));
oss << "SELECT last_oid FROM pool_control WHERE tablename='" << table
<< "'";
db->exec(oss, this);
unset_callback();
}
;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -78,7 +116,8 @@ const bool AclManager::authorize(int uid, const set<int> &user_groups,
AclRule request_rule(AclRule::INDIVIDUAL_ID + uid, resource_oid_req, rights_req);
AclRule request_rule(-1, AclRule::INDIVIDUAL_ID + uid, resource_oid_req,
rights_req);
oss << "Request " << request_rule.to_str();
NebulaLog::log("ACL",Log::DEBUG,oss);
@ -193,7 +232,12 @@ bool AclManager::match_rules(
int AclManager::add_rule(long long user, long long resource, long long rights,
string& error_str)
{
AclRule * rule = new AclRule(user, resource, rights);
if (lastOID == INT_MAX)
{
lastOID = -1;
}
AclRule * rule = new AclRule(++lastOID, user, resource, rights);
ostringstream oss;
int rc;
@ -218,20 +262,12 @@ int AclManager::add_rule(long long user, long long resource, long long rights,
if ( found )
{
oss << "Rule " << rule->to_str() << " already exists";
error_str = oss.str();
delete rule;
return -1;
goto error_duplicated;
}
if ( rule->malformed(error_str) )
{
oss << "Rule " << rule->to_str() << " is malformed: " << error_str;
error_str = oss.str();
delete rule;
return -2;
goto error_malformed;
}
@ -239,35 +275,84 @@ int AclManager::add_rule(long long user, long long resource, long long rights,
if ( rc != 0 )
{
error_str = "Error inserting rule in DB";
return -1;
goto error_insert;
}
acl_rules.insert( make_pair(rule->user, rule) );
acl_rules_oids.insert( make_pair(rule->oid, rule) );
return 0;
update_lastOID();
return lastOID;
error_duplicated:
oss << "Rule " << rule->to_str() << " already exists";
rc = -1;
goto error_common;
error_malformed:
oss << "Rule " << rule->to_str() << " is malformed: " << error_str;
rc = -2;
goto error_common;
error_insert:
oss << "Error inserting rule in DB";
rc = -3;
goto error_common;
error_common:
error_str = oss.str();
delete rule;
lastOID--;
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::del_rule(long long user, long long resource, long long rights,
string& error_str)
int AclManager::del_rule(int oid, string& error_str)
{
multimap<long long, AclRule *>::iterator it;
pair<multimap<long long, AclRule *>::iterator,
multimap<long long, AclRule *>::iterator> index;
int rc;
bool found = false;
AclRule * rule;
int rc;
bool found = false;
index = acl_rules.equal_range( user );
// Check the rule exists
found = acl_rules_oids.count(oid) > 0;
if ( !found )
{
ostringstream oss;
oss << "Rule " << oid << " does not exist";
error_str = oss.str();
return -1;
}
rule = acl_rules_oids[oid];
// Look for it in the multimap
found = false;
index = acl_rules.equal_range( rule->user );
it = index.first;
while ( !found && it != index.second )
{
found = ( it->second->resource == resource &&
it->second->rights == rights );
found = *rule == *(it->second);
if ( !found )
{
@ -277,16 +362,17 @@ int AclManager::del_rule(long long user, long long resource, long long rights,
if ( !found )
{
AclRule rule(user, resource, rights);
ostringstream oss;
oss << "Rule " << rule.to_str() << " does not exist";
error_str = oss.str();
oss << "Internal error: ACL Rule " << oid
<< " indexed by oid, but not in by user attribute";
NebulaLog::log("ACL",Log::ERROR,oss);
return -1;
}
rc = drop( it->second );
rc = drop( oid );
if ( rc != 0 )
{
@ -295,7 +381,9 @@ int AclManager::del_rule(long long user, long long resource, long long rights,
}
delete it->second;
acl_rules.erase( it );
acl_rules_oids.erase( oid );
return 0;
}
@ -303,12 +391,30 @@ int AclManager::del_rule(long long user, long long resource, long long rights,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void AclManager::update_lastOID()
{
// db->escape_str is not used for 'table' since its name can't be set in
// any way by the user, it is hardcoded.
ostringstream oss;
oss << "REPLACE INTO pool_control (tablename, last_oid) VALUES ("
<< "'" << table << "',"
<< lastOID << ")";
db->exec(oss);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::select_cb(void *nil, int num, char **values, char **names)
{
if ( (num != 3) ||
if ( (num != 4) ||
(!values[0]) ||
(!values[1]) ||
(!values[2]) )
(!values[2]) ||
(!values[3]) )
{
return -1;
}
@ -316,11 +422,13 @@ int AclManager::select_cb(void *nil, int num, char **values, char **names)
ostringstream oss;
istringstream iss;
int oid = atoi(values[0]);
long long rule_values[3];
for ( int i = 0; i < 3; i++ )
{
iss.str( values[i] );
iss.str( values[i+1] );
iss >> rule_values[i];
@ -334,13 +442,15 @@ int AclManager::select_cb(void *nil, int num, char **values, char **names)
// 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]);
AclRule * rule = new AclRule(oid, rule_values[0], rule_values[1],
rule_values[2]);
oss << "Loading ACL Rule " << rule->to_str();
NebulaLog::log("ACL",Log::DEBUG,oss);
NebulaLog::log("ACL",Log::DDEBUG,oss);
acl_rules.insert( make_pair(rule->user, rule) );
acl_rules_oids.insert( make_pair(rule->oid, rule) );
return 0;
}
@ -375,6 +485,7 @@ int AclManager::insert(AclRule * rule)
// Construct the SQL statement to Insert
oss << "INSERT INTO " << table <<" ("<< db_names <<") VALUES ("
<< rule->oid << ","
<< rule->user << ","
<< rule->resource << ","
<< rule->rights << ")";
@ -387,15 +498,14 @@ int AclManager::insert(AclRule * rule)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AclManager::drop(AclRule * rule)
int AclManager::drop(int oid)
{
ostringstream oss;
int rc;
oss << "DELETE FROM " << table << " WHERE "
<< "user=" << rule->user << "AND"
<< "resource=" << rule->resource << "AND"
<< "rights=" << rule->rights;
<< "oid=" << oid;
rc = db->exec(oss);
@ -407,17 +517,17 @@ int AclManager::drop(AclRule * rule)
int AclManager::dump(ostringstream& oss)
{
multimap<long long, AclRule *>::iterator it;
map<int, AclRule *>::iterator it;
string xml;
oss << "<ACL>";
oss << "<ACL_POOL>";
for ( it = acl_rules.begin() ; it != acl_rules.end(); it++ )
for ( it = acl_rules_oids.begin() ; it != acl_rules_oids.end(); it++ )
{
oss << it->second->to_xml(xml);
}
oss << "</ACL>";
oss << "</ACL_POOL>";
return 0;
}

View File

@ -276,12 +276,13 @@ string& AclRule::to_xml(string& xml) const
ostringstream oss;
oss <<
"<RULE>"
"<ACL>"
"<ID>" << oid << "</ID>" <<
"<USER>" << hex << user << "</USER>" <<
"<RESOURCE>" << hex << resource << "</RESOURCE>" <<
"<RIGHTS>" << hex << rights << "</RIGHTS>" <<
"<STRING>" << str << "</STRING>" <<
"</RULE>";
"</ACL>";
xml = oss.str();

View File

@ -69,10 +69,10 @@ cmd = CommandParser::CmdParser.new(ARGV) do
Deletes an existing ACL rule
EOT
command :delrule, delrule_desc, :user, :resource, :rights do
command :delrule, delrule_desc, :id do
acl = OpenNebula::Acl.new( OpenNebula::Client.new() )
rc = acl.delrule( args[0], args[1], args[2] )
rc = acl.delrule( args[0] )
if OpenNebula.is_error?(rc)
[-1, rc.message]

View File

@ -81,11 +81,9 @@ module OpenNebula
# Deletes an existing ACL rule.
#
# +user+ A hex number, e.g. 0x100000001
# +resource+ A hex number, e.g. 0x2100000001
# +rights+ A hex number, e.g. 0x10
def delrule(user, resource, rights)
rc = @client.call( ACL_METHODS[:delrule], user, resource, rights )
# +id+ Rule id
def delrule(id)
rc = @client.call( ACL_METHODS[:delrule], id.to_i )
rc = nil if !OpenNebula.is_error?(rc)

View File

@ -21,7 +21,7 @@ using namespace std;
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void RequestManagerAcl::request_execute(xmlrpc_c::paramList const& paramList)
void AclAddRule::request_execute(xmlrpc_c::paramList const& paramList)
{
/*
xmlrpc-c version 1.07 can manage 64 bit numbers, but not all distros. ship
@ -32,6 +32,10 @@ void RequestManagerAcl::request_execute(xmlrpc_c::paramList const& paramList)
rights = xmlrpc_c::value_i8(paramList.getI8(3));
*/
long long user;
long long resource;
long long rights;
istringstream iss;
iss.str( xmlrpc_c::value_string(paramList.getString(1)) );
@ -59,9 +63,43 @@ void RequestManagerAcl::request_execute(xmlrpc_c::paramList const& paramList)
return;
}
int rc = perform_operation(error_msg);
int rc = aclm->add_rule(user, resource, rights, error_msg);
if ( rc != 0 )
if ( rc < 0 )
{
failure_response(INTERNAL, request_error(error_msg, ""));
return;
}
success_response(rc);
return;
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void AclDelRule::request_execute(xmlrpc_c::paramList const& paramList)
{
int oid = xmlrpc_c::value_int(paramList.getInt(1));
Nebula& nd = Nebula::instance();
aclm = nd.get_aclm();
string error_msg;
// TODO: Only oneadmin can manage ACL
if ( uid != 0 )
{
failure_response(AUTHORIZATION,
authorization_error("Only oneadmin can manage ACL rules"));
return;
}
int rc = aclm->del_rule(oid, error_msg);
if ( rc < 0 )
{
failure_response(INTERNAL, request_error(error_msg, ""));
return;
@ -72,20 +110,6 @@ void RequestManagerAcl::request_execute(xmlrpc_c::paramList const& paramList)
return;
}
/* ------------------------------------------------------------------------- */
int AclAddRule::perform_operation(string& error_msg)
{
return aclm->add_rule(user, resource, rights, error_msg);
}
/* ------------------------------------------------------------------------- */
int AclDelRule::perform_operation(string& error_msg)
{
return aclm->del_rule(user, resource, rights, error_msg);
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */