From cf31d91abdb1933babb38842782f354cf5d45475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= Date: Tue, 21 Jan 2014 12:52:25 +0100 Subject: [PATCH] Feature #2653: Add zone id to each ACL rule --- include/AclManager.h | 11 +++++ include/AclRule.h | 36 +++++++++++--- include/Nebula.h | 6 +++ src/acl/AclManager.cc | 61 ++++++++++++++++++------ src/acl/AclRule.cc | 73 +++++++++++++++++++++++++++++ src/cli/etc/oneacl.yaml | 6 +++ src/cli/one_helper/oneacl_helper.rb | 6 ++- src/cli/oneacl | 4 +- src/oca/ruby/opennebula/acl.rb | 39 ++++++++++++--- src/pool/PoolObjectAuth.cc | 14 ++++-- src/rm/RequestManagerAcl.cc | 14 +++++- src/rm/RequestManagerGroup.cc | 16 ++++++- src/scheduler/src/pool/AclXML.cc | 2 +- 13 files changed, 250 insertions(+), 38 deletions(-) diff --git a/include/AclManager.h b/include/AclManager.h index 7bf7f75cb5..502eb5eeb2 100644 --- a/include/AclManager.h +++ b/include/AclManager.h @@ -74,6 +74,7 @@ public: * @param user 64 bit ID and flags * @param resource 64 bit ID and flags * @param rights 64 bit flags + * @param zone 64 bit flags * @param error_str Returns the error reason, if any * * @return the oid assigned to the rule on success, @@ -84,6 +85,7 @@ public: virtual int add_rule(long long user, long long resource, long long rights, + long long zone, string& error_str); /** * Deletes a rule from the ACL rule set @@ -100,6 +102,7 @@ public: * @param user 64 bit ID and flags * @param resource 64 bit ID and flags * @param rights 64 bit flags + * @param zone 64 bit flags * * @param error_str Returns the error reason, if any * @return 0 on success @@ -107,6 +110,7 @@ public: virtual int del_rule(long long user, long long resource, long long rights, + long long zone, string& error_str); /** @@ -271,6 +275,13 @@ private: long long resource_req, long long resource_mask); + + // TODO + int get_zone_id() const + { + return 10; + }; + // ---------------------------------------- // Mutex synchronization // ---------------------------------------- diff --git a/include/AclRule.h b/include/AclRule.h index 46de7aea82..bccd6a51d8 100644 --- a/include/AclRule.h +++ b/include/AclRule.h @@ -47,7 +47,7 @@ public: /** * Creates an empty ACL rule */ - AclRule():oid(0), user(0), resource(0), rights(0), str("") {}; + AclRule():oid(0), user(0), resource(0), rights(0), zone(0), str("") {}; /** * Main ACL rule constructor @@ -55,8 +55,10 @@ public: AclRule(int _oid, long long _user, long long _resource, - long long _rights): - oid(_oid), user(_user), resource(_resource), rights(_rights) + long long _rights, + long long _zone): + oid(_oid), user(_user), resource(_resource), + rights(_rights), zone(_zone) { build_str(); }; @@ -64,16 +66,17 @@ public: /** * Set the fields of the ACL, and updates its representation */ - void set(int _oid, long long _user, long long _resource, - long long _rights) + long long _rights, + long long _zone) { oid = _oid; user = _user; resource = _resource; rights = _rights; + zone = _zone; build_str(); }; @@ -85,7 +88,8 @@ public: { return (user == other.user && resource == other.resource && - rights == other.rights); + rights == other.rights && + zone == other.zone); }; /** @@ -164,6 +168,16 @@ public: return resource & 0xFFFFFFFF00000000LL; }; + /** + * Returns the 32 less significant bits of the zone long long attribute + * + * @return the zone ID + */ + int zone_id() const + { + return zone; + }; + // ------------------------------------------------------------------------ // Functions needed by the Scheduler ACL engine // ------------------------------------------------------------------------ @@ -220,6 +234,16 @@ private: */ long long rights; + /** + * 64 bit integer holding a zone compound: + * + * 32 bits 32 bits + * +-----------------------+-----------------------+ + * | Type (individual,all) | zone ID | + * +-----------------------+-----------------------+ + */ + long long zone; + /** * Human readable representation of the rule */ diff --git a/include/Nebula.h b/include/Nebula.h index 97dd177bdb..dca257aa27 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -357,6 +357,12 @@ public: return hostname; }; + // TODO + int get_zone_id() + { + return 10; + }; + /** * Returns the version of oned * @return the version diff --git a/src/acl/AclManager.cc b/src/acl/AclManager.cc index 222199ac10..c54636cc13 100644 --- a/src/acl/AclManager.cc +++ b/src/acl/AclManager.cc @@ -25,10 +25,11 @@ const char * AclManager::table = "acl"; -const char * AclManager::db_names = "oid, user, resource, rights"; +const char * AclManager::db_names = "oid, user, resource, rights, zone"; const char * AclManager::db_bootstrap = "CREATE TABLE IF NOT EXISTS " - "acl (oid INT PRIMARY KEY, user BIGINT, resource BIGINT, rights BIGINT)"; + "acl (oid INT PRIMARY KEY, user BIGINT, resource BIGINT, " + "rights BIGINT, zone BIGINT)"; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -77,6 +78,7 @@ AclManager::AclManager(SqlDB * _db) : db(_db), lastOID(-1) PoolObjectSQL::IMAGE | PoolObjectSQL::TEMPLATE, AuthRequest::CREATE, + AclRule::ALL_ID, error_str); // Users in USERS can deploy VMs in any HOST @@ -86,12 +88,14 @@ AclManager::AclManager(SqlDB * _db) : db(_db), lastOID(-1) AclRule::ALL_ID | PoolObjectSQL::HOST, AuthRequest::MANAGE, + AclRule::ALL_ID, error_str); add_rule(AclRule::ALL_ID, AclRule::ALL_ID | PoolObjectSQL::DOCUMENT, AuthRequest::CREATE, + AclRule::ALL_ID, error_str); } @@ -219,7 +223,8 @@ const bool AclManager::authorize( AclRule log_rule(-1, AclRule::INDIVIDUAL_ID | uid, log_resource, - rights_req); + rights_req, + AclRule::INDIVIDUAL_ID | get_zone_id()); oss << "Request " << log_rule.to_str(); NebulaLog::log("ACL",Log::DDEBUG,oss); @@ -389,6 +394,10 @@ bool AclManager::match_rules( pair::iterator, multimap::iterator> index; + long long zone_oid_mask = AclRule::INDIVIDUAL_ID | 0x00000000FFFFFFFFLL; + long long zone_req = AclRule::INDIVIDUAL_ID | get_zone_id(); + long long zone_all_req = AclRule::ALL_ID; + index = rules.equal_range( user_req ); for ( it = index.first; it != index.second; it++) @@ -398,6 +407,14 @@ bool AclManager::match_rules( NebulaLog::log("ACL",Log::DDEBUG,oss); auth = + ( + // Rule applies in any Zone + ( ( it->second->zone & zone_all_req ) == zone_all_req ) + || + // Rule applies in this Zone + ( ( it->second->zone & zone_oid_mask ) == zone_req ) + ) + && // Rule grants the requested rights ( ( it->second->rights & rights_req ) == rights_req ) && @@ -431,7 +448,7 @@ bool AclManager::match_rules( /* -------------------------------------------------------------------------- */ int AclManager::add_rule(long long user, long long resource, long long rights, - string& error_str) + long long zone, string& error_str) { lock(); @@ -440,7 +457,7 @@ int AclManager::add_rule(long long user, long long resource, long long rights, lastOID = -1; } - AclRule * rule = new AclRule(++lastOID, user, resource, rights); + AclRule * rule = new AclRule(++lastOID, user, resource, rights, zone); ostringstream oss; int rc; @@ -604,11 +621,12 @@ int AclManager::del_rule( long long user, long long resource, long long rights, + long long zone, string& error_str) { lock(); - AclRule * rule = new AclRule(-1, user, resource, rights); + AclRule * rule = new AclRule(-1, user, resource, rights, zone); int oid = -1; bool found = false; @@ -796,6 +814,10 @@ void AclManager::reverse_search(int uid, long long resource_cid_mask = ( obj_type | AclRule::CLUSTER_ID ); + long long zone_oid_req = + AclRule::INDIVIDUAL_ID | get_zone_id(); + + long long zone_all_req = AclRule::ALL_ID; // Create a temporal rule, to log the request long long log_resource; @@ -805,7 +827,8 @@ void AclManager::reverse_search(int uid, AclRule log_rule(-1, AclRule::INDIVIDUAL_ID | uid, log_resource, - rights_req); + rights_req, + zone_oid_req); oss << "Reverse search request " << log_rule.to_str(); NebulaLog::log("ACL",Log::DDEBUG,oss); @@ -841,8 +864,15 @@ void AclManager::reverse_search(int uid, for ( it = index.first; it != index.second; it++) { - // Rule grants the requested rights - if ( ( it->second->rights & rights_req ) == rights_req ) + // Rule grants the requested rights + if ( ( ( it->second->rights & rights_req ) == rights_req ) + && + // Rule applies in this zone or in all zones + ( ( it->second->zone == zone_oid_req ) + || + ( it->second->zone == zone_all_req ) + ) + ) { oss.str(""); oss << "> Rule " << it->second->to_str(); @@ -919,11 +949,12 @@ void AclManager::update_lastOID() int AclManager::select_cb(void *nil, int num, char **values, char **names) { - if ( (num != 4) || + if ( (num != 5) || (!values[0]) || (!values[1]) || (!values[2]) || - (!values[3]) ) + (!values[3]) || + (!values[4]) ) { return -1; } @@ -935,7 +966,7 @@ int AclManager::select_cb(void *nil, int num, char **values, char **names) long long rule_values[3]; - for ( int i = 0; i < 3; i++ ) + for ( int i = 0; i < 4; i++ ) { iss.str( values[i+1] ); @@ -952,7 +983,8 @@ int AclManager::select_cb(void *nil, int num, char **values, char **names) AclRule * rule = new AclRule(oid, rule_values[0], rule_values[1], - rule_values[2]); + rule_values[2], + rule_values[3]); oss << "Loading ACL Rule " << rule->to_str(); NebulaLog::log("ACL",Log::DDEBUG,oss); @@ -996,7 +1028,8 @@ int AclManager::insert(AclRule * rule, SqlDB * db) << rule->oid << "," << rule->user << "," << rule->resource << "," - << rule->rights << ")"; + << rule->rights << "," + << rule->zone << ")"; rc = db->exec(oss); diff --git a/src/acl/AclRule.cc b/src/acl/AclRule.cc index 6233168c7a..147a392f8e 100644 --- a/src/acl/AclRule.cc +++ b/src/acl/AclRule.cc @@ -240,6 +240,59 @@ bool AclRule::malformed(string& error_str) const oss << "wrong [rights], it cannot be bigger than 0xF"; } + // Check zone + + if ( (zone & GROUP_ID) != 0 ) + { + error = true; + oss << "[zone] GROUP (@) bit is not supported"; + } + + if ( (zone & INDIVIDUAL_ID) != 0 && (zone & ALL_ID) != 0 ) + { + if ( error ) + { + oss << "; "; + } + + error = true; + oss << "[zone] INDIVIDUAL (#) and ALL (*) bits are exclusive"; + } + + if ( (zone & 0x700000000LL) == 0 ) + { + if ( error ) + { + oss << "; "; + } + + error = true; + oss << "[zone] is missing one of the INDIVIDUAL or ALL bits"; + } + + if ( zone_id() < 0 ) + { + if ( error ) + { + oss << "; "; + } + + error = true; + oss << "[zone] ID cannot be negative"; + } + + if ( (zone & ALL_ID) != 0 && zone_id() != 0 ) + { + if ( error ) + { + oss << "; "; + } + + error = true; + oss << "when using the ALL bit, [zone] ID must be 0"; + } + + if ( error ) { error_str = oss.str(); @@ -331,6 +384,21 @@ void AclRule::build_str() } } + oss << " "; + + if ( (zone & INDIVIDUAL_ID) != 0 ) + { + oss << "#" << zone_id(); + } + else if ( (zone & ALL_ID) != 0 ) + { + oss << "*"; + } + else + { + oss << "??"; + } + str = oss.str(); } @@ -347,6 +415,7 @@ string& AclRule::to_xml(string& xml) const "" << hex << user << "" << "" << hex << resource << "" << "" << hex << rights << "" << + "" << hex << zone << "" << "" << str << "" << ""; @@ -397,6 +466,10 @@ int AclRule::from_xml(xmlNodePtr node) { iss >> hex >> rights; } + else if (name == "ZONE") + { + iss >> hex >> zone; + } else if (name == "STRING") { str = iss.str(); diff --git a/src/cli/etc/oneacl.yaml b/src/cli/etc/oneacl.yaml index b16205a23a..3e2fadddb5 100644 --- a/src/cli/etc/oneacl.yaml +++ b/src/cli/etc/oneacl.yaml @@ -18,6 +18,11 @@ :size: 5 :right: true +:ZONE: + :desc: Zone ID + :size: 5 + :right: true + :OPE_UMAC: :desc: Operation to which the rule applies :size: 8 @@ -28,4 +33,5 @@ - :USER - :RES_VHNIUTGDCO - :RID +- :ZONE - :OPE_UMAC diff --git a/src/cli/one_helper/oneacl_helper.rb b/src/cli/one_helper/oneacl_helper.rb index aaf009190b..782fbb5c43 100644 --- a/src/cli/one_helper/oneacl_helper.rb +++ b/src/cli/one_helper/oneacl_helper.rb @@ -116,12 +116,16 @@ private d['STRING'].split(" ")[1].split("/")[1] end + column :ZONE, "Zone ID", :right, :size=>5 do |d| + d['STRING'].split(" ")[3] + end + column :OPE_UMAC, "Operation to which the rule applies", :size =>8 do |d| OneAclHelper::right_mask d['STRING'].split(" ")[2] end - default :ID, :USER, :RES_VHNIUTGDCO, :RID, :OPE_UMAC + default :ID, :USER, :RES_VHNIUTGDCO, :RID, :ZONE, :OPE_UMAC end table diff --git a/src/cli/oneacl b/src/cli/oneacl index 3e5994ebcf..d0d474d616 100755 --- a/src/cli/oneacl +++ b/src/cli/oneacl @@ -69,10 +69,10 @@ cmd = CommandParser::CmdParser.new(ARGV) do if OpenNebula.is_error?(new_args) next -1, new_args.message end - when 3 + when 3, 4 new_args=args else - next -1, "Wrong number of arguments, must be 1 or 3" + next -1, "Wrong number of arguments, must be 1 or 4" end helper.create_resource(options) do |rule| diff --git a/src/oca/ruby/opennebula/acl.rb b/src/oca/ruby/opennebula/acl.rb index 1051d0ecd9..bb037b6bba 100644 --- a/src/oca/ruby/opennebula/acl.rb +++ b/src/oca/ruby/opennebula/acl.rb @@ -99,14 +99,24 @@ module OpenNebula # A string containing a hex number, e.g. 0x2100000001 # @param rights [String] # A string containing a hex number, e.g. 0x10 + # @param zone [String] + # A string containing a hex number, e.g. 0x100000001 # # @return [nil, OpenNebula::Error] nil in case of success, Error # otherwise - def allocate(user, resource, rights) - return super( AclPool::ACL_POOL_METHODS[:addrule], - user, - resource, - rights ) + def allocate(user, resource, rights, zone=nil) + if !zone.nil? + return super( AclPool::ACL_POOL_METHODS[:addrule], + user, + resource, + rights, + zone ) + else + return super( AclPool::ACL_POOL_METHODS[:addrule], + user, + resource, + rights) + end end # Deletes the Acl rule @@ -138,7 +148,7 @@ module OpenNebula rule_str = rule_str.split(" ") - if rule_str.length != 3 + if rule_str.length != 3 && rule_str.length != 4 return OpenNebula::Error.new( "String needs three components: User, Resource, Rights") end @@ -147,6 +157,10 @@ module OpenNebula ret << parse_resources(rule_str[1]) ret << parse_rights(rule_str[2]) + if rule_str.length > 3 + ret << parse_zone(rule_str[3]) + end + errors=ret.map do |arg| if OpenNebula.is_error?(arg) arg.message @@ -230,6 +244,19 @@ private end end + # Converts a string in the form [#, *] to a hex. number + # + # @param zone [String] Zone component string + # + # @return [String] A string containing a hex number + def self.parse_zone(zone) + begin + return calculate_ids(zone).to_i.to_s(16) + rescue Exception => e + return OpenNebula::Error.new(e.message) + end + end + # Calculates the numeric value for a String containing an individual # (#), group (@) or all (*) ID component # diff --git a/src/pool/PoolObjectAuth.cc b/src/pool/PoolObjectAuth.cc index 88b06599ac..5b3b8d437f 100644 --- a/src/pool/PoolObjectAuth.cc +++ b/src/pool/PoolObjectAuth.cc @@ -22,12 +22,16 @@ void PoolObjectAuth::get_acl_rules(AclRule& owner_rule, AclRule& group_rule, AclRule& other_rule) const { - long long perm_user, perm_resource, perm_rights; + long long perm_user, perm_resource, perm_rights, perm_zone; perm_resource = obj_type | AclRule::INDIVIDUAL_ID | oid; + // TODO + //perm_zone = AclRule::INDIVIDUAL_ID | Nebula::instance().get_zone_id(); + perm_zone = AclRule::INDIVIDUAL_ID | 10; + // ------------------------------------------------------------------------- - // Rule "#uid ob_type/#oid user_rights" + // Rule "#uid ob_type/#oid user_rights #zone" // ------------------------------------------------------------------------- perm_user = AclRule::INDIVIDUAL_ID | uid; @@ -48,7 +52,7 @@ void PoolObjectAuth::get_acl_rules(AclRule& owner_rule, perm_rights = perm_rights | AuthRequest::ADMIN; } - owner_rule.set(0, perm_user, perm_resource, perm_rights); + owner_rule.set(0, perm_user, perm_resource, perm_rights, perm_zone); // ------------------------------------------------------------------------- // Rule "@gid ob_type/#oid group_rights" @@ -72,7 +76,7 @@ void PoolObjectAuth::get_acl_rules(AclRule& owner_rule, perm_rights = perm_rights | AuthRequest::ADMIN; } - group_rule.set(0, perm_user, perm_resource, perm_rights); + group_rule.set(0, perm_user, perm_resource, perm_rights, perm_zone); // ------------------------------------------------------------------------- // Rule "* ob_type/#oid others_rights" @@ -96,6 +100,6 @@ void PoolObjectAuth::get_acl_rules(AclRule& owner_rule, perm_rights = perm_rights | AuthRequest::ADMIN; } - other_rule.set(0, perm_user, perm_resource, perm_rights); + other_rule.set(0, perm_user, perm_resource, perm_rights, perm_zone); }; diff --git a/src/rm/RequestManagerAcl.cc b/src/rm/RequestManagerAcl.cc index 2560f532d1..178ca59b01 100644 --- a/src/rm/RequestManagerAcl.cc +++ b/src/rm/RequestManagerAcl.cc @@ -35,6 +35,7 @@ void AclAddRule::request_execute(xmlrpc_c::paramList const& paramList, long long user; long long resource; long long rights; + long long zone; istringstream iss; @@ -49,6 +50,17 @@ void AclAddRule::request_execute(xmlrpc_c::paramList const& paramList, iss.str( xmlrpc_c::value_string(paramList.getString(3)) ); iss >> hex >> rights; + if ( paramList.size() > 4 ) + { + iss.clear(); + iss.str( xmlrpc_c::value_string(paramList.getString(4)) ); + iss >> hex >> zone; + } + else + { + zone = AclRule::INDIVIDUAL_ID | Nebula::instance().get_zone_id(); + } + string error_msg; if ( basic_authorization(-1, att) == false ) @@ -56,7 +68,7 @@ void AclAddRule::request_execute(xmlrpc_c::paramList const& paramList, return; } - int rc = aclm->add_rule(user, resource, rights, error_msg); + int rc = aclm->add_rule(user, resource, rights, zone, error_msg); if ( rc < 0 ) { diff --git a/src/rm/RequestManagerGroup.cc b/src/rm/RequestManagerGroup.cc index 268d4c85f6..1084d434f6 100644 --- a/src/rm/RequestManagerGroup.cc +++ b/src/rm/RequestManagerGroup.cc @@ -218,6 +218,9 @@ int GroupAddProvider::edit_acl_rules( AuthRequest::MANAGE, + AclRule::INDIVIDUAL_ID | + zone_id, + error_msg); // @ DATASTORE+NET/% USE @@ -231,6 +234,9 @@ int GroupAddProvider::edit_acl_rules( AuthRequest::USE, + AclRule::INDIVIDUAL_ID | + zone_id, + error_msg); if (rc != 0) @@ -269,7 +275,7 @@ int GroupDelProvider::edit_acl_rules( mask_prefix = AclRule::CLUSTER_ID | cluster_id; } - // @ HOST/% MANAGE + // @ HOST/% MANAGE # rc += aclm->del_rule( AclRule::GROUP_ID | group_id, @@ -279,9 +285,12 @@ int GroupDelProvider::edit_acl_rules( AuthRequest::MANAGE, + AclRule::INDIVIDUAL_ID | + zone_id, + error_msg); - // @ DATASTORE+NET/% USE + // @ DATASTORE+NET/% USE # rc += aclm->del_rule( AclRule::GROUP_ID | group_id, @@ -292,6 +301,9 @@ int GroupDelProvider::edit_acl_rules( AuthRequest::USE, + AclRule::INDIVIDUAL_ID | + zone_id, + error_msg); if (rc != 0) diff --git a/src/scheduler/src/pool/AclXML.cc b/src/scheduler/src/pool/AclXML.cc index 44ea6d7530..81a89ffb5d 100644 --- a/src/scheduler/src/pool/AclXML.cc +++ b/src/scheduler/src/pool/AclXML.cc @@ -81,7 +81,7 @@ int AclXML::load_rules(const string& xml_str) for (it = rules.begin(); it != rules.end() ; it++) { - AclRule * rule = new AclRule(0,0,0,0); + AclRule * rule = new AclRule(0,0,0,0,0); int rc = rule->from_xml(*it); if ( rc == 0 )