スクリプト:ACL が評価される状況の理解Issue ビジネスルール、UI スクリプト、スクリプトインクルード、バックグラウンドスクリプト、UI アクション、クライアントスクリプト、実行時に発生する ACL 評価について確認する場合、まず知っておく必要がある 3 つの事項は以下のとおりです。 前述のスクリプトは、現在のユーザーのコンテキストで実行される。ServiceNow のサーバーサイド JavaScript API クラスを利用してレコードを作成、読み取り、更新、削除するスクリプトは、アクセス制御ルール (Access Control Rules, ACL) の合格または不合格の対象にはならない。GlideRecordSecure クラスはこの例外。ServiceNow のクライアントサイド JavaScript API 関数を利用するスクリプトでは、常に ACL が適用される。 この 3 点について理解していないと、クライアントサイドとサーバーサイドの JavaScript に関連する問題の調査に手間取ることがよくあります。 例 わずか 1 つの UI アクションを使用して、これら 3 つの事項をすべて確認できます。まず、次の質問から始めましょう。 「フォームの [ステータス (State)] フィールドへの書き込みアクセス権がないユーザーが、テーブル [sysapproval_approver] のレコードを承認できるのはなぜですか?」 テストインスタンスで次の URL に移動し、この UI アクションを確認してください。 /nav_to.do?uri=sys_ui_action.do?sys_id=8468ee55c611227d01a072a67bdbd3e7 [クライアント (Client)] チェックボックスがオフになっているため、サーバーサイドの JavaScript が実行されます。UI アクションで実行されるスクリプトは、現在のレコードのステータスを「approved」に設定してから、レコードを更新して変更を保存します。すでに説明したように、デフォルトではサーバーサイドで ACL が適用されないため、テーブル sysapproval_approver での ACL への合否に関係なく、UI アクションのフォームボタンにアクセスできるすべてのユーザーが現在の承認レコードを承認できることがわかります。 UI アクションのフォームボタンの状況を表示するための条件は、現在のレコードのステータスが「requested」であり、現在のユーザーがレコードの承認者または承認者の代理人でなければならないというものです。テーブルの ACL がテーブルに対する書き込み権限を持たないユーザーによる承認を防止するという前提のもと、より多くのエンドユーザーに UI アクションボタンが表示されるように条件を緩和すると問題が発生します。 この状況をテストしてみましょう。 次の UI アクションの条件を変更します。 current.state == 'requested' && isApprovalMine(current) これを次のように変更します。 current.state == 'requested' アプリケーションナビゲーターで [デバッグ (Debug)] を探して [セキュリティのデバッグ] をクリックします。ITIL ユーザーとして代理操作します。ITIL ユーザーは、テーブル [sysapproval_approver] のすべてのレコードを読み取ることはできますが、デフォルトのすぐに利用可能なインスタンスの [ステータス] フィールドの書き込み ACL には合格しません。/nav_to.do?uri=sysapproval_approver_list.do に移動します。ステータスが「requested」のレコードを開きます。ブラウザのページで「state/write」というテキストを検索します。(Mac では Chrome で ⌘+Enter を使用して検索します。Windows では、Ctrl + f を使用します。)テキスト検索の結果を確認すると、ITIL ユーザーが sysapproval_approver.state の書き込み ACL に不合格であることが分かります。[承認 (Approve)] UI アクションボタンを押します。 直感的には ACL によって ITIL ユーザーによる [ステータス] フィールドへの書き込みが防止されると思うかもしれませんが、実際には、UI アクションのサーバーサイド JavaScript は ACL をチェックせずに [ステータス] フィールドを更新できます。このテストの最終結果は、[ステータス] フィールドの書き込み ACL に合格できないユーザーによりレコードが承認されるというものです。これが可能である理由は、このユーザーに [承認] UI アクションのフォームボタンを使用できるアクセス権を付与したためです。 サーバーサイドスクリプトで ACL が適用されるようにする必要がある場合は、以下のオプションがあります。 サーバーサイドの GlideRecord クラスの canCreate()、canRead()、canWrite()、canDelete() の各関数、またはサーバーサイドの GlideElement クラスの canRead() 関数、canWrite() 関数を使用できます。テーブルレベルで ACL をチェックするには GlideRecord 関数を使用し、フィールドレベルで ACL をチェックするには GlideElement 関数を使用します。GlideRecord と GlideElement の「can」関数は非常に単純です。ユーザーがテーブルまたはフィールドを作成、読み取り、削除、書き込みできる場合は true を返し、できない場合は false を返します。または、GlideRecordSecure クラスを使用できます。これは、GlideRecord クラスと同じように使用できますが、GlideRecordSecure では読み取りまたは書き込みしようとしているテーブルに ACL が適用される点が異なります。 引き続き前の例と同じ [承認] UI アクションを変更して、これをテストしましょう。 条件が次のままであることを確認します。 current.state == 'requested' 次のスクリプトを変更します。 current.state='approved'; current.update(); これを次のように変更します。 if(current.state.canWrite()){ current.state='approved'; current.update(); } UI アクションへの変更を保存し、ITIL ユーザーとして代理操作を行って、テーブル [sysapproval_approver] で要求の承認を再試行します。 今回は、[ステータス] フィールドが [Requested] から [Approved] に変更されていません。これは、更新を許可する前に、GlideElement クラスの canWrite() 関数を使用して、ITIL ユーザーが sysapproval_approver.state の書き込み ACL に合格できるかどうかが確認されるためです。ユーザーは ACL に不合格なため、[ステータス] フィールドを変更できません。 GlideRecordSecure クラスを使用することもできます。同じ UI アクションでこれをテストしましょう。 条件が次のままであることを確認します。 current.state == 'requested' 次のスクリプトを変更します。 if(current.state.canWrite()){ current.state='approved'; current.update(); } これを次のように変更します。 var grs = GlideRecordSecure('sysapproval_approver'); grs.get(current.sys_id); grs.state='approved'; grs.update(); UI アクションへの変更を保存し、ITIL ユーザーとして代理操作を行って、テーブル [sysapproval_approver] で要求の承認を再試行します。 方法が異なるだけで、結果はまったく同じです。ITIL ユーザーは、やはり [ステータス] フィールドを変更できません。 サーバーサイドのデフォルト動作では ACL が適用されない場合に、これをクライアントサイドに変えるとどのように機能しますか? この質問に答えるために、3 つ目の事項に触れます。クライアントサイドの JavaScript API 関数は常に ACL を適用します。その理由は、誰がこの関数を実行するのかをコントロールできないためです。技術に精通したエンドユーザーなら誰でも、ブラウザで JavaScript コンソールを開き、どのようなクライアントサイドの JavaScript でも実行できます。 これを証明するには、前の UI アクションに変更を加えて、クライアントサイドの JavaScript を実行するようにします。クライアントサイドの GlideRecord クラスを使用して [ステータス] フィールドを「approved」に設定し、レコードを更新する新しいスクリプトを作成します。 条件が次のままであることを確認します。 current.state == 'requested' [クライアント] チェックボックスをオンにします。[クリック時 (Onclick)] フィールドに次を入力します。 approve() 次のスクリプトを変更します。 var grs = GlideRecordSecure('sysapproval_approver'); grs.get(current.sys_id); grs.state='approved'; grs.update(); これを次のように変更します。 function approve(){ var gr = new GlideRecord('sysapproval_approver'); gr.get(g_form.getUniqueValue()); gr.state = 'approved'; gr.update(); } UI アクションへの変更を保存し、ITIL ユーザーとして代理操作を行って、テーブル [sysapproval_approver] で要求の承認を再試行します。 サーバーサイドの時のように、ACL が確実に適用されるようにするための特別な作業を行う必要はありません。ServiceNow のクライアントサイド JavaScript API では、常に ACL が適用されます。 ServiceNow の JavaScript API に関する問題の解決では、こうした違いを理解することが重要とされる場合があります。