Bug 1602845 - Users are unable to log in to UI when utilizing Active Directory, failing with "unable to match user's group membership to an EVM role" unless get_direct_groups is set
Summary: Users are unable to log in to UI when utilizing Active Directory, failing wit...
Keywords:
Status: CLOSED CURRENTRELEASE
Alias: None
Product: Red Hat CloudForms Management Engine
Classification: Red Hat
Component: Documentation
Version: 5.9.0
Hardware: Unspecified
OS: Unspecified
high
high
Target Milestone: GA
: 5.9.4
Assignee: Dayle Parker
QA Contact: Suyog Sainkar
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2018-07-18 15:40 UTC by Robb Manes
Modified: 2021-09-09 15:05 UTC (History)
15 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2018-08-10 12:10:54 UTC
Category: ---
Cloudforms Team: ---
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Bugzilla 1602103 0 medium CLOSED LDAP/LDAPS said to be deprecated but not reflected in CloudForms documentation 2021-02-22 00:41:40 UTC

Internal Links: 1602103

Description Robb Manes 2018-07-18 15:40:56 UTC
Description of problem:
Our base issue is an inability to log in with LDAP users, provided by a Microsoft AD.  When they attempt to log in, they are greeted with "Invalid username/password", however the logs show we hit this condition 
with an empty matching_groups set:

module Authenticator
  class Base
- - - - - 8< - - - - -
    def authorize(taskid, username, *args)
      audit = {:event => "authorize", :userid => username}
      decrypt_ldap_password(config) if MiqLdap.using_ldap?

      run_task(taskid, "Authorizing") do |task|
        begin
          identity = find_external_identity(username, *args)

          unless identity
            msg = "Authentication failed for userid #{username}, unable to find user object in #{self.class.proper_name}"
            _log.warn(msg)
            AuditEvent.failure(audit.merge(:message => msg))
            task.error(msg)
            task.state_finished
            return nil
          end

          matching_groups = match_groups(groups_for(identity))
          userid, user = find_or_initialize_user(identity, username)
          update_user_attributes(user, userid, identity)
          user.miq_groups = matching_groups

          if matching_groups.empty?
            msg = "Authentication failed for userid #{user.userid}, unable to match user's group membership to an EVM role"
- - - - - 8< - - - - -

Reviewing the logs and the appliance, and adding our own debugging, we found that our matching_groups set from match_groups() was due to an empty set being returned by groups_for for the identity provided.  In match_groups, since we are supplied an empty set, we bail early in the method:

    def match_groups(external_group_names)
      return [] if external_group_names.empty?
- - - - - 8< - - - - -

However, in the groups_for method, we return an empty set every time, which causes us to fall through to matching_groups.empty? in the base authorize method, causing the error/exception.

module Authenticator
  class Ldap < Base
- - - - - 8< - - - - -
    def groups_for(obj)
      authentication = config.dup
      authentication[:group_memberships_max_depth] ||= DEFAULT_GROUP_MEMBERSHIPS_MAX_DEPTH

      if authentication.key?(:user_proxies) && !authentication[:user_proxies].blank? && authentication.key?(:get_direct_groups) && authentication[:get_direct_groups] == false
        _log.info("Skipping getting group memberships directly assigned to user bacause it has been disabled in the configuration")
        groups = []
      else
        groups = ldap.get_memberships(obj, authentication[:group_memberships_max_depth])
      end

      if authentication.key?(:user_proxies)
        if (sid = MiqLdap.get_attr(obj, :objectsid))
          authentication[:user_proxies].each do |auth|
            begin
              groups += user_proxy_membership(auth, MiqLdap.sid_to_s(sid))
            rescue Exception => err
              _log.warn("#{err.message} (from Authenticator#user_proxy_membership)")
            end
          end
        else
          _log.warn("User Object has no objectSID")
        end
      end

      groups.uniq
    end

In the above, we have no user_proxies and by default get_direct_groups is false, so we start by assigning groups as an empty set.  Since we have no user_proxies, we skip user_proxy_membership and the group set remains blank.  Unless we set get_direct_groups to true under the authentication section of the advanced settings, which causes get_memberships on the ldap object to run, we will always return an empty set unless user_proxies are also in place.

