From 65606e7faf715a0d47d0f2346f3f87061236a62e Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Wed, 27 Jul 2011 11:27:16 +0200 Subject: [PATCH 01/63] feture-754: OpenNebula core sends information about the ACL authZ result to the driver. Improved formating of auth strings. Check trivial authZ requests. --- include/AuthManager.h | 13 ++++++-- include/AuthManagerDriver.h | 6 ++-- src/authm/AuthManager.cc | 19 ++++++++--- src/authm/AuthManagerDriver.cc | 7 ++-- src/authm/test/AuthManagerTest.cc | 53 +++++++++++++++++++++++++++++-- 5 files changed, 85 insertions(+), 13 deletions(-) diff --git a/include/AuthManager.h b/include/AuthManager.h index e2331d7cb9..60322e9a1f 100644 --- a/include/AuthManager.h +++ b/include/AuthManager.h @@ -385,17 +385,26 @@ public: /** * Gets the authorization requests in a single string - * @return a space separated list of auth requests. + * @return a space separated list of auth requests, or an empty string if + * no auth requests were added */ string get_auths() { ostringstream oss; + unsigned int i; - for (unsigned int i=0; imessage = "Could not find Authorization driver"; + goto error; } // ------------------------------------------------------------------------ @@ -300,15 +301,23 @@ void AuthManager::authorize_action(AuthRequest * ar) auths = ar->get_auths(); - authm_md->authorize(ar->id, ar->uid, auths); + if ( auths.empty() ) + { + ar->message = "Empty authorization string"; + goto error; + } + + authm_md->authorize(ar->id, ar->uid, auths, ar->self_authorize); return; -error_driver: - ar->result = false; - ar->message = "Could not find Authorization driver"; +error: + ar->result = false; ar->notify(); + + return; } + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/src/authm/AuthManagerDriver.cc b/src/authm/AuthManagerDriver.cc index 43a29445f4..1722d0e14e 100644 --- a/src/authm/AuthManagerDriver.cc +++ b/src/authm/AuthManagerDriver.cc @@ -25,11 +25,14 @@ /* Driver ASCII Protocol Implementation */ /* ************************************************************************** */ -void AuthManagerDriver::authorize(int oid, int uid, const string& reqs) const +void AuthManagerDriver::authorize(int oid, + int uid, + const string& reqs, + bool acl) const { ostringstream os; - os << "AUTHORIZE " << oid << " " << uid << " " << reqs << endl; + os << "AUTHORIZE " << oid << " " << uid << " " << reqs << " " << acl <trigger(AuthManager::AUTHORIZE,&ar); ar.wait(); - /* if ( ar.result != false ) { @@ -229,6 +228,56 @@ public: //*/ CPPUNIT_ASSERT(ar.result==false); CPPUNIT_ASSERT(ar.message==astr); + + AuthRequest ar1(2, 2); + + string astr1= "VM:VGhpcyBpcyBhIHRlbXBsYXRlCg==:CREATE:-1:0:0 0"; + + ar1.add_auth(AuthRequest::VM, + "This is a template\n", + 0, + AuthRequest::CREATE, + -1, + false); + + am->trigger(AuthManager::AUTHORIZE,&ar1); + ar1.wait(); + /* + if ( ar1.result != false ) + { + cout << endl << "ar.result: " << ar1.result << endl; + } + + if ( ar1.message != astr1 ) + { + cout << endl << "ar.message: " << ar1.message; + cout << endl << "expected: " << astr1 << endl; + } +//*/ + CPPUNIT_ASSERT(ar1.result==false); + CPPUNIT_ASSERT(ar1.message==astr1); + + AuthRequest ar2(2, 2); + + string astr2= "Empty authorization string"; + + + am->trigger(AuthManager::AUTHORIZE,&ar2); + ar2.wait(); +/* + if ( ar1.result != false ) + { + cout << endl << "ar.result: " << ar1.result << endl; + } + + if ( ar1.message != astr1 ) + { + cout << endl << "ar.message: " << ar1.message; + cout << endl << "expected: " << astr1 << endl; + } +//*/ + CPPUNIT_ASSERT(ar2.result==false); + CPPUNIT_ASSERT(ar2.message==astr2); } From 72008ecfb7113866703f2f5e319f3e453d32fbc1 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Wed, 27 Jul 2011 17:50:49 +0200 Subject: [PATCH 02/63] feature-754: New auth driver. Minor indent changes. --- src/authm/AuthManagerDriver.cc | 8 +- src/authm_mad/one_auth_mad.rb | 170 +++++++++++++++++++------------ src/mad/ruby/OpenNebulaDriver.rb | 18 ++-- 3 files changed, 118 insertions(+), 78 deletions(-) diff --git a/src/authm/AuthManagerDriver.cc b/src/authm/AuthManagerDriver.cc index 1722d0e14e..ab12138c94 100644 --- a/src/authm/AuthManagerDriver.cc +++ b/src/authm/AuthManagerDriver.cc @@ -38,10 +38,10 @@ void AuthManagerDriver::authorize(int oid, } void AuthManagerDriver::authenticate(int oid, - int uid, - const string& username, - const string& password, - const string& session) const + int uid, + const string& username, + const string& password, + const string& session) const { ostringstream os; diff --git a/src/authm_mad/one_auth_mad.rb b/src/authm_mad/one_auth_mad.rb index fbc9af163a..adccafdadb 100755 --- a/src/authm_mad/one_auth_mad.rb +++ b/src/authm_mad/one_auth_mad.rb @@ -28,87 +28,125 @@ end $: << RUBY_LIB_LOCATION -require 'pp' -require 'rubygems' require 'OpenNebulaDriver' -require 'simple_auth' -require 'simple_permissions' -require 'yaml' -require 'sequel' -require 'ssh_auth' +require 'getoptlong' -class AuthorizationManager < OpenNebulaDriver - def initialize +# This is a generic AuthZ/AuthN driver able to manage multiple authentication +# protocols (simultaneosly). It also supports the definition of custom +# authorization methods +class AuthDriver < OpenNebulaDriver + + # Auth Driver Protocol constants + ACTION = { + :authN => "AUTHENTICATE", + :authZ => "AUTHORIZE" + } + + # Initialize an AuthDriver + # + # @param [String] the authorization method to be used, nil to use the + # built-in ACL engine + def initialize(authZ, nthreads) super( - :concurrency => 15, - :threaded => true + "auth", + :concurrency => nthreads, + :threaded => nthreads > 0, + :local_actions => {ACTION[:authN] => nil, ACTION[:authZ] => nil} ) + + register_action(ACTION[:authN].to_sym, method("authN")) + register_action(ACTION[:authZ].to_sym, method("authZ")) + + if authZ != nil + @authZ_cmd = File.join(@local_scripts_path, authZ) + @authZ_cmd = File.join(@authZ_cmd, ACTION[:authZ].downcase) + else + @authZ_cmd = nil + end + end + + # Authenticate a user based in a string of the form user:secret when using the + # driver secret is protocol:token + # @param [String] the id for this request, used by OpenNebula core + # to identify the request + # @param [String] id of the user, "-1" if not in defined in OpenNebula + # @param [Strgin] user filed of the auth string + # @param [String] password of the user registered in OpenNebula "-" if none + # @param [String] secret filed of the auth string + def authN(request_id, user_id, user, password, secret) + + secret_attr = secret.split(':') + + if secret_attr.length == 1 + protocol = "plain" + else + protocol = secret_attr[0] + secret_attr.shift + end + + #build path for the auth action + #/var/lib/one/remotes/auth//authenticate + authN_path = File.join(@local_scripts_path, protocol) - config_data=File.read(ETC_LOCATION+'/auth/auth.conf') - STDERR.puts(config_data) - @config=YAML::load(config_data) + command = File.join(authN_path,ACTION[:authN].downcase) + command << ' ' << secret_attr.join(' ') + + local_action(command, request_id, ACTION[:authN]) + end + + # Authenticate a user based in a string of the form user:secret when using the + # driver secret is protocol:token + # @param [String] the id for this request, used by OpenNebula core + # to identify the request + # @param [String] id of the user, "-1" if not in defined in OpenNebula + # @param [Array] of auth strings, last element is the ACL evaluation of + # the overall request (0 = denied, 1 = granted). Each request is in + # the form: + # OBJECT::OPERATION:OWNER:PUBLIC:ACL_EVAL + def authZ(request_id, user_id, *requests) - STDERR.puts @config.inspect - - database_url=@config[:database] - @db=Sequel.connect(database_url) - - # Get authentication driver - begin - driver_prefix=@config[:authentication].capitalize - driver_name="#{driver_prefix}Auth" - driver=Kernel.const_get(driver_name.to_sym) - @authenticate=driver.new + requests.flatten! + + if @authZ_cmd == nil + if requests[-1] == "1" + result = RESULT[:success] + else + result = RESULT[:failure] + end + + send_message(ACTION[:authZ],result,request_id,"-") + else + command = @authZ_cmd + command << ' ' << requests.join(' ') - STDERR.puts "Using '#{driver_prefix}' driver for authentication" - rescue - STDERR.puts "Driver '#{driver_prefix}' not found, "<< - "using SimpleAuth instead" - @authenticate=SimpleAuth.new - end - - @permissions=SimplePermissions.new(@db, OpenNebula::Client.new, - @config) - - register_action(:AUTHENTICATE, method('action_authenticate')) - register_action(:AUTHORIZE, method('action_authorize')) - end - - def action_authenticate(request_id, user_id, user, password, token) - auth=@authenticate.auth(user_id, user, password, token) - if auth==true - send_message('AUTHENTICATE', RESULT[:success], - request_id, 'Successfully authenticated') - else - send_message('AUTHENTICATE', RESULT[:failure], - request_id, auth) - end - end - - def action_authorize(request_id, user_id, *tokens) - begin - auth=@permissions.auth(user_id, tokens.flatten) - rescue Exception => e - auth="Error: #{e}" - end - - if auth==true - send_message('AUTHORIZE', RESULT[:success], - request_id, 'success') - else - send_message('AUTHORIZE', RESULT[:failure], - request_id, auth) + local_action(command, request_id, ACTION[:authZ]) end end end +# Auth Driver Main program +opts = GetoptLong.new( + [ '--threads', '-t', GetoptLong::REQUIRED_ARGUMENT ], + [ '--authz', '-z', GetoptLong::REQUIRED_ARGUMENT ] +) + +threads = 15 +authz = nil + begin - am=AuthorizationManager.new + opts.each do |opt, arg| + case opt + when '--threads' + threads = arg.to_i + when '--authz' + authz = arg + end + end rescue Exception => e - puts "Error: #{e}" exit(-1) end -am.start_driver +auth_driver = AuthDriver.new(authz, threads) +auth_driver.start_driver diff --git a/src/mad/ruby/OpenNebulaDriver.rb b/src/mad/ruby/OpenNebulaDriver.rb index 7b32ad705a..6129795d3a 100644 --- a/src/mad/ruby/OpenNebulaDriver.rb +++ b/src/mad/ruby/OpenNebulaDriver.rb @@ -90,20 +90,22 @@ class OpenNebulaDriver < ActionManager def initialize(directory, options={}) @options={ :concurrency => 10, - :threaded => true, - :retries => 0, + :threaded => true, + :retries => 0, :local_actions => {} }.merge!(options) super(@options[:concurrency], @options[:threaded]) - @retries = @options[:retries] - @send_mutex=Mutex.new - @local_actions=@options[:local_actions] + @retries = @options[:retries] + @local_actions = @options[:local_actions] + + @send_mutex = Mutex.new # set default values @config = read_configuration - @remote_scripts_base_path=@config['SCRIPTS_REMOTE_DIR'] + @remote_scripts_base_path = @config['SCRIPTS_REMOTE_DIR'] + if ENV['ONE_LOCATION'] == nil @local_scripts_base_path = "/var/lib/one/remotes" else @@ -111,8 +113,8 @@ class OpenNebulaDriver < ActionManager end # dummy paths - @remote_scripts_path=File.join(@remote_scripts_base_path, directory) - @local_scripts_path=File.join(@local_scripts_base_path, directory) + @remote_scripts_path = File.join(@remote_scripts_base_path, directory) + @local_scripts_path = File.join(@local_scripts_base_path, directory) register_action(:INIT, method("init")) end From 0846bcea0b1517b16be4770893e5b47fe0823dc2 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 28 Jul 2011 03:41:41 +0200 Subject: [PATCH 03/63] feature-754: use username instead of uids for a ssh proxy. Removed quota temporarily --- src/authm_mad/oneauth | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/authm_mad/oneauth b/src/authm_mad/oneauth index 965cdb84cc..f5b7f610f7 100755 --- a/src/authm_mad/oneauth +++ b/src/authm_mad/oneauth @@ -35,7 +35,6 @@ require 'OpenNebula' require 'rubygems' require 'sequel' -require 'quota' require 'ssh_auth' require 'yaml' @@ -89,7 +88,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do the expiration time in seconds EOT - command 'login', login_desc, :userid, :text do + command 'login', login_desc, :text, :text do user=args[0] time=args[1] pp args @@ -106,7 +105,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do command 'key', 'Gets public key' do ssh=SshAuth.new - puts ssh.extract_public_key + puts ssh.public_key exit_with_code 0 end -end \ No newline at end of file +end From f725fe966799fd31564a0819495663a4e7fe20f7 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Thu, 28 Jul 2011 03:43:50 +0200 Subject: [PATCH 04/63] feature-754: Work on one_auth. Added ssh authenticate. Place holder for other protocols --- install.sh | 17 +-- src/authm_mad/one_auth_mad.rb | 5 +- .../plain/authenticate} | 0 .../{quota.rb => remotes/quota/authorize} | 0 src/authm_mad/remotes/ssh/authenticate | 49 ++++++++ src/authm_mad/ssh_auth.rb | 114 ------------------ src/um/UserPool.cc | 3 + 7 files changed, 66 insertions(+), 122 deletions(-) rename src/authm_mad/{simple_auth.rb => remotes/plain/authenticate} (100%) rename src/authm_mad/{quota.rb => remotes/quota/authorize} (100%) create mode 100755 src/authm_mad/remotes/ssh/authenticate delete mode 100644 src/authm_mad/ssh_auth.rb diff --git a/install.sh b/install.sh index b0801db3c6..709205e2d3 100755 --- a/install.sh +++ b/install.sh @@ -222,7 +222,9 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/hooks \ $VAR_LOCATION/remotes/hooks/vnm \ $VAR_LOCATION/remotes/image \ - $VAR_LOCATION/remotes/image/fs" + $VAR_LOCATION/remotes/image/fs \ + $VAR_LOCATION/remotes/auth \ + $VAR_LOCATION/remotes/auth/ssh" SUNSTONE_DIRS="$SUNSTONE_LOCATION/models \ $SUNSTONE_LOCATION/models/OpenNebulaJSON \ @@ -314,6 +316,7 @@ INSTALL_FILES=( IM_PROBES_KVM_FILES:$VAR_LOCATION/remotes/im/kvm.d IM_PROBES_XEN_FILES:$VAR_LOCATION/remotes/im/xen.d IM_PROBES_GANGLIA_FILES:$VAR_LOCATION/remotes/im/ganglia.d + AUTH_SSH_FILES:$VAR_LOCATION/remotes/auth/ssh VMM_EXEC_KVM_SCRIPTS:$VAR_LOCATION/remotes/vmm/kvm VMM_EXEC_XEN_SCRIPTS:$VAR_LOCATION/remotes/vmm/xen VMM_EXEC_XEN_KVM_POLL:$VAR_LOCATION/remotes/vmm/kvm/poll @@ -478,11 +481,7 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \ src/mad/ruby/Ganglia.rb \ src/oca/ruby/OpenNebula.rb \ src/tm_mad/TMScript.rb \ - src/authm_mad/one_usage.rb \ - src/authm_mad/quota.rb \ - src/authm_mad/simple_auth.rb \ - src/authm_mad/simple_permissions.rb \ - src/authm_mad/ssh_auth.rb" + src/authm_mad/remotes/ssh/ssh_auth.rb" #----------------------------------------------------------------------------- # MAD Script library files, to be installed under $LIB_LOCATION/