Uploaded image for project: 'Project Quay'
  1. Project Quay
  2. PROJQUAY-5880

LDAP is being searched with the Quay username and not the LDAP UID

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done-Errata
    • Icon: Normal Normal
    • quay-v3.15.2
    • None
    • quay
    • False
    • Hide

      None

      Show
      None
    • False
    • Quay
    • Hide
      1. Set Quay in debug mode: USERS_DEBUG=1 and DEBUGLOG=true
      2. Set `LDAP_UID_ATTR` to an identifier with characters in it e.g. an email address test@example.com
      3. Set `LDAP_SUPERUSER_FILTER` to proposed Quay superusers
      4. Log onto Quay as a user which is expected to be a superuser
      5. As this is that users first time logging in and its UID has characters in it Quay suggests a new username with unscores instead so accept that Quay proposed username
      6. Now logged into Quay UI see if you have the superuser admin panel
      Show
      Set Quay in debug mode: USERS_DEBUG=1 and DEBUGLOG=true Set `LDAP_UID_ATTR` to an identifier with characters in it e.g. an email address test@example.com Set `LDAP_SUPERUSER_FILTER` to proposed Quay superusers Log onto Quay as a user which is expected to be a superuser As this is that users first time logging in and its UID has characters in it Quay suggests a new username with unscores instead so accept that Quay proposed username Now logged into Quay UI see if you have the superuser admin panel

      Issue

      When setting LDAP_UID_ATTR to an identifier which has a non-docker compatible character e.g. `@` Quay then remaps those characters to underscores e.g. test@example.com would map to test_example_com.

      This is not an issue for logging in, users can seemingly initially log in okay, however, under the covers Quay is attempting to perform an LDAP search to bring back user info for permissions based on that user's Quay ID and not the actual LDAP ID to get its groups.

      The below extracts from Quay app logs (with user debug turned on) illustrate this:

      gunicorn-web stdout | 2023-07-24 08:51:50,805 [203] [DEBUG] [endpoints.api] Checking permission <class 'auth.permissions.UserAdminPermission'> for user test_example_com
      gunicorn-web stdout | 2023-07-24 08:51:50,805 [203] [DEBUG] [auth.permissions] Loading user permissions after deferring for: 57dd98a8-d745-46e7-af84-68ab1691cb57
      gunicorn-web stdout | 2023-07-24 08:51:50,805 [203] [DEBUG] [auth.permissions] User permission: _UserTypeNeed(type='user', username='test_example_com', role='admin')
      gunicorn-web stdout | 2023-07-24 08:51:50,805 [203] [DEBUG] [auth.permissions] User namespace permission: _NamespaceWideNeed(type='organization', namespace='test_example_com', role='admin')
      gunicorn-web stdout | 2023-07-24 08:51:50,805 [203] [DEBUG] [auth.permissions] User namespace repo permission: _NamespaceWideNeed(type='organizationrepo', namespace='test_example_com',

       

      gunicorn-web stdout | 2023-07-24 08:51:50,882 [205] [DEBUG] [data.users.externalldap] Incoming username or email param: 'test_example_com' gunicorn-web stdout | 2023-07-24 08:51:50,883 [205] [DEBUG] [data.users.externalldap] Conducting user search: (&(&(|(desktopProfile=test_example_com)(mail=test_example_com))(&(|(memberof=CN=Quay,OU=Groups - Security,OU=Group Policy OU,DC=examplelab,DC=internal)(memberof=CN=QuayTest,OU=Groups - Security,OU=Group Policy OU,DC=examplelab,DC=internal))(objectcategory=person)(desktopProfile=*)))(memberof=CN=QuayAdmins,OU=Groups - Security,OU=Group Policy OU,DC=examplelab,DC=internal)) under ou="Group Policy OU",dc=examplelab,dc=internal gunicorn-web stdout | *** <ldap.ldapobject.SimpleLDAPObject object at 0x7f98c6d87fd0> ldap://windowsdc.examplelab.internal - SimpleLDAPObject.search_ext gunicorn-web stdout | (('ou="Group Policy OU",dc=examplelab,dc=internal', gunicorn-web stdout |   2, gunicorn-web stdout |   '(&(&(|(desktopProfile=test_example_com)(mail=test_example_com))(&(|(memberof=CN=Quay,OU=Groups ' gunicorn-web stdout |   '- Security,OU=Group Policy ' gunicorn-web stdout |   'OU,DC=examplelab,DC=internal)(memberof=CN=QuayTest,OU=Groups - ' gunicorn-web stdout |   'Security,OU=Group Policy ' gunicorn-web stdout |   'OU,DC=examplelab,DC=internal))(objectcategory=person)(desktopProfile=*)))(memberof=CN=QuayAdmins,OU=Groups ' gunicorn-web stdout |   '- Security,OU=Group Policy OU,DC=examplelab,DC=internal))', gunicorn-web stdout |   None, gunicorn-web stdout |   0, gunicorn-web stdout |   None, gunicorn-web stdout |   None, gunicorn-web stdout |   -1, gunicorn-web stdout |   0), gunicorn-web stdout |  {}) gunicorn-web stdout | => result: gunicorn-web stdout | 2 gunicorn-web stdout | *** <ldap.ldapobject.SimpleLDAPObject object at 0x7f98c6d87fd0> ldap://windowsdc.examplelab.internal - SimpleLDAPObject.result4 gunicorn-web stdout | ((2, 1, -1, 0, 0, 0), {}) gunicorn-web stdout | => result: gunicorn-web stdout | (101, [], 2, []) gunicorn-web stdout | 2023-07-24 08:51:50,885 [205] [DEBUG] [data.users.externalldap] Found matching DNs: [] gunicorn-web stdout | *** <ldap.ldapobject.SimpleLDAPObject object at 0x7f98c6d87fd0> ldap://windowsdc.examplelab.internal - SimpleLDAPObject.unbind_ext gunicorn-web stdout | ((None, None), {}) gunicorn-web stdout | => result: gunicorn-web stdout | None gunicorn-web stdout | 2023-07-24 08:51:50,888 [205] [DEBUG] [data.users.externalldap] LDAP superuser test_example_com not found: Invalid username or password. gunicorn-web stdout | 2023-07-24 08:51:50,893 [205] [DEBUG] [peewee] ('SELECT "t1"."id", "t1"."uuid", "t1"."username", "t1"."password_hash", "t1"."email", "t1"."verified", "t1"."stripe_id", "t1"."organization", "t1"."robot", "t1"."invoice_email", "t1"."invalid_login_attempts", "t1"."last_invalid_login", "t1"."removed_tag_expiration_s", "t1"."enabled", "t1"."invoice_email_address", "t1"."given_name", "t1"."family_name", "t1"."company", "t1"."location", "t1"."maximum_queued_builds_count", "t1"."creation_date", "t1"."last_accessed" FROM "user" AS "t1" WHERE ("t1"."username" = %s) LIMIT %s OFFSET %s', ['test_example_com', 1, 0])
      

      This presents quite an issue and thus it's impossible to define superusers in the `LDAP_SUPERUSER_FILTER` as no matter what, permissions are looking to be derived from this ldap search, which at this moment is using the wrong identifier within its query.

      I believe the issue sits within the ldap search query, as that ldap search string is being built with the Quay username and in this case that search will only ever work when the user in Quay is exactly like the UID in LDAP. As we have options in Quay to change/confirm your username this is an issue. I think our ldap search builder construct needs to be amended to use the users LDAP uid.

      Tested on Quay 3.8.10

      Reproducer:

      1. Set Quay in debug mode: USERS_DEBUG=1 and DEBUGLOG=true
      2. Set `LDAP_UID_ATTR` to an identifier with characters in it e.g. an email address test@example.com
      3. Set `LDAP_SUPERUSER_FILTER` to proposed Quay superusers
      4. Log onto Quay as a user which is expected to be a superuser
      5. As this is that users first time logging in and its UID has characters in it Quay suggests a new username with unscores instead so accept that Quay proposed username
      6. Now logged into Quay UI see if you have the superuser admin panel

      Example LDAP config

      # LDAP Configuration
      FEATURE_TEAM_SYNCING: true
      TEAM_RESYNC_STALE_TIME: 60m
      AUTHENTICATION_TYPE: LDAP
      LDAP_SUPERUSER_FILTER: (memberof=CN=QuayAdmins,OU=Groups - Security,OU=Group Policy OU,DC=examplelab,DC=internal)
      LDAP_ADMIN_DN: "CN=admin,CN=Managed Service Accounts,DC=examplelab,DC=internal"
      LDAP_ADMIN_PASSWD: {{ ldap_bind_password }}
      LDAP_ALLOW_INSECURE_FALLBACK: false
      LDAP_BASE_DN:
          - dc=examplelab
          - dc=internal
      LDAP_USER_RDN:
          - ou="Group Policy OU"
      LDAP_UID_ATTR: desktopProfile
      LDAP_EMAIL_ATTR: mail
      LDAP_URI: ldap://windowsdc.examplelab.internal
      LDAP_USER_FILTER: (&(|(memberof=CN=Quay,OU=Groups - Security,OU=Group Policy OU,DC=examplelab,DC=internal)(memberof=CN=QuayTest,OU=Groups - Security,OU=Group Policy OU,DC=examplelab,DC=internal))(objectcategory=person)(desktopProfile=*))
      FEATURE_RESTRICTED_USERS: true
      LDAP_RESTRICTED_USER_FILTER: (memberof=CN=QuayRestricted,OU=Groups - Security,OU=Group Policy OU,DC=examplelab,DC=internal) 

              Unassigned Unassigned
              jforce1 James Force
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: