mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: implement SCIM handler for SCIM 2.0 compliance (#25572)
Rewrites the SCIM 2.0 user provisioning handler to be RFC 7644 compliant. Verified against an external IdP Okta. Behavior is OPT IN
This commit is contained in:
@@ -742,6 +742,29 @@ var (
|
||||
}),
|
||||
Scope: rbac.ScopeAll,
|
||||
}.WithCachedASTValue()
|
||||
|
||||
subjectSCIM = rbac.Subject{
|
||||
Type: rbac.SubjectTypeSCIMProvisioner,
|
||||
FriendlyName: "SCIM Provisioner",
|
||||
ID: uuid.Nil.String(),
|
||||
Roles: rbac.Roles([]rbac.Role{
|
||||
{
|
||||
Identifier: rbac.RoleIdentifier{Name: "scim"},
|
||||
DisplayName: "SCIM",
|
||||
Site: rbac.Permissions(map[string][]policy.Action{
|
||||
rbac.ResourceSystem.Type: {policy.ActionRead}, // Required for idp config reads, this should be fixed
|
||||
rbac.ResourceAssignRole.Type: rbac.ResourceAssignRole.AvailableActions(),
|
||||
rbac.ResourceAssignOrgRole.Type: rbac.ResourceAssignOrgRole.AvailableActions(),
|
||||
rbac.ResourceUser.Type: {policy.ActionCreate, policy.ActionUpdate, policy.ActionRead, policy.ActionUpdatePersonal},
|
||||
rbac.ResourceOrganization.Type: {policy.ActionRead},
|
||||
rbac.ResourceOrganizationMember.Type: {policy.ActionRead, policy.ActionCreate, policy.ActionUpdate},
|
||||
}),
|
||||
User: []rbac.Permission{},
|
||||
ByOrgID: map[string]rbac.OrgPermissions{},
|
||||
},
|
||||
}),
|
||||
Scope: rbac.ScopeAll,
|
||||
}.WithCachedASTValue()
|
||||
)
|
||||
|
||||
// AsProvisionerd returns a context with an actor that has permissions required
|
||||
@@ -872,6 +895,12 @@ func AsAIProviderMetadataReader(ctx context.Context) context.Context {
|
||||
return As(ctx, subjectAIProviderMetadataReader)
|
||||
}
|
||||
|
||||
// AsSCIMProvisioner returns a context with an actor that has permissions required for
|
||||
// handling the /scim/v2 routes and provisioning users via SCIM.
|
||||
func AsSCIMProvisioner(ctx context.Context) context.Context {
|
||||
return As(ctx, subjectSCIM)
|
||||
}
|
||||
|
||||
var AsRemoveActor = rbac.Subject{
|
||||
ID: "remove-actor",
|
||||
}
|
||||
@@ -4659,7 +4688,8 @@ func (q *querier) GetUserCodeDiffDisplayMode(ctx context.Context, userID uuid.UU
|
||||
}
|
||||
|
||||
func (q *querier) GetUserCount(ctx context.Context, includeSystem bool) (int64, error) {
|
||||
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
|
||||
// If you can read every user, then you can read the count of users.
|
||||
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceUser); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return q.db.GetUserCount(ctx, includeSystem)
|
||||
|
||||
@@ -4578,7 +4578,7 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
||||
}))
|
||||
s.Run("GetUserCount", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
||||
dbm.EXPECT().GetUserCount(gomock.Any(), false).Return(int64(0), nil).AnyTimes()
|
||||
check.Args(false).Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(int64(0))
|
||||
check.Args(false).Asserts(rbac.ResourceUser, policy.ActionRead).Returns(int64(0))
|
||||
}))
|
||||
s.Run("GetTemplates", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
||||
dbm.EXPECT().GetTemplates(gomock.Any()).Return([]database.Template{}, nil).AnyTimes()
|
||||
|
||||
Reference in New Issue
Block a user