Skip to content

Add a prefix to SCIM tokens behind a feature flag

Nick Malcolm requested to merge 435096-prefix-scim-tokens into master

What does this MR do and why?

Add a prefix to SCIM tokens behind a feature flag (Rollout issue: [Feature flag] Enable prefix_scim_tokens (#435423 - closed))

Prefixes SCIM OAuth Access Tokens with glsoat- following the guidance at https://docs.gitlab.com/ee/development/secure_coding_guidelines.html#token-prefixes.

GitLab applies a prefix to some of its generated secrets. For example, a Personal Access Token begins with glpat-. This MR adds a prefix to SCIM Tokens. It also updates our frontend secret detection which helps prevent users from leaking tokens via Issue / MR comments.

SCIM tokens can belong to a Group, or have no Group and be an instance token. These tokens are used to authenticate against the APIs described at https://docs.gitlab.com/ee/development/internal_api/#group-scim-api and https://docs.gitlab.com/ee/development/internal_api/#instance-scim-api respectively.

A feature flag is being used to reduce the risk of breaking third-party integrations, which might have made assumptions about the format of GitLab's SCIM tokens remaining static. See #435096 (comment 1691498327) for discussion. The feature flag only controls the prefixing of new tokens; front-end secret detection will continue to detect prefixed tokens even if the flag is disabled. This is because the risk we're mitigating is breaking integrations with third parties, and the frontend should be able to detect any prefixed tokens whether the flag has been subsequently disabled or not.

Resolves #435096 (closed)

Changelog: changed

Screenshots or screen recordings

Screenshots are required for UI changes, and strongly recommended for all other merge requests.

Before After
Screenshot_2023-12-15_at_15.59.16 Screenshot_2023-12-15_at_16.03.08
Screenshot_2023-12-15_at_14.09.35 Screenshot_2023-12-15_at_14.12.14

How to set up and validate locally

Prep

  1. Make sure your GDK is Premium / Ultimate
  2. Create a new group and make it Premium (Admin > Groups > Edit > Permissions and group features > Plan dropdown)
    1. In examples below the group is called scimtest
  3. Set up HTTPS & SAML SSO for GDK: https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/saml.md?plain=1&ref_type=heads#L8
    1. This includes the "GitLab configuration" section, "Configuring the group" section, and "Instance SAML with Docker" sections
    2. Make sure you're not simulating SaaS (for instance SCIM API testing, at least): https://docs.gitlab.com/ee/development/ee_features.html#simulate-a-saas-instance
  4. Validate that you're set up right:
    % curl "https://gdk.test:3443/api/scim/v2/groups/scimtest/Users/"
    # GOOD
    {"schemas":["urn:ietf:params:scim:api:messages:2.0:Error"],"detail":"Group scimtest does not have SAML SSO configured","status":404}
    # BAD
    {"message":"403 Forbidden - Group SAML not enabled."}
    
    % curl "https://gdk.test:3443/api/scim/v2/application/Users"
    # GOOD
    {"message":"401 Unauthorized"}
    # BAD
    {"message":"404 Not Found"}

Group SCIM

As group owner:

  1. Navigate to the group you created > Settings > SAML SSO
  2. Click "Generate SCIM token"
  3. Observe that it is not prefixed
  4. Confirm that the non-prefixed token works:
    % curl -v "https://gdk.test:3443/api/scim/v2/groups/scimtest/Users" \
             --header "Authorization: Bearer NON_PREFIXED_GROUP_SCIM_TOKEN" \
             --header "Content-Type: application/scim+json"
    {"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],"totalResults":0,"itemsPerPage":20,"startIndex":1,"Resources":[]}%
  5. In the rails console, Feature.enable(:prefix_scim_tokens)
  6. Confirm that the non-prefixed token continues to work - we haven't broken anything:
    % curl -v "https://gdk.test:3443/api/scim/v2/groups/scimtest/Users" \
             --header "Authorization: Bearer NON_PREFIXED_GROUP_SCIM_TOKEN" \
             --header "Content-Type: application/scim+json"
    {"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],"totalResults":0,"itemsPerPage":20,"startIndex":1,"Resources":[]}%
  7. Refresh the page (to get the "reset" link back) and click it
  8. Observe that the new token is prefixed
  9. Confirm that the prefixed token works:
    % curl -v "https://gdk.test:3443/api/scim/v2/groups/scimtest/Users" \
             --header "Authorization: Bearer PREFIXED_GROUP_SCIM_TOKEN" \
             --header "Content-Type: application/scim+json"
    {"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],"totalResults":0,"itemsPerPage":20,"startIndex":1,"Resources":[]}%
  10. In the rails console, Feature.disable(:prefix_scim_tokens)

Instance SCIM

As admin:

  1. Navigate to Admin > Settings > General > SCIM Token
  2. Click generate / "reset secret"
  3. Observe that it is not prefixed
  4. Confirm that the non-prefixed token works:
    % curl -v "https://gdk.test:3443/api/scim/v2/groups/GROUP_NAME/Users" \
         --header "Authorization: Bearer NON_PREFIXED_INSTANCE_SCIM_TOKEN" \
         --header "Content-Type: application/scim+json"
    {"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],"totalResults":1,"itemsPerPage":20,"startIndex":1,"Resources":[{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"id":"test_uid","active":true,"emails":[{"type":"work","value":"work@example.com","primary":true}],"name":{"formatted":"Test Name","givenName":"Test","familyName":"Name"},"meta":{"resourceType":"User"},"userName":"username"}]}
  5. In the rails console, Feature.enable(:prefix_scim_tokens)
  6. Confirm that the non-prefixed token continues to work - we haven't broken anything:
    % curl -v "https://gdk.test:3443/api/scim/v2/groups/GROUP_NAME/Users" \
         --header "Authorization: Bearer NON_PREFIXED_INSTANCE_SCIM_TOKEN" \
         --header "Content-Type: application/scim+json"
    {"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],"totalResults":1,"itemsPerPage":20,"startIndex":1,"Resources":[{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],"id":"test_uid","active":true,"emails":[{"type":"work","value":"work@example.com","primary":true}],"name":{"formatted":"Test Name","givenName":"Test","familyName":"Name"},"meta":{"resourceType":"User"},"userName":"username"}]}
  7. Refresh the page (to get the "reset" link back) and click it
  8. Observe that the token is prefixed
  9. Confirm that the prefixed token works:
    % curl -v "https://gdk.test:3443/api/scim/v2/groups/GROUP_NAME/Users" \
         --header "Authorization: Bearer PREFIXED_INSTANCE_SCIM_TOKEN" \
         --header "Content-Type: application/scim+json"
  10. In the rails console, Feature.disable(:prefix_scim_tokens)

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #435096 (closed)

Edited by Nick Malcolm

Merge request reports