api/users の実行権限
ユーザ API(/api/users/...)は、テナント管理者でなくても一部の操作ができます。1.5.8.1 のソースでの判定をまとめます。
- Get は API が使えるユーザなら誰でも実行でき、同じテナントの全ユーザを取得できる。画面のユーザ管理と違い、テナント管理者かどうかを見ない
- Update は自分自身(
/api/users/{自分のUserId}/Update)なら一般ユーザでも実行できる。変えられる列は、列ごとの既定のアクセス制御で決まる - Create・Delete・Import はテナント管理者(または特権ユーザ)だけ。委任管理(
EnableManageTenant)のユーザにはできない
管理権限の種類(特権ユーザ・テナント管理者・委任管理)とコントローラごとの判定の全体は アクセス権限の実装 を参照してください。
エンドポイント
ルーティングは Controllers/Api/UsersController.cs の属性ルーティングで、すべて POST です(UsersController.cs)。
| ルート | 処理 | 使う検証 |
|---|---|---|
api/users/Get、api/users/{id}/Get | UserUtilities.GetByApi | UserValidators.OnEntry |
api/users/Create | UserUtilities.CreateByApi | UserValidators.OnCreating |
api/users/{id}/Update | UserUtilities.UpdateByApi | UserValidators.OnUpdating |
api/users/{id}/Delete | UserUtilities.DeleteByApi | UserValidators.OnDeleting |
api/users/Import | UserUtilities.ImportByApi | UserValidators.OnImporting |
コントローラには [AllowAnonymous] と [CheckApiContextAttributes] が付いています。[AllowAnonymous] は ASP.NET Core の認証を素通りさせるだけで、各アクションが context.Authenticated を確かめ、未認証なら Unauthorized を返します。
全操作に共通の事前チェック
図を読み込み中…
CheckApiContextAttributes は、リクエストボディの有無、Security.json の AllowIpAddresses による IP 制限、契約設定の IP 制限、JSON の妥当性、TokenCheck 有効時のトークンを確かめます(CheckApiContextAttributes.cs)。
Validators.ValidateApi は、次のどれかに当たると InvalidRequest(403)を返します(Validators.cs#L72-L94)。サーバースクリプトから呼ばれた場合(serverScript: true)はこの 3 つを確かめません。
Api.jsonのEnabledがfalse- 契約設定で API が無効
UserSettings.AllowApi()がfalse
AllowApi() はユーザの「API を許可」列だけで決まるわけではありません(UserSettings.cs#L102-L108)。
特権ユーザなら true。それ以外は
(User.json の DisableApi も テナントの DisableApi も false または ユーザの AllowApi が true)
かつ UserSettings の DisableApi が true でない既定(User.json の DisableApi が false)では全ユーザが API を使えます。ユーザの「API を許可」列が効くのは、パラメータかテナントで API を無効にしたときだけです。
操作ごとの判定
判定に出てくるメソッドの中身は次のとおりです(Permissions.cs#L450-L705、#L770-L795)。context.Id は URL の {id}、context.UserId はログインユーザです。
メソッド(users の場合) | 条件 |
|---|---|
CanManageTenant | テナント管理者 または 特権ユーザ |
CannotManageUsers | EnableManageTenant でない かつ 特権ユーザでない かつ ShowProfiles が false |
CanRead | CanManageTenant または 本人(UserId == Id) または EnableManageTenant |
CanCreate | EnableManageTenant なら false、それ以外は CanManageTenant |
CanUpdate | CanManageTenant または 本人 または EnableManageTenant |
CanDelete | CanManageTenant かつ 本人でない |
CanImport | CanManageTenant |
CanExport | CanManageTenant または EnableManageTenant |
各操作の検証の順序です(UserValidators.cs)。
| 操作 | 評価順 |
|---|---|
| Get | ValidateApi のみ |
| Create | ValidateApi → ShowProfiles または特権ユーザ → CanCreate → 列ごとの CanCreate |
| Update | ValidateApi → CannotManageUsers → 自分の「テナント管理者」の変更禁止 → CanUpdate → 列ごとの CanUpdate |
| Delete | ValidateApi → ShowProfiles または特権ユーザ → CanDelete |
| Import | ValidateApi → ShowProfiles または特権ユーザ → CanImport |
ShowProfiles(Service.json、既定 true)が false だと、特権ユーザ以外は Create・Delete・Import が InvalidRequest になり、Update も EnableManageTenant のユーザ以外は CannotManageUsers で止まります。
Get
API の場合、OnEntry は ValidateApi だけで通過し、CannotManageUsers やテナント管理者のチェックをしません(UserValidators.cs#L18-L43)。画面のユーザ管理(api: false)では CannotManageUsers と「テナント管理者または EnableManageTenant」を確かめるので、API と画面で入口の条件が違います。
取得結果は Users.TenantId でテナントに絞られます。メールアドレスは、リクエストのビューの ApiGetMailAddresses を指定したときだけ含まれます。ビューの ColumnFilterHash に SiteId を指定すると、そのサイトの読み取り権限を確かめたうえで、そのサイトに権限を持つ有効なユーザだけに絞られます(UserUtilities.cs#L5063-L5190)。
Update(自分のプロファイルの更新)
一般ユーザが自分の UserId を指定して /api/users/{id}/Update を呼ぶと、次の順に通過します。
図を読み込み中…
自分の「テナント管理者」を変える操作は PermissionNotSelfChange で拒否されますが、この判定は context.Forms.Exists("Users_TenantManager") を見ています(UserValidators.cs#L1082-L1086)。API のリクエストはフォームではなく JSON なので、API ではこのチェックは働かず、列ごとの CanUpdate だけで判定されます(「テナント管理者」の列は既定で更新に ManageTenant が必要なので、テナント管理者以外は変えられません)。
列ごとのチェックは、更新できない列について値が変わっている場合だけ HasNotChangeColumnPermission を返します。更新できない列を同じ値で送ってもエラーにはなりません。
Delete
CanDelete は「CanManageTenant かつ本人でない」だけで、削除対象が特権ユーザかどうかは見ません。テナント管理者は特権ユーザも削除できます(Permissions.cs#L608-L610)。対策は 拡張 SQL の活用(一覧から隠す方法)と 特権ユーザの削除・編集の制限(改修案) を参照してください。
ユーザ種別ごとの可否
ShowProfiles = true(既定)で、API が使えるユーザの場合です。
| 操作 | テナント管理者 | 一般ユーザ | EnableManageTenant | 特権ユーザ |
|---|---|---|---|---|
| Get | 可 | 可(テナント内の全ユーザ) | 可 | 可 |
| Create | 可(ただし EnableManageTenant も有効なら不可) | 不可 | 不可 | 可 |
| Update | 可(全ユーザ) | 自分だけ | 可(全ユーザ) | 可 |
| Delete | 可(自分以外) | 不可 | 不可 | 可(自分以外) |
| Import | 可 | 不可 | 不可 | 可 |
列ごとの既定のアクセス制御
ユーザ管理の SiteSettings には、サイト権限の代わりに Permissions.Admins() の値(テナント管理者なら ManageTenant、サービス管理者なら ManageService のビット)がセットされます。各列の既定の条件は列定義(App_Data/Definitions/Definition_Column/Users_*.json)の ReadAccessControl・CreateAccessControl・UpdateAccessControl で、主なものは次のとおりです(1.5.8.1)。
| 既定の条件 | 列 |
|---|---|
読み取り・作成・更新とも ManageTenant | テナント管理者、トップサイトでの作成許可、グループ管理の許可、グループ作成の許可、API の許可、トップサイトからの移動許可、二要素認証の有効化・無効化、無効、ロックアウト、ロックアウト回数、ログイン有効期限、パスワード有効期限、シークレットキーの有効化 |
更新だけ ManageTenant | 組織(DeptId)、パスワード(読み取りは ManageService) |
読み取り・作成・更新とも ManageService | 姓、名、生年月日、性別、姓名の順序、サービス管理者、開発者 |
読み取りは ManageTenant、作成・更新は ManageService | 最終ログイン日時、ログイン回数、認証失敗回数、パスワード変更日時 |
| 条件なし(誰でも) | ログイン ID、グローバル ID、名前、ユーザコード、言語、タイムゾーン、テーマ、管理者、説明 など |
「条件なし」の列は項目のアクセス制御では制限されないため、CanUpdate を通ったユーザ(本人を含む)が変更できます。ManageService が条件の列は、テナント管理者や特権ユーザでも ServiceManager でなければ読み書きできません(特権ユーザは ManageTenant のビットは持ちますが ManageService は持ちません)。
API の許可(AllowApi)の列は、User.json の DisableApi もテナントの DisableApi も false のとき(または契約で API が無効のとき)、条件が ManageService に差し替えられ、通常は見えません。パラメータかテナントで API を無効にしているときは列定義どおり ManageTenant が条件になり、委任管理のユーザに対しては条件なしに差し替えられます(SiteSettingsUtilities.cs#L536-L597)。