fix: show selected owner's external auth when creating a workspace (#26653)

This commit is contained in:
McKayla はな
2026-07-23 16:39:53 -06:00
committed by GitHub
parent d5a3963167
commit 3cf97ff8e7
19 changed files with 377 additions and 49 deletions
+28
View File
@@ -837,6 +837,28 @@ var (
}),
Scope: rbac.ScopeAll,
}.WithCachedASTValue()
// subjectExternalAuthCoordinator is used to check whether a user has configured
// external auth providers or not when an admin is creating a workspace for
// another user.
subjectExternalAuthCoordinator = rbac.Subject{
Type: rbac.SubjectTypeExternalAuthCoordinator,
FriendlyName: "External Auth Coordinator",
ID: uuid.Nil.String(),
Roles: rbac.Roles([]rbac.Role{
{
Identifier: rbac.RoleIdentifier{Name: "external-auth-coordinator"},
DisplayName: "External Auth Coordinator",
Site: rbac.Permissions(map[string][]policy.Action{
// policy.ActionUpdatePersonal allows us to refresh tokens.
rbac.ResourceUser.Type: {policy.ActionReadPersonal, policy.ActionUpdatePersonal},
}),
User: []rbac.Permission{},
ByOrgID: map[string]rbac.OrgPermissions{},
},
}),
Scope: rbac.ScopeAll,
}.WithCachedASTValue()
)
// AsProvisionerd returns a context with an actor that has permissions required
@@ -985,6 +1007,12 @@ func AsSCIMProvisioner(ctx context.Context) context.Context {
return As(ctx, subjectSCIM)
}
// AsExternalAuthCoordinator returns a context with an actor that has permission to
// read and refresh any user's external auth links.
func AsExternalAuthCoordinator(ctx context.Context) context.Context {
return As(ctx, subjectExternalAuthCoordinator)
}
var AsRemoveActor = rbac.Subject{
ID: "remove-actor",
}
+45
View File
@@ -7633,3 +7633,48 @@ func TestAsChatd(t *testing.T) {
require.Error(t, err, "provisioner daemon read should be denied")
})
}
func TestAsExternalAuthChecker(t *testing.T) {
t.Parallel()
ctx := dbauthz.AsExternalAuthCoordinator(context.Background())
actor, ok := dbauthz.ActorFromContext(ctx)
require.True(t, ok, "actor must be present")
auth := rbac.NewStrictCachingAuthorizer(prometheus.NewRegistry())
t.Run("AllowedActions", func(t *testing.T) {
t.Parallel()
// Reading and refreshing a user's external auth link requires personal
// read and update on the user resource.
for _, action := range []policy.Action{
policy.ActionReadPersonal, policy.ActionUpdatePersonal,
} {
err := auth.Authorize(ctx, actor, action, rbac.ResourceUser)
require.NoError(t, err, "user %s should be allowed", action)
}
})
t.Run("DeniedActions", func(t *testing.T) {
t.Parallel()
// No general user read/write, only personal external auth access.
for _, action := range []policy.Action{
policy.ActionRead, policy.ActionCreate,
policy.ActionUpdate, policy.ActionDelete,
} {
err := auth.Authorize(ctx, actor, action, rbac.ResourceUser)
require.Error(t, err, "user %s should be denied", action)
}
// Unlike AsSystemRestricted, this actor cannot read other resources.
for _, res := range []rbac.Object{
rbac.ResourceWorkspace, rbac.ResourceTemplate,
rbac.ResourceApiKey, rbac.ResourceOrganization,
} {
err := auth.Authorize(ctx, actor, policy.ActionRead, res)
require.Error(t, err, "%s read should be denied", res.Type)
}
})
}