Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7139374

Browse files
authored
feat: implement organization role sync (#14649)
* chore: implement organization and site wide role sync in idpsync* chore: remove old role sync, insert new idpsync package
1 parent5aa54be commit7139374

File tree

16 files changed

+1159
-223
lines changed

16 files changed

+1159
-223
lines changed

‎cli/server.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,6 @@ func createOIDCConfig(ctx context.Context, logger slog.Logger, vals *codersdk.De
187187
EmailField:vals.OIDC.EmailField.String(),
188188
AuthURLParams:vals.OIDC.AuthURLParams.Value,
189189
IgnoreUserInfo:vals.OIDC.IgnoreUserInfo.Value(),
190-
UserRoleField:vals.OIDC.UserRoleField.String(),
191-
UserRoleMapping:vals.OIDC.UserRoleMapping.Value,
192-
UserRolesDefault:vals.OIDC.UserRolesDefault.GetSlice(),
193190
SignInText:vals.OIDC.SignInText.String(),
194191
SignupsDisabledText:vals.OIDC.SignupsDisabledText.String(),
195192
IconURL:vals.OIDC.IconURL.String(),

‎coderd/coderd.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ type Options struct {
181181
NetworkTelemetryBatchFrequency time.Duration
182182
NetworkTelemetryBatchMaxSizeint
183183
SwaggerEndpointbool
184-
SetUserSiteRolesfunc(ctx context.Context,logger slog.Logger,tx database.Store,userID uuid.UUID,roles []string)error
185184
TemplateScheduleStore*atomic.Pointer[schedule.TemplateScheduleStore]
186185
UserQuietHoursScheduleStore*atomic.Pointer[schedule.UserQuietHoursScheduleStore]
187186
AccessControlStore*atomic.Pointer[dbauthz.AccessControlStore]
@@ -373,14 +372,6 @@ func New(options *Options) *API {
373372
ifoptions.TracerProvider==nil {
374373
options.TracerProvider=trace.NewNoopTracerProvider()
375374
}
376-
ifoptions.SetUserSiteRoles==nil {
377-
options.SetUserSiteRoles=func(ctx context.Context,logger slog.Logger,_ database.Store,userID uuid.UUID,roles []string)error {
378-
logger.Warn(ctx,"attempted to assign OIDC user roles without enterprise license",
379-
slog.F("user_id",userID),slog.F("roles",roles),
380-
)
381-
returnnil
382-
}
383-
}
384375
ifoptions.TemplateScheduleStore==nil {
385376
options.TemplateScheduleStore=&atomic.Pointer[schedule.TemplateScheduleStore]{}
386377
}

‎coderd/database/dbmem/dbmem.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8730,7 +8730,7 @@ func (q *FakeQuerier) UpdateUserRoles(_ context.Context, arg database.UpdateUser
87308730
}
87318731

87328732
// Set new roles
8733-
user.RBACRoles=arg.GrantedRoles
8733+
user.RBACRoles=slice.Unique(arg.GrantedRoles)
87348734
// Remove duplicates and sort
87358735
uniqueRoles:=make([]string,0,len(user.RBACRoles))
87368736
exist:=make(map[string]struct{})

‎coderd/idpsync/group_test.go

Lines changed: 148 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func TestGroupSyncTable(t *testing.T) {
8585
testCases:= []orgSetupDefinition{
8686
{
8787
Name:"SwitchGroups",
88-
Settings:&codersdk.GroupSyncSettings{
88+
GroupSettings:&codersdk.GroupSyncSettings{
8989
Field:"groups",
9090
Mapping:map[string][]uuid.UUID{
9191
"foo": {ids.ID("sg-foo"),ids.ID("sg-foo-2")},
@@ -102,16 +102,18 @@ func TestGroupSyncTable(t *testing.T) {
102102
ids.ID("sg-bar"):false,
103103
ids.ID("sg-baz"):false,
104104
},
105-
ExpectedGroups: []uuid.UUID{
106-
ids.ID("sg-foo"),
107-
ids.ID("sg-foo-2"),
108-
ids.ID("sg-bar"),
109-
ids.ID("sg-baz"),
105+
assertGroups:&orgGroupAssert{
106+
ExpectedGroups: []uuid.UUID{
107+
ids.ID("sg-foo"),
108+
ids.ID("sg-foo-2"),
109+
ids.ID("sg-bar"),
110+
ids.ID("sg-baz"),
111+
},
110112
},
111113
},
112114
{
113115
Name:"StayInGroup",
114-
Settings:&codersdk.GroupSyncSettings{
116+
GroupSettings:&codersdk.GroupSyncSettings{
115117
Field:"groups",
116118
// Only match foo, so bar does not map
117119
RegexFilter:regexp.MustCompile("^foo$"),
@@ -125,13 +127,15 @@ func TestGroupSyncTable(t *testing.T) {
125127
ids.ID("gg-foo"):true,
126128
ids.ID("gg-bar"):false,
127129
},
128-
ExpectedGroups: []uuid.UUID{
129-
ids.ID("gg-foo"),
130+
assertGroups:&orgGroupAssert{
131+
ExpectedGroups: []uuid.UUID{
132+
ids.ID("gg-foo"),
133+
},
130134
},
131135
},
132136
{
133137
Name:"UserJoinsGroups",
134-
Settings:&codersdk.GroupSyncSettings{
138+
GroupSettings:&codersdk.GroupSyncSettings{
135139
Field:"groups",
136140
Mapping:map[string][]uuid.UUID{
137141
"foo": {ids.ID("ng-foo"),uuid.New()},
@@ -145,29 +149,33 @@ func TestGroupSyncTable(t *testing.T) {
145149
ids.ID("ng-bar-2"):false,
146150
ids.ID("ng-baz"):false,
147151
},
148-
ExpectedGroups: []uuid.UUID{
149-
ids.ID("ng-foo"),
150-
ids.ID("ng-bar"),
151-
ids.ID("ng-bar-2"),
152-
ids.ID("ng-baz"),
152+
assertGroups:&orgGroupAssert{
153+
ExpectedGroups: []uuid.UUID{
154+
ids.ID("ng-foo"),
155+
ids.ID("ng-bar"),
156+
ids.ID("ng-bar-2"),
157+
ids.ID("ng-baz"),
158+
},
153159
},
154160
},
155161
{
156162
Name:"CreateGroups",
157-
Settings:&codersdk.GroupSyncSettings{
163+
GroupSettings:&codersdk.GroupSyncSettings{
158164
Field:"groups",
159165
RegexFilter:regexp.MustCompile("^create"),
160166
AutoCreateMissing:true,
161167
},
162168
Groups:map[uuid.UUID]bool{},
163-
ExpectedGroupNames: []string{
164-
"create-bar",
165-
"create-baz",
169+
assertGroups:&orgGroupAssert{
170+
ExpectedGroupNames: []string{
171+
"create-bar",
172+
"create-baz",
173+
},
166174
},
167175
},
168176
{
169177
Name:"GroupNamesNoMapping",
170-
Settings:&codersdk.GroupSyncSettings{
178+
GroupSettings:&codersdk.GroupSyncSettings{
171179
Field:"groups",
172180
RegexFilter:regexp.MustCompile(".*"),
173181
AutoCreateMissing:false,
@@ -177,14 +185,16 @@ func TestGroupSyncTable(t *testing.T) {
177185
"bar":false,
178186
"goob":true,
179187
},
180-
ExpectedGroupNames: []string{
181-
"foo",
182-
"bar",
188+
assertGroups:&orgGroupAssert{
189+
ExpectedGroupNames: []string{
190+
"foo",
191+
"bar",
192+
},
183193
},
184194
},
185195
{
186196
Name:"NoUser",
187-
Settings:&codersdk.GroupSyncSettings{
197+
GroupSettings:&codersdk.GroupSyncSettings{
188198
Field:"groups",
189199
Mapping:map[string][]uuid.UUID{
190200
// Extra ID that does not map to a group
@@ -200,13 +210,16 @@ func TestGroupSyncTable(t *testing.T) {
200210
},
201211
},
202212
{
203-
Name:"NoSettingsNoUser",
204-
Settings:nil,
205-
Groups:map[uuid.UUID]bool{},
213+
Name:"NoSettings",
214+
GroupSettings:nil,
215+
Groups:map[uuid.UUID]bool{},
216+
assertGroups:&orgGroupAssert{
217+
ExpectedGroups: []uuid.UUID{},
218+
},
206219
},
207220
{
208221
Name:"LegacyMapping",
209-
Settings:&codersdk.GroupSyncSettings{
222+
GroupSettings:&codersdk.GroupSyncSettings{
210223
Field:"groups",
211224
RegexFilter:regexp.MustCompile("^legacy"),
212225
LegacyNameMapping:map[string]string{
@@ -224,9 +237,11 @@ func TestGroupSyncTable(t *testing.T) {
224237
"extra":true,
225238
"legacy-bop":true,
226239
},
227-
ExpectedGroupNames: []string{
228-
"legacy-bar",
229-
"legacy-foo",
240+
assertGroups:&orgGroupAssert{
241+
ExpectedGroupNames: []string{
242+
"legacy-bar",
243+
"legacy-foo",
244+
},
230245
},
231246
},
232247
}
@@ -311,9 +326,10 @@ func TestGroupSyncTable(t *testing.T) {
311326
"random":true,
312327
},
313328
// No settings, because they come from the deployment values
314-
Settings:nil,
315-
ExpectedGroups:nil,
316-
ExpectedGroupNames: []string{"legacy-foo","legacy-baz","legacy-bar"},
329+
GroupSettings:nil,
330+
assertGroups:&orgGroupAssert{
331+
ExpectedGroupNames: []string{"legacy-foo","legacy-baz","legacy-bar"},
332+
},
317333
}
318334

319335
//nolint:gocritic // testing
@@ -385,16 +401,18 @@ func TestSyncDisabled(t *testing.T) {
385401
ids.ID("baz"):false,
386402
ids.ID("bop"):false,
387403
},
388-
Settings:&codersdk.GroupSyncSettings{
404+
GroupSettings:&codersdk.GroupSyncSettings{
389405
Field:"groups",
390406
Mapping:map[string][]uuid.UUID{
391407
"foo": {ids.ID("foo")},
392408
"baz": {ids.ID("baz")},
393409
},
394410
},
395-
ExpectedGroups: []uuid.UUID{
396-
ids.ID("foo"),
397-
ids.ID("bar"),
411+
assertGroups:&orgGroupAssert{
412+
ExpectedGroups: []uuid.UUID{
413+
ids.ID("foo"),
414+
ids.ID("bar"),
415+
},
398416
},
399417
}
400418

@@ -728,9 +746,14 @@ func SetupOrganization(t *testing.T, s *idpsync.AGPLIDPSync, db database.Store,
728746
}
729747

730748
manager:=runtimeconfig.NewManager()
731-
ifdef.Settings!=nil {
732-
orgResolver:=manager.OrganizationResolver(db,org.ID)
733-
err=s.Group.SetRuntimeValue(context.Background(),orgResolver, (*idpsync.GroupSyncSettings)(def.Settings))
749+
orgResolver:=manager.OrganizationResolver(db,org.ID)
750+
ifdef.GroupSettings!=nil {
751+
err=s.Group.SetRuntimeValue(context.Background(),orgResolver, (*idpsync.GroupSyncSettings)(def.GroupSettings))
752+
require.NoError(t,err)
753+
}
754+
755+
ifdef.RoleSettings!=nil {
756+
err=s.Role.SetRuntimeValue(context.Background(),orgResolver,def.RoleSettings)
734757
require.NoError(t,err)
735758
}
736759

@@ -740,6 +763,33 @@ func SetupOrganization(t *testing.T, s *idpsync.AGPLIDPSync, db database.Store,
740763
OrganizationID:org.ID,
741764
})
742765
}
766+
767+
iflen(def.OrganizationRoles)>0 {
768+
_,err:=db.UpdateMemberRoles(context.Background(), database.UpdateMemberRolesParams{
769+
GrantedRoles:def.OrganizationRoles,
770+
UserID:user.ID,
771+
OrgID:org.ID,
772+
})
773+
require.NoError(t,err)
774+
}
775+
776+
iflen(def.CustomRoles)>0 {
777+
for_,cr:=rangedef.CustomRoles {
778+
_,err:=db.InsertCustomRole(context.Background(), database.InsertCustomRoleParams{
779+
Name:cr,
780+
DisplayName:cr,
781+
OrganizationID: uuid.NullUUID{
782+
UUID:org.ID,
783+
Valid:true,
784+
},
785+
SitePermissions:nil,
786+
OrgPermissions:nil,
787+
UserPermissions:nil,
788+
})
789+
require.NoError(t,err)
790+
}
791+
}
792+
743793
forgroupID,in:=rangedef.Groups {
744794
dbgen.Group(t,db, database.Group{
745795
ID:groupID,
@@ -769,11 +819,25 @@ func SetupOrganization(t *testing.T, s *idpsync.AGPLIDPSync, db database.Store,
769819
typeorgSetupDefinitionstruct {
770820
Namestring
771821
// True if the user is a member of the group
772-
Groupsmap[uuid.UUID]bool
773-
GroupNamesmap[string]bool
774-
NotMemberbool
822+
Groupsmap[uuid.UUID]bool
823+
GroupNamesmap[string]bool
824+
OrganizationRoles []string
825+
CustomRoles []string
826+
// NotMember if true will ensure the user is not a member of the organization.
827+
NotMemberbool
828+
829+
GroupSettings*codersdk.GroupSyncSettings
830+
RoleSettings*idpsync.RoleSyncSettings
831+
832+
assertGroups*orgGroupAssert
833+
assertRoles*orgRoleAssert
834+
}
835+
836+
typeorgRoleAssertstruct {
837+
ExpectedOrgRoles []string
838+
}
775839

776-
Settings*codersdk.GroupSyncSettings
840+
typeorgGroupAssertstruct {
777841
ExpectedGroups []uuid.UUID
778842
ExpectedGroupNames []string
779843
}
@@ -794,6 +858,25 @@ func (o orgSetupDefinition) Assert(t *testing.T, orgID uuid.UUID, db database.St
794858
require.Len(t,members,1,"should be a member")
795859
}
796860

861+
ifo.assertGroups!=nil {
862+
o.assertGroups.Assert(t,orgID,db,user)
863+
}
864+
ifo.assertRoles!=nil {
865+
o.assertRoles.Assert(t,orgID,db,o.NotMember,user)
866+
}
867+
868+
// If the user is not a member, there is nothing to really assert in the org
869+
ifo.assertGroups==nil&&o.assertRoles==nil&&!o.NotMember {
870+
t.Errorf("no group or role asserts present, must have at least one")
871+
t.FailNow()
872+
}
873+
}
874+
875+
func (oorgGroupAssert)Assert(t*testing.T,orgID uuid.UUID,db database.Store,user database.User) {
876+
t.Helper()
877+
878+
ctx:=context.Background()
879+
797880
userGroups,err:=db.GetGroups(ctx, database.GetGroupsParams{
798881
OrganizationID:orgID,
799882
HasMemberID:user.ID,
@@ -826,3 +909,23 @@ func (o orgSetupDefinition) Assert(t *testing.T, orgID uuid.UUID, db database.St
826909
require.Len(t,o.ExpectedGroupNames,0,"ExpectedGroupNames should be empty")
827910
}
828911
}
912+
913+
//nolint:revive
914+
func (oorgRoleAssert)Assert(t*testing.T,orgID uuid.UUID,db database.Store,notMemberbool,user database.User) {
915+
t.Helper()
916+
917+
ctx:=context.Background()
918+
919+
members,err:=db.OrganizationMembers(ctx, database.OrganizationMembersParams{
920+
OrganizationID:orgID,
921+
UserID:user.ID,
922+
})
923+
ifnotMember {
924+
require.ErrorIs(t,err,sql.ErrNoRows)
925+
return
926+
}
927+
require.NoError(t,err)
928+
require.Len(t,members,1)
929+
member:=members[0]
930+
require.ElementsMatch(t,member.OrganizationMember.Roles,o.ExpectedOrgRoles)
931+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp