Add read-only groups attribute to instance SCIM User resource

What does this MR do and why?

The instance SCIM API can tell you who is in a SCIM group but not what groups a user belongs to. GET /Users and GET /Users/:id return no entitlement information at all, so an IdP connector that reconciles per user (such as SailPoint) has no way to verify the associations it created. RFC 7643 section 4.1.2 defines a read-only groups attribute on the User resource for this.

This MR adds it to both GET endpoints and each entry looks like:

{ "value": "<scim_group_uid>", "display": "<saml_group_name>", "type": "direct" }
  • value is the SCIM group's ID: it's the same id the Groups endpoints return, so a connector can round-trip between the two resources
  • display is the SAML group link's name, matching displayName on the Group resource
  • type is the membership type, which is always direct (see !249043 (comment 3658852666))

This is the reverse of !243439 (merged) which populated members on the Groups side.

Implementation note

The lookup runs two bounded queries rather than a join because there's no association to join through: scim_group_memberships and saml_group_links are connected by a matching scim_group_uid, not a foreign key. Both queries run once per page, so the serializer issues no queries of its own. There's a QueryRecorder spec to cover it.

References

How to set up and validate locally

  1. Set up Self-managed mode: export GITLAB_SIMULATE_SAAS=0

  2. Run gdk reconfigure

  3. Configure SAML: edit config/gitlab.yml, replacing development.omniauth.providers with the following

    Click to expand
    development:
      <<: *base
      omniauth:
        providers:
          - { name: 'saml',
              label: 'SAML',
              args: { assertion_consumer_service_url: 'http://gdk.test:3000/users/auth/saml/callback',
                      idp_cert_fingerprint: 'AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD',
                      idp_sso_target_url: 'https://example.com/sso',
                      issuer: 'http://gdk.test:3000',
                      name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' } }
  4. Start gdk: gdk start

  5. Ensure your gdk instance has an active Premium or Ultimate tier license

  6. In the rails console, seed a SCIM group and membership

    group = Group.first
    user  = group.members.last.user
    
    link = SamlGroupLink.create!(
      group: group,
      saml_group_name: 'Developers',
      access_level: ::Gitlab::Access::GUEST,
      scim_group_uid: SecureRandom.uuid
    )
    
    ScimIdentity.create!(user: user, extern_uid: 'test_uid', group: nil, active: true)
    Authn::ScimGroupMembership.create!(user: user, scim_group_uid: link.scim_group_uid)
    
    link.scim_group_uid # note this for reference in step 8.3
  7. Generate a SCIM token and note the token and URL

  8. Using the token and URL from the previous step, verify the groups attribute is returned:

    1. GET /Users/:id : curl -s "$BASE/Users/test_uid" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json"

    2. GET /Users: curl -s "$BASE/Users" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/scim+json"

    3. Each user resource includes a groups array. For a user that belongs to a SCIM group it contains one entry per group:

      "groups": [
        {
          "value": "<scim_group_uid from step 6>",
          "display": "Developers",
          "type": "direct"
        }
      ]

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Closes #604760 (closed)

Edited by Katherine Richards

Merge request reports

Loading
Loading