@@ -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