diff --git a/include/AclManager.h b/include/AclManager.h index f37864a716..3a12d72b24 100644 --- a/include/AclManager.h +++ b/include/AclManager.h @@ -32,7 +32,12 @@ class AclManager : public Callbackable public: AclManager(SqlDB * _db); - ~AclManager(); + AclManager():db(0),lastOID(0) + { + pthread_mutex_init(&mutex, 0); + }; + + virtual ~AclManager(); /** * Loads the ACL rule set from the DB @@ -75,10 +80,10 @@ public: * -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); + virtual int add_rule(long long user, + long long resource, + long long rights, + string& error_str); /** * Deletes a rule from the ACL rule set * @@ -86,7 +91,7 @@ public: * @param error_str Returns the error reason, if any * @return 0 on success */ - int del_rule(int oid, string& error_str); + virtual int del_rule(int oid, string& error_str); /* ---------------------------------------------------------------------- */ /* DB management */ @@ -102,9 +107,9 @@ public: * @param oss The output stream to dump the rule set contents * @return 0 on success */ - int dump(ostringstream& oss); + virtual int dump(ostringstream& oss); -private: +protected: // ---------------------------------------- // ACL rules management @@ -121,6 +126,8 @@ private: */ map acl_rules_oids; +private: + /** * Gets all rules that apply to the user_req and, if any of them grants * permission, returns true. diff --git a/include/AclRule.h b/include/AclRule.h index 91b21e5697..4047ff57ee 100644 --- a/include/AclRule.h +++ b/include/AclRule.h @@ -19,6 +19,7 @@ #include #include +#include using namespace std; @@ -83,11 +84,10 @@ public: /** * Rebuilds the rule from an xml formatted string * - * @param xml_str The xml-formatted string - * + * @param node xml node for the ACL rule * @return 0 on success, -1 otherwise */ - int from_xml(const string &xml_str); + int from_xml(xmlNodePtr node); /** * Returns the 32 less significant bits of the user long long attribute @@ -131,6 +131,20 @@ public: return resource & 0xFFFFFFFF00000000LL; }; + // ------------------------------------------------------------------------ + // Functions needed by the Scheduler ACL engine + // ------------------------------------------------------------------------ + + long long get_user() const + { + return user; + } + + long long get_oid() const + { + return oid; + } + private: // NONE_ID can never be used in a rule. It is useful to create masks that // will never match any existing rule diff --git a/include/ObjectXML.h b/include/ObjectXML.h index d370270226..9be989618b 100644 --- a/include/ObjectXML.h +++ b/include/ObjectXML.h @@ -94,20 +94,6 @@ public: int xpath(unsigned int& value, const char * xpath_expr, const unsigned int& def); - /** - * Gets and sets a xpath attribute, if the attribute is not found a default - * is used - * @param value to set - * @param xpath_expr of the xml element - * @param def default value if the element is not found - * @param hex if true, the contents of the element are expected to be in - * hexadecimal instead of decimal - * - * @return -1 if default was set - */ - long long xpath(long long& value, const char * xpath_expr, - const long long& def, bool hex=true); - /** * Gets and sets a xpath attribute, if the attribute is not found a default * is used diff --git a/src/acl/AclManager.cc b/src/acl/AclManager.cc index 6edc23a79f..cb35403267 100644 --- a/src/acl/AclManager.cc +++ b/src/acl/AclManager.cc @@ -340,7 +340,6 @@ int AclManager::add_rule(long long user, long long resource, long long rights, goto error_malformed; } - rc = insert(rule); if ( rc != 0 ) diff --git a/src/acl/AclRule.cc b/src/acl/AclRule.cc index 91ebf218f5..92243bb55e 100644 --- a/src/acl/AclRule.cc +++ b/src/acl/AclRule.cc @@ -350,27 +350,54 @@ string& AclRule::to_xml(string& xml) const /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int AclRule::from_xml(const string &xml_str) +int AclRule::from_xml(xmlNodePtr node) { int rc = 0; - string tmp_error; - - ObjectXML xml_obj(xml_str); - - rc += xml_obj.xpath(oid , "/ACL/ID" , 0); - rc += xml_obj.xpath(user , "/ACL/USER" , 0); - rc += xml_obj.xpath(resource, "/ACL/RESOURCE", 0); - rc += xml_obj.xpath(rights , "/ACL/RIGHTS" , 0); - rc += xml_obj.xpath(str , "/ACL/STRING" , ""); - - if ( (rc != 0) || malformed(tmp_error) ) + for (xmlNodePtr acl = node->children ; acl != 0 ; acl = acl->next) { - return -1; + if ( acl->type != XML_ELEMENT_NODE ) + { + rc = -1; + break; + } + + xmlNodePtr elem = acl->children; + + if ( elem->type != XML_TEXT_NODE ) + { + rc = -1; + break; + } + + string name = reinterpret_cast(acl->name); + istringstream iss(reinterpret_cast(elem->content)); + + if (name == "ID") + { + iss >> oid; + } + else if (name == "USER") + { + iss >> hex >> user; + } + else if (name == "RESOURCE") + { + iss >> hex >> resource; + } + else if (name == "RIGHTS") + { + iss >> hex >> rights; + } + else if (name == "STRING") + { + str = iss.str(); + } } - return 0; + return rc; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + diff --git a/src/cli/one_helper/oneacl_helper.rb b/src/cli/one_helper/oneacl_helper.rb index 6d920ab909..d82d64c6df 100644 --- a/src/cli/one_helper/oneacl_helper.rb +++ b/src/cli/one_helper/oneacl_helper.rb @@ -35,10 +35,10 @@ class OneAclHelper < OpenNebulaHelper::OneHelper end if OpenNebula.is_error?(rc) - [-1, rc.message] + return [-1, rc.message] else - if !rc - puts "Rule added" if options[:verbose] + if rc.class == Fixnum + puts "Rule added with ID #{rc}" if options[:verbose] return 0 end return [-1, rc[:users].message] if OpenNebula.is_error?(rc[:users]) diff --git a/src/cli/oneacl b/src/cli/oneacl index 30bcd8819c..98a55278c0 100755 --- a/src/cli/oneacl +++ b/src/cli/oneacl @@ -54,7 +54,7 @@ cmd = CommandParser::CmdParser.new(ARGV) do Adds a new ACL rule EOT - command :addrule, addrule_desc, [:user,:rulestr], [:resource, nil], [:rights, nil] do + command :create, addrule_desc, [:user,:rulestr], [:resource, nil], [:rights, nil] do helper.add_rule(options, args[0], args[1], args[2] ) end @@ -62,7 +62,7 @@ cmd = CommandParser::CmdParser.new(ARGV) do Deletes an existing ACL rule EOT - command :delrule, delrule_desc, :id do + command :delete, delrule_desc, :id do helper.delete_rule( options, args[0] ) end diff --git a/src/oca/ruby/OpenNebula/Acl.rb b/src/oca/ruby/OpenNebula/Acl.rb index 708a0b5d0f..48a336051e 100644 --- a/src/oca/ruby/OpenNebula/Acl.rb +++ b/src/oca/ruby/OpenNebula/Acl.rb @@ -111,7 +111,9 @@ module OpenNebula end resources[0].split("+").each{ |resource| - next if !RESOURCES[resource.upcase] + if !RESOURCES[resource.upcase] + raise "Resource #{resource} malformed." + end @content[:resources] += RESOURCES[resource.upcase] } @@ -127,7 +129,7 @@ module OpenNebula rights = rights.split("+") rights.each{ |right| - next if !RIGHTS[right.upcase] + raise "Right #{right} malformed." if !RIGHTS[right.upcase] @content[:rights] += RIGHTS[right.upcase] } diff --git a/src/oca/ruby/OpenNebula/AclPool.rb b/src/oca/ruby/OpenNebula/AclPool.rb index 9c012a61b8..9b767e21c8 100644 --- a/src/oca/ruby/OpenNebula/AclPool.rb +++ b/src/oca/ruby/OpenNebula/AclPool.rb @@ -56,14 +56,10 @@ module OpenNebula # +resource+ A string containing a hex number, e.g. 0x2100000001 # +rights+ A string containing a hex number, e.g. 0x10 def addrule(user, resource, rights) - rc = @client.call( ACL_POOL_METHODS[:addrule], + return @client.call( ACL_POOL_METHODS[:addrule], user, resource, rights ) - - rc = nil if !OpenNebula.is_error?(rc) - - return rc end # Adds a new ACL rule. diff --git a/src/scheduler/include/AclXML.h b/src/scheduler/include/AclXML.h new file mode 100644 index 0000000000..d3aecd593c --- /dev/null +++ b/src/scheduler/include/AclXML.h @@ -0,0 +1,83 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#ifndef ACL_XML_H_ +#define ACL_XML_H_ + +#include "AclManager.h" +#include "Client.h" + +using namespace std; + +/** + * This class manages the ACL rules and the authorization engine + */ +class AclXML : public AclManager +{ +public: + AclXML(Client * _client):AclManager(), client(_client){}; + + virtual ~AclXML(){}; + + /** + * Loads the ACL rule set from the DB + * @return 0 on success. + */ + int set_up(); + +private: + /* ---------------------------------------------------------------------- */ + /* Re-implement DB public functions not used in scheduler */ + /* ---------------------------------------------------------------------- */ + int start() + { + return -1; + } + + int add_rule(long long user, + long long resource, + long long rights, + string& error_str) + { + return -1; + }; + + int del_rule(int oid, string& error_str) + { + return -1; + }; + + int dump(ostringstream& oss) + { + return -1; + }; + + Client * client; + + /** + * Loads the ACL rule set from its XML representation: + * as obtained by a dump call + * + * @param xml_str string with the XML document for the ACL + * @return 0 on success. + */ + int load_rules(const string& xml_str); + + void flush_rules(); +}; + +#endif /*ACL_XML_H*/ + diff --git a/src/scheduler/include/Scheduler.h b/src/scheduler/include/Scheduler.h index 5fd1ae6365..93e2ff7345 100644 --- a/src/scheduler/include/Scheduler.h +++ b/src/scheduler/include/Scheduler.h @@ -23,6 +23,7 @@ #include "VirtualMachinePoolXML.h" #include "SchedulerPolicy.h" #include "ActionManager.h" +#include "AclXML.h" using namespace std; @@ -50,6 +51,7 @@ protected: hpool(0), vmpool(0), upool(0), + acls(0), timer(_timer), url(_url), machines_limit(_machines_limit), @@ -78,6 +80,11 @@ protected: delete upool; } + if ( acls != 0) + { + delete acls; + } + if ( client != 0) { delete client; @@ -91,6 +98,7 @@ protected: HostPoolXML * hpool; VirtualMachinePoolXML * vmpool; UserPoolXML * upool; + AclXML * acls; // --------------------------------------------------------------- // Scheduler Policies diff --git a/src/scheduler/include/UserXML.h b/src/scheduler/include/UserXML.h index ef791274a0..ede214cd52 100644 --- a/src/scheduler/include/UserXML.h +++ b/src/scheduler/include/UserXML.h @@ -41,7 +41,12 @@ public: return oid; }; - set get_groups() + int get_gid() + { + return gid; + }; + + const set& get_groups() { return group_ids; }; diff --git a/src/scheduler/src/pool/AclXML.cc b/src/scheduler/src/pool/AclXML.cc new file mode 100644 index 0000000000..d9ed6b4954 --- /dev/null +++ b/src/scheduler/src/pool/AclXML.cc @@ -0,0 +1,114 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include "AclXML.h" +#include "ObjectXML.h" +#include + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int AclXML::set_up() +{ + xmlrpc_c::value result; + + try + { + client->call(client->get_endpoint(), // serverUrl + "one.acl.info", // methodName + "s", // arguments format + &result, // resultP + client->get_oneauth().c_str());// argument + + vector values = + xmlrpc_c::value_array(result).vectorValueValue(); + + bool success = xmlrpc_c::value_boolean(values[0]); + string message = xmlrpc_c::value_string(values[1]); + + if( !success ) + { + ostringstream oss; + + oss << "ONE returned error while retrieving the acls:" << endl; + oss << message; + + NebulaLog::log("ACL", Log::ERROR, oss); + return -1; + } + + flush_rules(); + + load_rules(message); + + return 0; + } + catch (exception const& e) + { + ostringstream oss; + oss << "Exception raised: " << e.what(); + + NebulaLog::log("ACL", Log::ERROR, oss); + + return -1; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int AclXML::load_rules(const string& xml_str) +{ + ObjectXML acl_xml(xml_str); + + vector rules; + vector::iterator it; + + acl_xml.get_nodes("/ACL_POOL/ACL",rules); + + for (it = rules.begin(); it != rules.end() ; it++) + { + AclRule * rule = new AclRule(0,0,0,0); + int rc = rule->from_xml(*it); + + if ( rc == 0 ) + { + acl_rules.insert( make_pair(rule->get_user(), rule) ); + acl_rules_oids.insert( make_pair(rule->get_oid(), rule) ); + } + } + + acl_xml.free_nodes(rules); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void AclXML::flush_rules() +{ + multimap::iterator it; + + for ( it = acl_rules.begin(); it != acl_rules.end(); it++ ) + { + delete it->second; + } + + acl_rules.clear(); + acl_rules_oids.clear(); +} + diff --git a/src/scheduler/src/pool/SConstruct b/src/scheduler/src/pool/SConstruct index 0eb31942d5..428b17b01b 100644 --- a/src/scheduler/src/pool/SConstruct +++ b/src/scheduler/src/pool/SConstruct @@ -21,6 +21,7 @@ Import('sched_env') lib_name='scheduler_pool' source_files=[ + 'AclXML.cc', 'UserPoolXML.cc', 'UserXML.cc', 'HostPoolXML.cc', diff --git a/src/scheduler/src/sched/SConstruct b/src/scheduler/src/sched/SConstruct index 41cb064c98..e66ebfacf2 100644 --- a/src/scheduler/src/sched/SConstruct +++ b/src/scheduler/src/sched/SConstruct @@ -32,6 +32,7 @@ sched_env.Prepend(LIBS=[ 'scheduler_pool', 'nebula_log', 'scheduler_client', + 'nebula_acl', 'nebula_xml', 'nebula_common', 'crypto', diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 0ea7eae18f..fe0f057841 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -122,6 +122,7 @@ void Scheduler::start() hpool = new HostPoolXML(client); vmpool = new VirtualMachinePoolXML(client, machines_limit); upool = new UserPoolXML(client); + acls = new AclXML(client); // ----------------------------------------------------------- // Load scheduler policies @@ -244,9 +245,12 @@ int Scheduler::set_up_pools() //Cleans the cache and get the ACLs //-------------------------------------------------------------------------- - //TODO - // 1.- one.acl.list - // 2.- from_xml + rc = acls->set_up(); + + if ( rc != 0 ) + { + return rc; + } //-------------------------------------------------------------------------- //Get the matching hosts for each VM @@ -326,11 +330,17 @@ void Scheduler::match() if ( matched == false ) { + ostringstream oss; + + oss << "Host " << host->get_hid() << + " filtered out. It does not fullfil REQUIREMENTS."; + + NebulaLog::log("SCHED",Log::DEBUG,oss); continue; } // ----------------------------------------------------------------- - // Check host capacity + // Check if user is authorized // ----------------------------------------------------------------- user = upool->get(uid); @@ -338,21 +348,35 @@ void Scheduler::match() if ( user != 0 ) { - set groups = user->get_groups(); - //TODO Authorization test for this user on this host - // 1.- user = uid - // 2.- gid - // 3.- groups - // 4.- DEPLOY on host->get_hid + const set groups = user->get_groups(); + + if ( uid == 0 || user->get_gid() == 0 ) + { + matched = true; + } + else + { + matched = acls->authorize(uid, + groups, + AuthRequest::HOST, + host->get_hid(), + -1, + AuthRequest::USE); + } } else { - //TODO Log debug info (user not authorized)? continue; } if ( matched == false ) { + ostringstream oss; + + oss << "Host " << host->get_hid() << + " filtered out. User is not authorized to use it."; + + NebulaLog::log("SCHED",Log::DEBUG,oss); continue; } // ----------------------------------------------------------------- @@ -370,6 +394,16 @@ void Scheduler::match() vm->add_host(host->get_hid()); } } + else + { + ostringstream oss; + + oss << "Host " << host->get_hid() << + " filtered out. It does not have enough capacity."; + + NebulaLog::log("SCHED",Log::DEBUG,oss); + + } } } } diff --git a/src/xml/ObjectXML.cc b/src/xml/ObjectXML.cc index 8e30594b9f..d0704eb9aa 100644 --- a/src/xml/ObjectXML.cc +++ b/src/xml/ObjectXML.cc @@ -222,47 +222,6 @@ int ObjectXML::xpath(unsigned int& value, const char * xpath_expr, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -long long ObjectXML::xpath(long long& value, const char * xpath_expr, - const long long& def, bool hex) -{ - vector values; - int rc = 0; - - values = (*this)[xpath_expr]; - - if (values.empty() == true) - { - value = def; - rc = -1; - } - else - { - istringstream iss; - - iss.str(values[0]); - - if ( hex ) - { - iss >> hex >> value; - } - else - { - iss >> dec >> value; - } - - if (iss.fail() == true) - { - value = def; - rc = -1; - } - } - - return rc; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - int ObjectXML::xpath(time_t& value, const char * xpath_expr, const time_t& def) { int int_val;