Skip to content

Commit e0423c1

Browse files
committed
add httpd authentication
1 parent 171ada3 commit e0423c1

File tree

2 files changed

+100
-2
lines changed

2 files changed

+100
-2
lines changed

vmdb/app/controllers/dashboard_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ def validate_user(user)
644644

645645
# Call the authentication, use wait_for_task if a task is spawned
646646
begin
647-
user_or_taskid = User.authenticate(user[:name],user[:password])
647+
user_or_taskid = User.authenticate(user[:name], user[:password], request)
648648
rescue MiqException::MiqEVMLoginError => err
649649
@flash_msg = I18n.t("flash.authentication.error")
650650
user[:name] = nil

vmdb/app/models/user.rb

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def self.verify_ldap_credentials(username, password)
214214
raise MiqException::MiqEVMLoginError, "authentication failed" unless ldap.bind(fq_user, password)
215215
end
216216

217-
def self.authenticate(username, password)
217+
def self.authenticate(username, password, request = nil)
218218
fail_message = "Authentication failed"
219219
mode = self.mode
220220

@@ -225,6 +225,8 @@ def self.authenticate(username, password)
225225
self.authenticate_ldap(username, password)
226226
elsif mode == "amazon"
227227
self.authenticate_amazon(username, password)
228+
elsif mode == "httpd"
229+
authenticate_httpd(username, request)
228230
end
229231

230232
raise MiqException::MiqEVMLoginError, fail_message if user_or_taskid.nil?
@@ -454,6 +456,94 @@ def self.authorize_ldap(taskid, fq_user)
454456
end
455457
end
456458

459+
def self.authenticate_httpd(username, request)
460+
audit = {:event => "authenticate_httpd", :userid => username}
461+
if request.nil?
462+
AuditEvent.failure(audit.merge(:message => "Authentication failed for user #{username}, request missing"))
463+
nil
464+
elsif request.headers['X_REMOTE_USER'].present?
465+
AuditEvent.success(audit.merge(:message => "User #{username} successfully validated by httpd"))
466+
467+
if VMDB::Config.new("vmdb").config[:authentication][:httpd_role] == true
468+
user = authorize_httpd_queue(username, request)
469+
else
470+
# If role_mode == database we will only use httpd for authentication. Also, the user must exist in our database
471+
# otherwise we will fail authentication
472+
unless (user = find_by_userid(username))
473+
AuditEvent.failure(audit.merge(:message => "User #{username} authenticated but not defined in EVM"))
474+
raise MiqException::MiqEVMLoginError,
475+
"User authenticated but not defined in EVM, please contact your EVM administrator"
476+
end
477+
end
478+
479+
AuditEvent.success(audit.merge(:message => "Authentication successful for user #{username}"))
480+
user
481+
else
482+
external_auth_error = request.headers['HTTP_X_EXTERNAL_AUTH_ERROR']
483+
AuditEvent.failure(audit.merge(:message => "Authentication failed for userid #{username} #{external_auth_error}"))
484+
nil
485+
end
486+
end
487+
488+
def self.authorize_httpd_queue(username, request)
489+
task = MiqTask.create(:name => "External httpd User Authorization of '#{username}'", :userid => username)
490+
user_attrs = {:username => username,
491+
:fullname => request.headers['X_REMOTE_USER_FULLNAME'],
492+
:firstname => request.headers['X_REMOTE_USER_FIRSTNAME'],
493+
:lastname => request.headers['X_REMOTE_USER_LASTNAME'],
494+
:email => request.headers['X_REMOTE_USER_EMAIL']}
495+
membership_list = (request.headers['X_REMOTE_USER_GROUPS'] || '').split(":")
496+
497+
if !MiqEnvironment::Process.is_ui_worker_via_command_line?
498+
authorize_httpd(task.id, username, user_attrs, membership_list)
499+
else
500+
MiqQueue.put(
501+
:queue_name => "generic",
502+
:class_name => to_s,
503+
:method_name => "authorize_httpd",
504+
:args => [task.id, username, user_attrs, membership_list],
505+
:server_guid => MiqServer.my_guid,
506+
:priority => MiqQueue::HIGH_PRIORITY,
507+
:miq_callback => {
508+
:class_name => task.class.name,
509+
:instance_id => task.id,
510+
:method_name => :queue_callback_on_exceptions,
511+
:args => ['Finished']
512+
})
513+
end
514+
515+
task.id
516+
end
517+
518+
def self.authorize_httpd(taskid, username, user_attrs, membership_list)
519+
log_prefix = "MIQ(User.authorize_httpd):"
520+
audit = {:event => "authorize_httpd", :userid => username}
521+
522+
task = MiqTask.find_by_id(taskid)
523+
if task.nil?
524+
message = "#{log_prefix} Unable to find task with id: [#{taskid}]"
525+
$log.error(message)
526+
raise message
527+
end
528+
task.update_status("Active", "Ok", "Authorizing")
529+
530+
begin
531+
VMDB::Config.new("vmdb").config[:authentication]
532+
$log.info("#{log_prefix} User: [#{username}]")
533+
534+
matching_groups = match_groups(membership_list)
535+
user = find_by_userid(username) || new(:userid => username)
536+
user.update_attrs_from_httpd(user_attrs)
537+
user.save_successful_logon(matching_groups, audit, task)
538+
rescue err
539+
$log.log_backtrace(err)
540+
task.error(err.message)
541+
AuditEvent.failure(audit.merge(:message => err.message))
542+
task.state_finished
543+
raise
544+
end
545+
end
546+
457547
def self.authenticate_with_http_basic(username, password)
458548
u = username.dup
459549
user = User.find_by_userid(u)
@@ -551,6 +641,14 @@ def update_attrs_from_ldap(ldap, obj)
551641
self.email = email unless email.blank?
552642
end
553643

644+
def update_attrs_from_httpd(user_attrs)
645+
self.userid = user_attrs[:username]
646+
self.name = user_attrs[:fullname]
647+
self.first_name = user_attrs[:firstname]
648+
self.last_name = user_attrs[:lastname]
649+
self.email = user_attrs[:email] unless user_attrs[:email].blank?
650+
end
651+
554652
def update_attrs_from_iam(amazon_auth, amazon_user, username)
555653
self.userid = username
556654
self.name = amazon_user.name

0 commit comments

Comments
 (0)