Skip to content

特権ユーザの削除・編集の制限(改修案) ​

第1版作成 最終更新 (日本時間)
確認バージョン1.5.8.1

プリザンターでは、テナント管理者が特権ユーザを削除・編集できます。特権ユーザを保護する機能は本体にありません。このページは、特権ユーザの削除(と編集)を特権ユーザだけに限る本体改修の設計メモです。

本体を改修せずにできる範囲(OnSelectingWhere の拡張 SQL でユーザ一覧から隠す方法)とその限界は 拡張 SQL の活用 にあります。拡張 SQL では API からの /api/users/{id}/Delete を止められないため、ここでは権限判定そのものに手を入れます。

前提にした現行実装(1.5.8.1) ​

  • 特権ユーザは App_Data/Parameters/Security.json の PrivilegedUsers に LoginId で列挙されたユーザで、Context.HasPrivilege が true になり、ほとんどの権限チェックをバイパスします(アクセス権限の実装)。判定は Permissions.PrivilegedUsers(loginId)(Permissions.cs#L883-L887)。

  • users コントローラの削除可否は「CanManageTenant かつ本人でない」だけです(Permissions.cs#L608-L610)。

    csharp
    case "users":
        return CanManageTenant(context: context)
            && context.UserId != context.Id;
  • 更新可否は「CanManageTenant または本人 または EnableManageTenant」です(Permissions.cs#L563-L566)。

  • context.Id は URL の {id}(対象ユーザの UserId)です。画面の削除も API の削除も UserValidators.OnDeleting → context.CanDelete(ss) を通ります(UserValidators.cs#L1811-L1852)。

  • ユーザ情報はテナントキャッシュから SiteInfo.User(context, userId) で引けます(SiteInfo.cs#L439)。

図を読み込み中…

期待する動作 ​

操作者対象削除
テナント管理者一般ユーザ可(現行どおり)
テナント管理者特権ユーザ不可(新規)
特権ユーザ別の特権ユーザ可
誰でも自分自身不可(現行どおり。本人チェックが先に効く)

画面と API の両方で同じ制限にします。

改修箇所の候補 ​

案改修箇所長所短所
1(推奨)Permissions.CanDelete の case "users"権限判定が 1 か所に集まり、画面・API と、CanDelete で出し分けている削除ボタン(HtmlCommands.cs)に同時に効く判定のたびに SiteInfo.User を引く(キャッシュなので軽い)
2UserValidators.OnDeleting の CanDelete の後ユーザ検証の中で完結し、専用のエラー種別を返しやすい削除ボタンの表示など CanDelete を使う他の箇所には効かない

案 1 の改修イメージです。

csharp
case "users":
    var targetUser = SiteInfo.User(
        context: context,
        userId: (int)context.Id);
    return CanManageTenant(context: context)
        && context.UserId != context.Id
        && (!PrivilegedUsers(loginId: targetUser?.LoginId)
            || context.HasPrivilege);

最後の条件の意味は次のとおりです。

  • 対象が特権ユーザでない → 削除可能
  • 対象が特権ユーザで、操作者も特権ユーザ → 削除可能
  • 対象が特権ユーザで、操作者が特権ユーザでない → 削除不可

SiteInfo.User は該当ユーザがいないと null を返しうるため、targetUser?.LoginId のように null を考慮します(PrivilegedUsers(null) は false)。

案 2 の場合は、OnDeleting の CanDelete 判定の後に次を足します。

csharp
if (!context.HasPrivilege
    && Permissions.PrivilegedUsers(loginId: userModel.LoginId))
{
    return new ErrorData(type: Error.Types.HasNotPermission);
}

パラメータで切り替える案 ​

既存環境の挙動を変えないよう、制限をパラメータで有効にする案です。削除だけでなく編集(CanUpdate)にも同じ制限をかけられるようにします。

方式 1: フラグ列挙型(推奨) ​

Implem.ParameterAccessor/Parts/Security.cs に列挙型とプロパティを追加します。

csharp
[Flags]
public enum PrivilegedUserRestrictions
{
    None = 0,
    Delete = 1,
    Update = 2
}

public class Security
{
    public List<string> PrivilegedUsers;
    // 既存のプロパティ...
    public PrivilegedUserRestrictions RestrictPrivilegedUsers;
}
json
{
    "PrivilegedUsers": ["admin"],
    "RestrictPrivilegedUsers": "Delete, Update"
}
設定値意味
"None"制限なし(既定。現行どおり)
"Delete"削除だけ制限
"Update"編集だけ制限
"Delete, Update"両方を制限

1 つのパラメータで複数の制限を持て、将来の追加もしやすい形です。

方式 2: 真偽値を 2 つ ​

csharp
public bool RestrictPrivilegedUserDeletion;
public bool RestrictPrivilegedUserUpdate;

既存のパラメータの書き方に近く分かりやすい一方、制限の種類が増えるとパラメータも増えます。

判定の改修(方式 1 の場合) ​

削除:

csharp
case "users":
    var canDelete = CanManageTenant(context: context)
        && context.UserId != context.Id;
    if (canDelete
        && Parameters.Security.RestrictPrivilegedUsers.HasFlag(
            PrivilegedUserRestrictions.Delete))
    {
        var targetUser = SiteInfo.User(
            context: context,
            userId: (int)context.Id);
        if (PrivilegedUsers(loginId: targetUser?.LoginId)
            && !context.HasPrivilege)
        {
            return false;
        }
    }
    return canDelete;

編集:

csharp
case "users":
    var canUpdate = CanManageTenant(context: context)
        || context.UserId == context.Id
        || context.UserSettings?.EnableManageTenant == true;
    if (canUpdate
        && Parameters.Security.RestrictPrivilegedUsers.HasFlag(
            PrivilegedUserRestrictions.Update))
    {
        var targetUser = SiteInfo.User(
            context: context,
            userId: (int)context.Id);
        if (PrivilegedUsers(loginId: targetUser?.LoginId)
            && !context.HasPrivilege)
        {
            return false;
        }
    }
    return canUpdate;

対象が特権ユーザでなければ条件に当たらないため、一般ユーザが自分のプロファイルを編集する動作は変わりません。編集の制限を有効にすると、テナント管理者だけでなく EnableManageTenant(委任管理)のユーザも特権ユーザを編集できなくなります。削除は取り返しがつかないため有効を推奨し、編集は運用上の影響が大きいので必要なときだけ有効にするのが無難です。

専用のエラーメッセージ(任意) ​

HasNotPermission ではなく理由の分かるメッセージを返す場合は、エラー種別と表示文言を追加します。1.5.8.1 では、エラー種別の列挙は Implem.Pleasanter/Libraries/General/Error.cs、表示文言は App_Data/Displays/ の ID ごとの JSON(例: PermissionNotSelfChange.json)にあります。

ID(案)日本語英語
CannotDeletePrivilegedUser特権ユーザは削除できません。Cannot delete a privileged user.
CannotUpdatePrivilegedUser特権ユーザは編集できません。Cannot update a privileged user.

専用のエラーを返すには、CanDelete が bool を返す作りのため、案 2(OnDeleting で判定)と組み合わせます。

テスト観点 ​

削除の制限が有効な場合:

  1. テナント管理者が一般ユーザを削除できる(現行どおり)
  2. テナント管理者が特権ユーザを削除しようとすると拒否される
  3. 特権ユーザが別の特権ユーザを削除できる
  4. 特権ユーザが自分を削除しようとすると拒否される(現行どおり)
  5. API(/api/users/{id}/Delete)でも 1〜4 と同じ結果になる

編集の制限が有効な場合:

  1. テナント管理者が一般ユーザを編集できる
  2. テナント管理者・委任管理のユーザが特権ユーザを編集しようとすると拒否される
  3. 特権ユーザが別の特権ユーザを編集できる
  4. 一般ユーザ・特権ユーザが自分のプロファイルを編集できる
  5. API でも同じ結果になる

制限が無効(None)の場合は、テナント管理者が特権ユーザを削除・編集できる(現行どおり)ことを確かめます。

関連ページ ​

変更履歴

第1版管理機能の権限・グループの入れ子・トップ画面とテナント・api/users の実行権限の解説と、権限グループ・特権ユーザ保護の改修・設計メモを追加