SCIM: Add a distinctive label for externally provisioned users (#102701)
* Add json mapping for user.isProvisioned * Retrieve the isProvisioned value from database * Add a Provisioned label to pages that list users * Update swagger definitions * Add changes to User Admin pages
This commit is contained in:
@@ -157,6 +157,7 @@ type OrgUserDTO struct {
|
||||
IsDisabled bool `json:"isDisabled"`
|
||||
AuthLabels []string `json:"authLabels" xorm:"-"`
|
||||
IsExternallySynced bool `json:"isExternallySynced"`
|
||||
IsProvisioned bool `json:"isProvisioned"`
|
||||
}
|
||||
|
||||
type RemoveOrgUserCommand struct {
|
||||
|
||||
@@ -611,6 +611,7 @@ func (ss *sqlStore) SearchOrgUsers(ctx context.Context, query *org.SearchOrgUser
|
||||
"u.created",
|
||||
"u.updated",
|
||||
"u.is_disabled",
|
||||
"u.is_provisioned",
|
||||
)
|
||||
|
||||
if len(query.SortOpts) > 0 {
|
||||
|
||||
@@ -137,11 +137,11 @@ type UserSearchHitDTO struct {
|
||||
AvatarURL string `json:"avatarUrl" xorm:"avatar_url"`
|
||||
IsAdmin bool `json:"isAdmin"`
|
||||
IsDisabled bool `json:"isDisabled"`
|
||||
IsProvisioned bool `json:"isProvisioned"`
|
||||
LastSeenAt time.Time `json:"lastSeenAt"`
|
||||
LastSeenAtAge string `json:"lastSeenAtAge"`
|
||||
AuthLabels []string `json:"authLabels"`
|
||||
AuthModule AuthModuleConversion `json:"-"`
|
||||
IsProvisioned bool `json:"-" xorm:"is_provisioned"`
|
||||
}
|
||||
|
||||
type GetUserProfileQuery struct {
|
||||
@@ -166,7 +166,7 @@ type UserProfileDTO struct {
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
AvatarURL string `json:"avatarUrl"`
|
||||
AccessControl map[string]bool `json:"accessControl,omitempty"`
|
||||
IsProvisioned bool `json:"-"`
|
||||
IsProvisioned bool `json:"isProvisioned"`
|
||||
}
|
||||
|
||||
// implement Conversion interface to define custom field mapping (xorm feature)
|
||||
|
||||
@@ -374,6 +374,7 @@ func (ss *sqlStore) GetProfile(ctx context.Context, query *user.GetUserProfileQu
|
||||
Theme: usr.Theme,
|
||||
IsGrafanaAdmin: usr.IsAdmin,
|
||||
IsDisabled: usr.IsDisabled,
|
||||
IsProvisioned: usr.IsProvisioned,
|
||||
OrgID: usr.OrgID,
|
||||
UpdatedAt: usr.Updated,
|
||||
CreatedAt: usr.Created,
|
||||
@@ -526,7 +527,7 @@ func (ss *sqlStore) Search(ctx context.Context, query *user.SearchUsersQuery) (*
|
||||
sess.Limit(query.Limit, offset)
|
||||
}
|
||||
|
||||
sess.Cols("u.id", "u.uid", "u.email", "u.name", "u.login", "u.is_admin", "u.is_disabled", "u.last_seen_at", "user_auth.auth_module")
|
||||
sess.Cols("u.id", "u.uid", "u.email", "u.name", "u.login", "u.is_admin", "u.is_disabled", "u.last_seen_at", "user_auth.auth_module", "u.is_provisioned")
|
||||
|
||||
if len(query.SortOpts) > 0 {
|
||||
for i := range query.SortOpts {
|
||||
|
||||
@@ -5913,6 +5913,9 @@
|
||||
"isExternallySynced": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lastSeenAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
@@ -8605,6 +8608,9 @@
|
||||
"isGrafanaAdminExternallySynced": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -8652,6 +8658,9 @@
|
||||
"isDisabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lastSeenAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
|
||||
@@ -17760,6 +17760,9 @@
|
||||
"isExternallySynced": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lastSeenAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
@@ -22367,6 +22370,9 @@
|
||||
"isGrafanaAdminExternallySynced": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -22414,6 +22420,9 @@
|
||||
"isDisabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lastSeenAt": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
|
||||
@@ -115,7 +115,10 @@ export const UserAdminPage = ({
|
||||
const isLDAPUser = user?.isExternal && user?.authLabels?.includes('LDAP');
|
||||
const canReadSessions = contextSrv.hasPermission(AccessControlAction.UsersAuthTokenList);
|
||||
const canReadLDAPStatus = contextSrv.hasPermission(AccessControlAction.LDAPStatusRead);
|
||||
const authSource = user?.authLabels?.[0];
|
||||
let authSource = user?.authLabels?.[0];
|
||||
if (user?.isProvisioned) {
|
||||
authSource = 'SCIM';
|
||||
}
|
||||
const lockMessage = authSource ? `Synced via ${authSource}` : '';
|
||||
const pageNav: NavModelItem = {
|
||||
text: user?.login ?? '',
|
||||
|
||||
@@ -71,12 +71,18 @@ export function UserProfile({
|
||||
});
|
||||
};
|
||||
|
||||
const authSource = user.authLabels?.length && user.authLabels[0];
|
||||
let authSource = user.authLabels?.length && user.authLabels[0];
|
||||
if (user.isProvisioned) {
|
||||
authSource = 'SCIM';
|
||||
}
|
||||
const lockMessage = authSource ? `Synced via ${authSource}` : '';
|
||||
|
||||
const editLocked = user.isExternal || !contextSrv.hasPermissionInMetadata(AccessControlAction.UsersWrite, user);
|
||||
const editLocked =
|
||||
user.isExternal || user.isProvisioned || !contextSrv.hasPermissionInMetadata(AccessControlAction.UsersWrite, user);
|
||||
const passwordChangeLocked =
|
||||
user.isExternal || !contextSrv.hasPermissionInMetadata(AccessControlAction.UsersPasswordUpdate, user);
|
||||
user.isExternal ||
|
||||
user.isProvisioned ||
|
||||
!contextSrv.hasPermissionInMetadata(AccessControlAction.UsersPasswordUpdate, user);
|
||||
const canDelete = contextSrv.hasPermissionInMetadata(AccessControlAction.UsersDelete, user);
|
||||
const canDisable = contextSrv.hasPermissionInMetadata(AccessControlAction.UsersDisable, user);
|
||||
const canEnable = contextSrv.hasPermissionInMetadata(AccessControlAction.UsersEnable, user);
|
||||
|
||||
@@ -216,6 +216,13 @@ export const OrgUsersTable = ({
|
||||
<>{Array.isArray(value) && value.length > 0 && <TagBadge label={value[0]} removeIcon={false} count={0} />}</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'isProvisioned',
|
||||
header: 'Provisioned',
|
||||
cell: ({ cell: { value } }: Cell<'isProvisioned'>) => (
|
||||
<>{value && <Tag colorIndex={14} name={'Provisioned'} />}</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'isDisabled',
|
||||
header: '',
|
||||
|
||||
@@ -152,6 +152,13 @@ export const UsersTable = ({
|
||||
<>{Array.isArray(value) && value.length > 0 && <TagBadge label={value[0]} removeIcon={false} count={0} />}</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'isProvisioned',
|
||||
header: 'Provisioned',
|
||||
cell: ({ cell: { value } }: Cell<'isProvisioned'>) => (
|
||||
<>{value && <Tag colorIndex={14} name={'Provisioned'} />}</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'isDisabled',
|
||||
header: '',
|
||||
|
||||
@@ -22,7 +22,10 @@ export const UserProfileEditForm = ({ user, isSavingUser, updateProfile }: Props
|
||||
|
||||
// check if authLabels is longer than 0 otherwise false
|
||||
const isExternalUser: boolean = (user && user.isExternal) ?? false;
|
||||
const authSource = isExternalUser && user && user.authLabels ? user.authLabels[0] : '';
|
||||
let authSource = isExternalUser && user && user.authLabels ? user.authLabels[0] : '';
|
||||
if (user?.isProvisioned) {
|
||||
authSource = 'SCIM';
|
||||
}
|
||||
const lockMessage = authSource ? ` (Synced via ${authSource})` : '';
|
||||
const disabledEdit = disableLoginForm || isExternalUser;
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ export interface OrgUser extends WithAccessControlMetadata {
|
||||
isDisabled: boolean;
|
||||
authLabels?: string[];
|
||||
isExternallySynced?: boolean;
|
||||
// Externally provisioned
|
||||
isProvisioned?: boolean;
|
||||
}
|
||||
|
||||
export interface User {
|
||||
@@ -56,6 +58,7 @@ export interface UserDTO extends WithAccessControlMetadata {
|
||||
orgs?: Unit[];
|
||||
isExternallySynced?: boolean;
|
||||
isGrafanaAdminExternallySynced?: boolean;
|
||||
isProvisioned?: boolean;
|
||||
}
|
||||
|
||||
export interface Invitee {
|
||||
|
||||
@@ -7822,6 +7822,9 @@
|
||||
"isExternallySynced": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lastSeenAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
@@ -12428,6 +12431,9 @@
|
||||
"isGrafanaAdminExternallySynced": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"login": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -12475,6 +12481,9 @@
|
||||
"isDisabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProvisioned": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lastSeenAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
|
||||
Reference in New Issue
Block a user