Skip to content

Conversation

fflorent
Copy link
Collaborator

@fflorent fflorent commented Jan 3, 2025

Context

Following #1199, this PR proposes to implement the /Groups Endpoint.

As an IT asset administrator, I can create groups for my users using a centralized solution (an Identity Provider) so they can easily access to the resources. But these groups and memberships are not pushed to Grist as of today. The administrator is either offered to remove access entirely to Grist, or access to Grist and modify the permissions on the resources. Most of all, as Teams are not represented through the UI, it can be a quite painful task.

Proposed solution

SCIM is a standard proposed by the IETF through RFC7644 and RFC7643 which aims to through a simple Rest API provide solution for the above use cases.

Here is the abstract of the RFC7644 which introduces SCIM:

The System for Cross-domain Identity Management (SCIM) specification is an HTTP-based protocol that makes managing identities in multi-domain scenarios easier to support via a standardized service.
Examples include, but are not limited to, enterprise-to-cloud service providers and inter-cloud scenarios. The specification suite seeks to build upon experience with existing schemas and deployments, placing specific emphasis on simplicity of development and integration, while applying existing authentication, authorization, and privacy models. SCIM's intent is to reduce the cost and complexity of user management operations by providing a common user schema, an extension model, and a service protocol defined by this document.

This PR provides a complement to the now existing /scim/v2/Users endpoint (documented here):

SCIM Endpoint Group Type1 Usage
/scim/v2/Groups Team Represents a team of users in your organisation,
who are granted accesses toa set of resources through Roles
/scim/v2/Roles 2 Role Grants users and teams a certain access
(owner, editor, viewer, ...) to a given resource

Currently only the Roles were represented in the "groups" table. To achieve this distinction, this PR also introduces a "type" column, which only accept team or role values.

This PR provides the implementation of SCIM for Groups (aka Teams), and supports:

  • All the basic actions for Groups (POST /Groups/, PUT /Groups/:id, GET /Groups/, GET /Groups/:id and DELETE /Groups/:id).
  • The POST /Bulk endpoint
  • The POST /Groups/.search by using the Filters (actually to use them, you must have to fetch all the Resources from the DB, the filtering is done in JS, which is probably fine for small projects, I would just be cautious when using big databases + an ORM);
  • The PATCH /Groups/:id endpoint! It reads a resource using the egress method, applies the asked changes, and calls the ingress method to update the record ;
  • The pagination

The endpoint for /Roles are nearly the same, though:

  • Creation (trough POST) and the deletion are not allowed;
  • We can only update the memberships, which is helpful to assign a role to users or teams;
  • And the endpoint also return the resource ID associated to the role through the orgId, workspaceId or docId readonly attributes.

As in #1199, I take advantage of these two libraries: scimmy and scimmy-routers.

👀 Known limitations

  1. You cannot add a group as a member of a Resouce Users group, due to the fact that the depth for groups are limited to 4.
  2. The groups are not displayed in the Users Management popup for now. This may be a bit confusing.

⛹️ Play with this endpoint

This is a step-by-step tutorial to play with this new endpoint:
https://gist.github.com/fflorent/dd11a15e424ab4828f679ab038eea764

Related issues

Fixes #870

Has this been tested?

  • 👍 yes, I added tests to the test suite
  • 💭 no, because this PR is a draft and still needs work
  • 🙅 no, because this is not relevant here
  • 🙋 no, because I need help

Footnotes

  1. In the Grist terminology, and as specified in the groups.type column in the database.

  2. This is a custom endpoint as allowed by the SCIM standard.

@fflorent fflorent force-pushed the scim-groups-endpoints branch 3 times, most recently from fbce58e to 2c32360 Compare January 3, 2025 19:08
@fflorent fflorent force-pushed the scim-groups-endpoints branch 4 times, most recently from 8ecb5ce to 7f924fe Compare January 17, 2025 12:21
@fflorent fflorent force-pushed the scim-groups-endpoints branch from 0f8575a to 2e91be2 Compare January 31, 2025 12:50
assert.equal(res.status, 401);
});

