@@ -214,7 +214,7 @@ def self.verify_ldap_credentials(username, password)
214
214
raise MiqException ::MiqEVMLoginError , "authentication failed" unless ldap . bind ( fq_user , password )
215
215
end
216
216
217
- def self . authenticate ( username , password )
217
+ def self . authenticate ( username , password , request = nil )
218
218
fail_message = "Authentication failed"
219
219
mode = self . mode
220
220
@@ -225,6 +225,8 @@ def self.authenticate(username, password)
225
225
self . authenticate_ldap ( username , password )
226
226
elsif mode == "amazon"
227
227
self . authenticate_amazon ( username , password )
228
+ elsif mode == "httpd"
229
+ authenticate_httpd ( username , request )
228
230
end
229
231
230
232
raise MiqException ::MiqEVMLoginError , fail_message if user_or_taskid . nil?
@@ -454,6 +456,94 @@ def self.authorize_ldap(taskid, fq_user)
454
456
end
455
457
end
456
458
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
+
457
547
def self . authenticate_with_http_basic ( username , password )
458
548
u = username . dup
459
549
user = User . find_by_userid ( u )
@@ -551,6 +641,14 @@ def update_attrs_from_ldap(ldap, obj)
551
641
self . email = email unless email . blank?
552
642
end
553
643
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
+
554
652
def update_attrs_from_iam ( amazon_auth , amazon_user , username )
555
653
self . userid = username
556
654
self . name = amazon_user . name
0 commit comments