メインコンテンツまでスキップ
バージョン: 20 R5

権限

データ保護と、承認ユーザーによる迅速かつ容易なデータアクセスを両立することは、Webアプリケーションにとって大きな課題です。 ORDA のセキュリティアーキテクチャーはデータストアの中心に実装されており、プロジェクト内のさまざまなリソース (データストア、データクラス、関数など) に対して、すべての Web または REST ユーザーセッションに特定の権限を定義することができます。

概要

ORDA のセキュリティアーキテクチャーは、権限、許諾アクション (read、create など)、およびリソースの概念に基づいています。

Webユーザーまたは RESTユーザーがログインすると、そのセッションには自動的に関連する権限がロードされます。 権限は、session.setPrivileges() 関数によって、セッションに割り当てられます。

セッション内で送信されるユーザーリクエストは、プロジェクトの roles.json ファイルで定義された権限に対して評価されます。

権限外のアクションをユーザーが実行しようとすると、権限エラーが生成されるか、あるいは読み取り権限がない属性の場合にはそのデータは送信されません。

schema

リソース

プロジェクト内の以下のリソースに対して、許諾アクションと権限名を割り当てることができます (この設定をパーミッションと呼びます):

  • データストア
  • データクラス
  • 属性 (計算属性およびエイリアス属性を含む)
  • データモデルクラス関数

セッションがリソースにアクセスするたびに (アクセス形式に関係なく)、4D はセッションの権限を確認し、許可されていない場合にはアクセスを拒否します。

あるレベルにおいて定義されたパーミッションは基本的に下位レベルに継承されますが、パーミッションは複数のレベルで設定することもできます:

  • データストアレベルで定義されたパーミッションは、自動的にすべてのデータクラスに割り当てられます。
  • データクラスレベルで定義されたパーミッションは、データストアの設定をオーバーライドします (あれば)。 デフォルトでは、データクラスのすべての属性が、データクラスのパーミッションを継承します。
  • データクラスとは異なり、属性レベルで定義されたパーミッションは、親のデータクラスの設定をオーバーライドするのではなく、それに追加されます。 たとえば、同じ許諾アクションに対し、データクラスのレベルでは "general" という権限名を、データクラスの属性のレベルでは "detail" という権限名を割り当てた場合、その属性にアクセスするには、セッションに "general" と "detail" の両方の権限が設定されている必要があります。
info

パーミッションは、データストアオブジェクトへのアクセスを制御します。 特定の条件に基づいて読み取りデータをフィルタリングしたい場合は、制限付エンティティセレクション の利用がより適切かもしれません。

許諾アクション

利用可能なアクションは対象となるリソースによります。

アクションデータストアデータクラス属性データモデル関数
create任意のデータクラスにおいてエンティティを作成当該データクラスにおいてエンティティを作成当該属性に許可されたデフォルト値とは異なる値を持つエンティティを作成 (エイリアス属性の場合は無視されます)n/a
read任意のデータクラスにおいて属性を読み取り当該データクラスにおいて属性を読み取り当該属性を読み取りn/a
update任意のデータクラスにおいて属性を更新当該データクラスにおいて属性を更新当該属性を更新 (エイリアス属性の場合は無視されます)n/a
drop任意のデータクラスにおいてデータを削除当該データクラスにおいてデータを削除当該属性の null でない値を削除 (エイリアス属性と計算属性を除く)n/a
executeプロジェクトの任意の関数を実行 (データストア (authentify() を除く。後述の注記参照)、データクラス、エンティティセレクション、エンティティ)データクラスの任意の関数を実行。 データクラス関数、エンティティ関数、エンティティセレクション関数は、データクラスの関数として扱われます。n/a当該関数を実行
describe/rest/$catalog API ですべてのデータクラスが利用可能/rest/$catalog API で当該データクラスが利用可能/rest/$catalog API で当該属性が利用可能/rest/$catalog API で当該関数が利用可能
promoten/an/an/a関数の実行に指定の権限を関連付けます。 権限は一時的にセッションに追加され、関数の実行終了とともに削除されます。 セキュリティ上、セッション全体ではなく、当該関数を実行するプロセスのみに権限が追加されます。

注:

  • エイリアス属性の元である属性に対するアクセス権をセッションが持っていない場合でも、エイリアス属性へのアクセス権があれば、これを読み取ることができます。
  • 計算属性を構成する属性に対するアクセス権をセッションが持っていない場合でも、計算属性へのアクセス権があれば、これを読み取ることができます。
  • デフォルト値: 現在の実装では、Null のみデフォルト値として利用可能です。
  • REST の 強制ログインモード では、authentify()関数 は、権限の設定に関係なく常にゲストユーザーによって実行可能です。

許諾の設定は一貫している必要があります。とくに:

  • update および drop アクションには read が必要です (create には不要です)
  • promote アクションには describe が必要です

権限とロール

権限 とは、リソース に対して アクション を実行する技術的な能力であり、ロール は、管理者が使用するために公開された権限のことです。 基本的にロールとは、ビジネスユーザーのプロフィールを定義するためにいくつかの権限を集めたものです。 たとえば、"manageInvoices" (請求書管理) は権限の例で、"secretary" (秘書) は ("manageInvoices" および他の権限を持つ) ロールの例です。

