mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Auth: Lock organization roles for users who are managed through an external auth provider (#72204)
remove onlyExternalOrgRoleSync feature flag
This commit is contained in:
parent
b503434bd3
commit
e9ba6922c0
@ -94,7 +94,6 @@ Experimental features might be changed or removed without prior notice.
|
|||||||
| `editPanelCSVDragAndDrop` | Enables drag and drop for CSV and Excel files |
|
| `editPanelCSVDragAndDrop` | Enables drag and drop for CSV and Excel files |
|
||||||
| `lokiQuerySplittingConfig` | Give users the option to configure split durations for Loki queries |
|
| `lokiQuerySplittingConfig` | Give users the option to configure split durations for Loki queries |
|
||||||
| `individualCookiePreferences` | Support overriding cookie preferences per user |
|
| `individualCookiePreferences` | Support overriding cookie preferences per user |
|
||||||
| `onlyExternalOrgRoleSync` | Prohibits a user from changing organization roles synced with external auth providers |
|
|
||||||
| `timeSeriesTable` | Enable time series table transformer & sparkline cell type |
|
| `timeSeriesTable` | Enable time series table transformer & sparkline cell type |
|
||||||
| `prometheusResourceBrowserCache` | Displays browser caching options in Prometheus data source configuration |
|
| `prometheusResourceBrowserCache` | Displays browser caching options in Prometheus data source configuration |
|
||||||
| `influxdbBackendMigration` | Query InfluxDB InfluxQL without the proxy |
|
| `influxdbBackendMigration` | Query InfluxDB InfluxQL without the proxy |
|
||||||
|
@ -64,7 +64,6 @@ export interface FeatureToggles {
|
|||||||
lokiQuerySplitting?: boolean;
|
lokiQuerySplitting?: boolean;
|
||||||
lokiQuerySplittingConfig?: boolean;
|
lokiQuerySplittingConfig?: boolean;
|
||||||
individualCookiePreferences?: boolean;
|
individualCookiePreferences?: boolean;
|
||||||
onlyExternalOrgRoleSync?: boolean;
|
|
||||||
prometheusMetricEncyclopedia?: boolean;
|
prometheusMetricEncyclopedia?: boolean;
|
||||||
timeSeriesTable?: boolean;
|
timeSeriesTable?: boolean;
|
||||||
prometheusResourceBrowserCache?: boolean;
|
prometheusResourceBrowserCache?: boolean;
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
||||||
"github.com/grafana/grafana/pkg/services/login"
|
"github.com/grafana/grafana/pkg/services/login"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -389,22 +388,22 @@ func (hs *HTTPServer) updateOrgUserHelper(c *contextmodel.ReqContext, cmd org.Up
|
|||||||
if !c.OrgRole.Includes(cmd.Role) && !c.IsGrafanaAdmin {
|
if !c.OrgRole.Includes(cmd.Role) && !c.IsGrafanaAdmin {
|
||||||
return response.Error(http.StatusForbidden, "Cannot assign a role higher than user's role", nil)
|
return response.Error(http.StatusForbidden, "Cannot assign a role higher than user's role", nil)
|
||||||
}
|
}
|
||||||
if hs.Features.IsEnabled(featuremgmt.FlagOnlyExternalOrgRoleSync) {
|
|
||||||
// we do not allow to change role for external synced users
|
// we do not allow to change role for external synced users
|
||||||
qAuth := login.GetAuthInfoQuery{UserId: cmd.UserID}
|
qAuth := login.GetAuthInfoQuery{UserId: cmd.UserID}
|
||||||
authInfo, err := hs.authInfoService.GetAuthInfo(c.Req.Context(), &qAuth)
|
authInfo, err := hs.authInfoService.GetAuthInfo(c.Req.Context(), &qAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, user.ErrUserNotFound) {
|
if errors.Is(err, user.ErrUserNotFound) {
|
||||||
hs.log.Debug("Failed to get user auth info for basic auth user", cmd.UserID, nil)
|
hs.log.Debug("Failed to get user auth info for basic auth user", cmd.UserID, nil)
|
||||||
} else {
|
} else {
|
||||||
hs.log.Error("Failed to get user auth info for external sync check", cmd.UserID, err)
|
hs.log.Error("Failed to get user auth info for external sync check", cmd.UserID, err)
|
||||||
return response.Error(http.StatusInternalServerError, "Failed to get user auth info", nil)
|
return response.Error(http.StatusInternalServerError, "Failed to get user auth info", nil)
|
||||||
}
|
|
||||||
}
|
|
||||||
if authInfo != nil && authInfo.AuthModule != "" && login.IsExternallySynced(hs.Cfg, authInfo.AuthModule) {
|
|
||||||
return response.Err(org.ErrCannotChangeRoleForExternallySyncedUser.Errorf("Cannot change role for externally synced user"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if authInfo != nil && authInfo.AuthModule != "" && login.IsExternallySynced(hs.Cfg, authInfo.AuthModule) {
|
||||||
|
return response.Err(org.ErrCannotChangeRoleForExternallySyncedUser.Errorf("Cannot change role for externally synced user"))
|
||||||
|
}
|
||||||
|
|
||||||
if err := hs.orgService.UpdateOrgUser(c.Req.Context(), &cmd); err != nil {
|
if err := hs.orgService.UpdateOrgUser(c.Req.Context(), &cmd); err != nil {
|
||||||
if errors.Is(err, org.ErrLastOrgAdmin) {
|
if errors.Is(err, org.ErrLastOrgAdmin) {
|
||||||
return response.Error(http.StatusBadRequest, "Cannot change role so that there is no organization admin left", nil)
|
return response.Error(http.StatusBadRequest, "Cannot change role so that there is no organization admin left", nil)
|
||||||
|
@ -275,7 +275,6 @@ func TestOrgUsersAPIEndpoint_updateOrgRole(t *testing.T) {
|
|||||||
hs.authInfoService = &logintest.AuthInfoServiceFake{
|
hs.authInfoService = &logintest.AuthInfoServiceFake{
|
||||||
ExpectedUserAuth: &login.UserAuth{AuthModule: tt.AuthModule},
|
ExpectedUserAuth: &login.UserAuth{AuthModule: tt.AuthModule},
|
||||||
}
|
}
|
||||||
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagOnlyExternalOrgRoleSync, true)
|
|
||||||
hs.userService = &usertest.FakeUserService{ExpectedSignedInUser: userWithPermissions}
|
hs.userService = &usertest.FakeUserService{ExpectedSignedInUser: userWithPermissions}
|
||||||
hs.orgService = &orgtest.FakeOrgService{}
|
hs.orgService = &orgtest.FakeOrgService{}
|
||||||
hs.accesscontrolService = &actest.FakeService{
|
hs.accesscontrolService = &actest.FakeService{
|
||||||
|
@ -316,12 +316,6 @@ var (
|
|||||||
Stage: FeatureStageExperimental,
|
Stage: FeatureStageExperimental,
|
||||||
Owner: grafanaBackendPlatformSquad,
|
Owner: grafanaBackendPlatformSquad,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "onlyExternalOrgRoleSync",
|
|
||||||
Description: "Prohibits a user from changing organization roles synced with external auth providers",
|
|
||||||
Stage: FeatureStageExperimental,
|
|
||||||
Owner: grafanaAuthnzSquad,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "prometheusMetricEncyclopedia",
|
Name: "prometheusMetricEncyclopedia",
|
||||||
Description: "Adds the metrics explorer component to the Prometheus query builder as an option in metric select",
|
Description: "Adds the metrics explorer component to the Prometheus query builder as an option in metric select",
|
||||||
|
@ -45,7 +45,6 @@ logsContextDatasourceUi,GA,@grafana/observability-logs,false,false,false,true
|
|||||||
lokiQuerySplitting,GA,@grafana/observability-logs,false,false,false,true
|
lokiQuerySplitting,GA,@grafana/observability-logs,false,false,false,true
|
||||||
lokiQuerySplittingConfig,experimental,@grafana/observability-logs,false,false,false,true
|
lokiQuerySplittingConfig,experimental,@grafana/observability-logs,false,false,false,true
|
||||||
individualCookiePreferences,experimental,@grafana/backend-platform,false,false,false,false
|
individualCookiePreferences,experimental,@grafana/backend-platform,false,false,false,false
|
||||||
onlyExternalOrgRoleSync,experimental,@grafana/grafana-authnz-team,false,false,false,false
|
|
||||||
prometheusMetricEncyclopedia,GA,@grafana/observability-metrics,false,false,false,true
|
prometheusMetricEncyclopedia,GA,@grafana/observability-metrics,false,false,false,true
|
||||||
timeSeriesTable,experimental,@grafana/app-o11y,false,false,false,true
|
timeSeriesTable,experimental,@grafana/app-o11y,false,false,false,true
|
||||||
prometheusResourceBrowserCache,experimental,@grafana/observability-metrics,false,false,false,true
|
prometheusResourceBrowserCache,experimental,@grafana/observability-metrics,false,false,false,true
|
||||||
|
|
@ -191,10 +191,6 @@ const (
|
|||||||
// Support overriding cookie preferences per user
|
// Support overriding cookie preferences per user
|
||||||
FlagIndividualCookiePreferences = "individualCookiePreferences"
|
FlagIndividualCookiePreferences = "individualCookiePreferences"
|
||||||
|
|
||||||
// FlagOnlyExternalOrgRoleSync
|
|
||||||
// Prohibits a user from changing organization roles synced with external auth providers
|
|
||||||
FlagOnlyExternalOrgRoleSync = "onlyExternalOrgRoleSync"
|
|
||||||
|
|
||||||
// FlagPrometheusMetricEncyclopedia
|
// FlagPrometheusMetricEncyclopedia
|
||||||
// Adds the metrics explorer component to the Prometheus query builder as an option in metric select
|
// Adds the metrics explorer component to the Prometheus query builder as an option in metric select
|
||||||
FlagPrometheusMetricEncyclopedia = "prometheusMetricEncyclopedia"
|
FlagPrometheusMetricEncyclopedia = "prometheusMetricEncyclopedia"
|
||||||
|
@ -5,7 +5,6 @@ import { Button, ConfirmModal } from '@grafana/ui';
|
|||||||
import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
|
import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
|
||||||
import { fetchRoleOptions } from 'app/core/components/RolePicker/api';
|
import { fetchRoleOptions } from 'app/core/components/RolePicker/api';
|
||||||
import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
|
import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
|
||||||
import config from 'app/core/config';
|
|
||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { AccessControlAction, OrgUser, Role } from 'app/types';
|
import { AccessControlAction, OrgUser, Role } from 'app/types';
|
||||||
|
|
||||||
@ -57,10 +56,8 @@ export const UsersTable = ({ users, orgId, onRoleChange, onRemoveUser }: Props)
|
|||||||
<tbody>
|
<tbody>
|
||||||
{users.map((user, index) => {
|
{users.map((user, index) => {
|
||||||
let basicRoleDisabled = !contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersWrite, user);
|
let basicRoleDisabled = !contextSrv.hasPermissionInMetadata(AccessControlAction.OrgUsersWrite, user);
|
||||||
if (config.featureToggles.onlyExternalOrgRoleSync) {
|
const isUserSynced = user?.isExternallySynced;
|
||||||
const isUserSynced = user?.isExternallySynced;
|
basicRoleDisabled = isUserSynced || basicRoleDisabled;
|
||||||
basicRoleDisabled = isUserSynced || basicRoleDisabled;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<tr key={`${user.userId}-${index}`}>
|
<tr key={`${user.userId}-${index}`}>
|
||||||
<td className="width-2 text-center">
|
<td className="width-2 text-center">
|
||||||
|
Loading…
Reference in New Issue
Block a user