With the end goal of having as fast and efficient, as well as working, LDAP logins being possible, a few questions:

- What is the purpose of get_direct_groups in this context?
- In order for authorization to function when doing group lookups, when get_direct_groups is set to false, do we always expect there to be a user_proxies setting?
- Is the solution to this to ensure get_direct_groups is set to true so appropriate LDAP lookups can be performed for each login?
- Is there some other thing I am missing concerning how we validate groups so that we do not get an empty set when validating a user's authorization?

Version-Release number of selected component (if applicable):
5.9.2.4

How reproducible:
Every time, while get_direct_groups is false.  Works when get_direct_groups is true.

Steps to Reproduce:
1. In their environment, connect AD to CFME environment.
2. Accept defaults and map groups to EVM roles appropriately
3. Be unable to log in

Actual results:
Users are unable to log in unless get_direct_groups is set.

Expected results:
Logins should match users to groups as expected under the correct default conditions, if what we are utilizing is correct and nothing special.

Additional info:
We have validated the groups returned by the AD by basic tests such as ldapsearch from the appliance.

Comment 5 Robb Manes 2018-07-18 17:18:58 UTC
So, it appears I was very wrong, the default for get_direct_groups is true:

config/settings.yml:  :get_direct_groups: true

An explanation of this setting would be helpful, although we can see what it does here; it appears maybe this is a check box when setting up LDAPS and this is possibly just misconfiguration.

Comment 6 Robb Manes 2018-07-18 17:26:32 UTC
This bug can probably be closed; it turns out we have unchecked "Get Roles from Home Forest" from the UI, defined here:

    = hidden_div_if(!@edit[:new][:authentication][:ldap_role], :id => "ldap_role_details_div") do
      .form-horizontal
        .form-group#get_roles_now{:style => @edit[:new][:authentication][:user_proxies].blank? ? "display: none" : ""}
          %label.col-md-2.control-label
            = _("Get Roles from Home Forest")
          .col-md-8
            = check_box_tag("get_direct_groups", "1",
                            @edit[:new][:authentication][:get_direct_groups],
                            "data-miq_observe_checkbox" => {:url => url}.to_json)


The confusion was concerning the wording of the button, as they (and I) thought it had more to do with roles than groups.

We'd still like a definition as to what the usage of get_direct_groups is intended to be and an explanation of how it matches the description of the button, since that was the point of confusion, but all seems well now.  Thanks!

Comment 7 Joe Vlcek 2018-07-18 18:01:58 UTC
Closing based on phone discussion with Robb. 

Thanks for the great analysis Robb!

Bottom line is if "Get User Groups from LDAP" is checked
then "Get Roles from Home Forest" needs to be checked.

Comment 8 Gregg Tanzillo 2018-07-18 19:00:55 UTC
Regarding comment #6, I'm changing this to a doc bug. Looking at the current documentation in https://access.redhat.com/documentation/en-us/red_hat_cloudforms/4.6/html/managing_authentication_for_cloudforms/ldap_settings#ldap_config section 2.1.7 talks about "roles" when it should be "groups" because group assignment is the important thing here. I think that is partly responsible for the confusion causing this BZ to be opened. The words role and group are being conflated and causing the misunderstanding.

Comment 15 Joe Vlcek 2018-08-07 15:26:35 UTC
This should no longer be a blocker. The customer is up and running and is willing to close this BZ.

Before we resolved the customer issue this was correctly marked a blocker.

Then we closed this bug as not a bug.

GreggT decided to reopen as a documentation issue so we can get the documentation
clearer to help avoid the same confusion in the future. Unfortunately the blocker
flag was still set when the bug was reopened.

I discussed with GreggT and we both feel this should not be a blocker.

I will meet with Dayle to resolve her questions.

JoeV

Comment 22 Dayle Parker 2018-08-10 12:10:54 UTC
Updates for this BZ are now in the CloudForms 4.6 Managing Authentication guide published on the Customer Portal (in chapters 2 and 4):

https://access.redhat.com/documentation/en-us/red_hat_cloudforms/4.6/html-single/managing_authentication_for_cloudforms/


Note You need to log in before you can comment on or make changes to this bug.