権限は、複数の "リソース+アクション" の組み合わせと関連付けることができます。 また、一つのアクションに複数の権限を関連付けることができます。 権限は、他の権限を含むことができます。

  • 権限やロールの 作成roles.json ファイル内にておこないます (後述参照)。 アクセス権の範囲を 設定 するには、リソースに適用される許諾アクションに権限名を割り当てます。

  • 各ユーザーセッションに権限やロールを 許可 するには、Session クラスの .setPrivileges() 関数を使用します。

例題

セッションにおいて特定のロールを許可します:


exposed Function authenticate($identifier : Text; $password : Text)->$result : Text

var $user : cs.UsersEntity

Session.clearPrivileges()

$result:="ゲストとしてログインしています"

$user:=ds.Users.query("identifier = :1"; $identifier).first()

If ($user#Null)
If (Verify password hash($password; $user.password))
Session.setPrivileges(New object("roles"; $user.role))
$result:=$user.role+"としてログインしています"
End if
End if



roles.json ファイル

roles.json ファイルは、プロジェクトのセキュリティ設定の全体を記述します。

Qodly (クラウド) 以外のコンテキストでは、このファイルを次の場所に作成する必要があります: <project folder>/Project/Sources/アーキテクチャー を参照ください。

roles.json ファイルの構文は次のとおりです:

プロパティ名必須説明
privilegesprivilege オブジェクトの Collection定義された権限のリスト
[].privilegeStringアクセス権の名称
[].includesString の Collection内包する権限名のリスト
rolesrole オブジェクトの Collection定義されたロールのリスト
[].roleStringロール名
[].privilegesString の Collection内包する権限名のリスト
permissionsObject設定されたパーミッションのリスト
allowedpermission オブジェクトの Collection許可されたパーミッションのリスト
[].applyToString対象の リソース
[].typeStringリソース タイプ: "datastore", "dataclass", "attribute", "method"
[].readString の Collection権限名のリスト
[].createString の Collection権限名のリスト
[].updateString の Collection権限名のリスト
[].dropString の Collection権限名のリスト
[].describeString の Collection権限名のリスト
[].executeString の Collection権限名のリスト
[].promoteString の Collection権限名のリスト
forceLoginBoolean"forceLogin" モード を有効にする場合は true
注記
  • "WebAdmin" 権限名は、アプリケーションによって予約されています。 この名前をカスタムの権限名に使用することは推奨されません。
  • privileges および roles の名称においては文字の大小が区別されます。

Roles_Errors.json ファイル

roles.json ファイルは、4D 起動時に解析されます。 このファイルへの変更を反映させるには、アプリケーションを再起動する必要があります。

roles.json ファイルを解析する際にエラーが発生した場合、4D はプロジェクトを読み込みますが、グローバルアクセス保護は無効になります。これにより、開発者はエラー修正のためファイルにアクセスすることができます。 また、Roles_Errors.json という名前のエラーファイルが プロジェクトの Logs フォルダー に生成され、エラー行が記述されています。 このファイルは、roles.json ファイルのエラーがすべて修正されると、自動的に削除されます。

Roles_Errors.json ファイルが Logs フォルダー に存在するかどうか、起動時に確認することをお勧めします。存在する場合、解析エラーが発生し、アクセスが制限されないことを意味します。 たとえば、次のように書くことができます:

/Sources/DatabaseMethods/onStartup.4dm
If (Not(File("/LOGS/"+"Roles_Errors.json").exists))

Else // プロジェクトが開かれるのを防ぐことができます
ALERT("roles.json ファイルが不正なため、アプリケーションを終了します。")
QUIT 4D
End if

運用のための権限の初期化

roles.json ファイルに特定のパラメーターが定義されていない場合のデフォルトでは、アクセスは制限されません。 これにより、アクセスを気にすることなくアプリケーションを開発することができます。

しかし、実際にアプリケーションを運用する前には、まずすべての権限をロックしてから、許可されたセッションに必要な部分のみを公開するよう、ファイルを構成することが推奨されます。 すべてのリソースに対してすべての権限をロックするには、次の roles.json ファイルをプロジェクトフォルダーに置きます (メソッドの例が含まれています)。

/Project/Sources/roles.json
{
"privileges": [
{
"privilege": "none",
"includes": []
}
],

"roles": [],

"permissions": {
"allowed": [{
"applyTo": "ds",
"type": "datastore",
"read": [
"none"
],
"create": [
"none"
],
"update": [
"none"
],
"drop": [
"none"
],
"execute": [
"none"
],
"describe": [
"none"
],
"promote": [
"none"
]
},
{
"applyTo": "ds.loginAs",
"type": "method",
"execute": [
"guest"
]
},
{
"applyTo": "ds.hasPrivilege",
"type": "method",
"execute": [
"guest"
]
},
{
"applyTo": "ds.clearPrivileges",
"type": "method",
"execute": [
"guest"
]
},
{
"applyTo": "ds.isGuest",
"type": "method",
"execute": [
"guest"
]
},
{
"applyTo": "ds.getPrivileges",
"type": "method",
"execute": [
"guest"
]
},
{
"applyTo": "ds.setAllPrivileges",
"type": "method",
"execute": [
"guest"
]
}

]
}
}