it.skip('should allow operation like PATCH for kiwi', async function () {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed it, it looks like this won't be fixed (for good reasons I think):
scimmyjs/scimmy-routers#27

@fflorent fflorent marked this pull request as ready for review February 2, 2025 21:19
@fflorent fflorent requested a review from hexaltation February 2, 2025 21:19
Copy link
Collaborator

@hexaltation hexaltation left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @fflorent for this huge piece of work.

Two small changes asked.

And one concern about the stickyness of the code with SCIMMY.
How much of of work could it need:

  • To add a layer of abstraction to not use SCIMMY object in higher levels of grist,
  • To replace this lib contributed by only one guy the day he won't maintained it anymore.

But no doubt that it's the best solution for now.

@fflorent fflorent moved this to Needs feedback in French administration Board Mar 12, 2025
@fflorent fflorent moved this from Needs feedback to In Progress in French administration Board Jul 16, 2025
@fflorent fflorent force-pushed the scim-groups-endpoints branch from ef96456 to 52aeaec Compare July 21, 2025 08:55
fflorent added a commit to fflorent/grist-core that referenced this pull request Jul 21, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
fflorent added a commit to fflorent/grist-core that referenced this pull request Jul 21, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
@fflorent fflorent force-pushed the scim-groups-endpoints branch from 52aeaec to 1f3e416 Compare July 21, 2025 09:02
@fflorent fflorent moved this from In Progress to Needs feedback in French administration Board Jul 21, 2025
fflorent added a commit to fflorent/grist-core that referenced this pull request Jul 21, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
@fflorent fflorent force-pushed the scim-groups-endpoints branch from 1f3e416 to d532cfc Compare July 21, 2025 09:06
fflorent added a commit to fflorent/grist-core that referenced this pull request Jul 21, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
@fflorent fflorent force-pushed the scim-groups-endpoints branch from d532cfc to 2e3c081 Compare July 21, 2025 09:11
fflorent added a commit to fflorent/grist-core that referenced this pull request Jul 21, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
@fflorent fflorent force-pushed the scim-groups-endpoints branch 2 times, most recently from b404afd to b2ac191 Compare July 22, 2025 08:44
fflorent added a commit to fflorent/grist-core that referenced this pull request Jul 22, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
@fflorent fflorent force-pushed the scim-groups-endpoints branch from b2ac191 to 88455b6 Compare July 22, 2025 09:05
fflorent added a commit to fflorent/grist-core that referenced this pull request Jul 22, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
@fflorent fflorent force-pushed the scim-groups-endpoints branch from 88455b6 to e304fec Compare July 22, 2025 09:16
fflorent added a commit to fflorent/grist-core that referenced this pull request Jul 22, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
@fflorent fflorent force-pushed the scim-groups-endpoints branch from e304fec to 9c96d90 Compare July 22, 2025 10:10
@paulfitz paulfitz requested a review from Copilot July 23, 2025 17:03
Copilot

This comment was marked as outdated.

Copy link
Member

@paulfitz paulfitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(just a quick skim (scim?) of part of the code)

}

/**
* Returns a Promise for an array of User entites for the given userIds.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*entities

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(typo)

@fflorent fflorent force-pushed the scim-groups-endpoints branch from c4982e4 to 653f631 Compare July 25, 2025 08:18
@fflorent fflorent requested a review from paulfitz July 28, 2025 11:52
@fflorent fflorent force-pushed the scim-groups-endpoints branch from 653f631 to a7ecfb4 Compare August 13, 2025 15:13
fflorent added a commit to fflorent/grist-core that referenced this pull request Aug 13, 2025
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
const newColumnNonNull = newColumn.clone();
newColumnNonNull.isNullable = false;

await queryRunner.changeColumn('groups', newColumn, newColumnNonNull);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm this all feels ok and will probably run alright on large installations. At some point it is more practical to just use nullable columns and take the hit in type-checking, but we're not at that scale yet.

}

/**
* Returns a Promise for an array of User entites for the given userIds.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(typo)

fflorent and others added 4 commits September 2, 2025 11:33
This change also introduce a "Team" and a "Role" type for Groups. "Role"
type is the historical type, it is the role granted to the user for a
resource. The "Team" type is a new type, it is meant to gather people
and grant them a role together for a resource.

The SCIM /Groups endpoints gives access to the "Teams" groups.
The SCIM /Roles endpoints gives a (limited) access to the "Roles"
groups.

For more information, please take a look at this Pr description:
gristlabs#1357 (comment)

Co-authored-by: Grégoire Cutzach <[email protected]>
After having introduced the "type" column in the "Groups" table,
the test for migrating TeamMembers failed because the Group entity
had a property that does not exist yet as a column in the table.

Instead execute a plain INSERT INTO statement to run the migration so it
does not involve the non-existing yet "type" column.
@fflorent fflorent force-pushed the scim-groups-endpoints branch from d03c648 to 44c7a3e Compare September 2, 2025 09:47
After the upgrade of SCIMMY, it looks like SCIMMY has a better support
of typing. Let's take advantage of it!
@fflorent fflorent force-pushed the scim-groups-endpoints branch from 167bf46 to 279388d Compare September 2, 2025 15:55
@fflorent fflorent requested a review from Copilot September 2, 2025 16:56
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements SCIM support for Groups by adding a new /Groups endpoint and related functionality. It introduces a type distinction for groups (Team vs Role), adds extensive test coverage, and upgrades SCIM library dependencies.

  • Add Groups endpoints supporting CRUD operations for Teams
  • Introduce group type system distinguishing Teams from Roles
  • Add comprehensive test coverage for Groups and Roles functionality

Reviewed Changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
test/server/lib/Scim.ts Adds comprehensive test suite for Groups and Roles SCIM endpoints
test/gen-server/seed.ts Updates group creation to use new Group.create() method with type
test/gen-server/migrations.ts Adds GroupTypes migration and foreign key utility usage
test/gen-server/lib/homedb/UsersManager.ts Updates group creation to use new typed Group.create() method
test/gen-server/lib/homedb/GroupsManager.ts New comprehensive test suite for GroupsManager functionality
package.json Updates SCIM library versions to 1.3.5 and 1.3.2
app/server/lib/scim/v2/roles/SCIMMYRoleSchema.ts New schema definition for Role resources
app/server/lib/scim/v2/roles/SCIMMYRoleResource.ts New SCIM resource implementation for Roles
app/server/lib/scim/v2/ScimV2Api.ts Integrates Group and Role resources into SCIM API
app/server/lib/scim/v2/ScimUtils.ts Common utilities for SCIM transformations
app/server/lib/scim/v2/ScimUserUtils.ts Removed, functionality moved to ScimUtils
app/server/lib/scim/v2/ScimUserController.ts Refactored to extend BaseController
app/server/lib/scim/v2/ScimRoleController.ts New controller for Role SCIM operations
app/server/lib/scim/v2/ScimGroupController.ts New controller for Group SCIM operations
app/server/lib/scim/v2/BaseController.ts New base class for SCIM controllers
app/server/lib/dbUtils.ts Adds utility for SQLite foreign key constraint management
app/gen-server/migration/1753088213255-GroupTypes.ts New migration adding type column to groups table
app/gen-server/migration/1568238234987-TeamMembers.ts Updates to handle new Group entity structure
app/gen-server/lib/homedb/UsersManager.ts Adds getUsersByIdsStrict method
app/gen-server/lib/homedb/Interfaces.ts Adds GroupWithMembersDescriptor and GroupTypes
app/gen-server/lib/homedb/HomeDBManager.ts Adds group management methods
app/gen-server/lib/homedb/GroupsManager.ts Extensive additions for group CRUD operations
app/gen-server/entity/Group.ts Adds type column and validation logic

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Member

@paulfitz paulfitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for persisting @fflorent ! Looks good. The main focus of my reviewing has been to watch out for any security issues. Everything looks well organized from that perspective. The SCIM functionality looks plausible to me but I'm no expert. Responding to related feature requests and bug reports may be like for the OIDC work, where the original contributor bears the brunt of maintenance just due to the knowledge they've accumulated.

@paulfitz paulfitz merged commit c2b53f4 into gristlabs:main Sep 2, 2025
14 checks passed
@github-project-automation github-project-automation bot moved this from Needs feedback to Done in French administration Board Sep 2, 2025
@fflorent fflorent deleted the scim-groups-endpoints branch September 30, 2025 06:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Support SCIM

3 participants