tubasa_gekituiのブログ

salesforce社の無料学習サイト「Trailhead」の覚え書きとか日記とか

【Summer ’20 の新?機能】「Apex テストデータにアクセスする場合の「設定を参照」権限の必須化」を検証してみた【Let's Go 人柱】

この記事は Salesforce 開発者向けブログキャンペーンへのエントリー記事です。 Salesforce 開発者向けブログ投稿キャンペーン 第3弾 開催のお知らせ | Developer Force Blog

本記事は summer'20 の新機能 Apex テストデータにアクセスする場合の「設定を参照」権限の必須化 (更新)を検証してみた、です。
※. 第2回は諸事情により参加できませんでしたが、今回は連休もあって記事を書く時間が作れたのら

このリリース内容を引用してみますと、

この更新により、Salesforce 組織のセキュリティが向上します。この更新を有効にすると、ユーザが sObject (ApexTestQueueItem、ApexTestResult、ApexTestResultLimits、ApexTestRunResult、ApexTestSuite、TestSuiteMembership) にアクセスする場合に「設定・定義を参照する」権限が必要になります。

てか、テストに関するsObjectがありアクセスできることを今知ったにぇ!※. お前はこの5年間(適当)何をしてきたんだ?って感じですが・・・。
ということで、先のオブジェクトにアクセスするとどういう情報が取得できるのかどういった制限があるのか見るために人柱になりにきました、進んで。

では、試していきますぺこ。 ぺこ??

前置き

今回、記事作成のために構築したファンタジーsalesforceの組織情報はGit Hub にて公開しております。作成した内容の9割がsalesforce 上でドメイン駆動設計を実践してみたという、本記事とは関係のない内容になります。
以下リンクから参照できます。
Git hub 社員管理?アプリケーション

プロファイルとユーザの準備

まず初めに、プロファイルに「システム管理者」をコピーし、「設定・定義を参照する」チェックを外します。 チェックを外す前後の画像を並べて表示していますが、外すと便乗して他の権限もいろいろ外れるということがわかります。

「設定・定義を参照する」のチェックを外す前「設定・定義を参照する」のチェックを外した後
設定のチェックを外す前と後

上記のプロファイル(プロファイル名は「システム管理者_設定・定義を参照するヌキ」)に属するユーザを作成します。
作成後のユーザ一覧がこちら。

ユーザ一覧:ユーザ名は念のため黒塗り
ユーザ一覧(ロボ子さんを追加)

開発者コンソールからクエリ実行

先ほど作成したユーザことロボ子さんで代理ログインをします。 で、開発者コンソールを立ち上げ&クエリ実行してsObject「ApexTestResult」の登録内容を確認してみます・・・。
が、「設定・定義を参照する」の権限を外してしまったばっかりに、赤枠内にいつもはあるはずの歯車アイコンが消えております。

代理ログイン後の社員一覧画面
代理ログイン後の社員一覧画面

本来はクエリ実行でエラーが表示される(キャプションは権限があるため成功)だったんですがねー。

理想と現実の理想の方(画像は権限があったため成功している)
仕方がないので別の方法を模索します。

Visualforceページを作成

確認する1つの方法として、登録内容を確認できるVisualforceページを用意します。内容をさっと確認したいだけなので最低限のコード記述のみです。
Visualforceページ作成後にはタブを作成&アプリケーションに追加しています。

Visualforce

<apex:page controller="ApexTestResultListController" lightningStylesheets="true">
    <h1>ApexTestResult の内容をただ確認したいだけ</h1>
    <apex:pageBlock title="ApexTestResultの内容">
        <apex:pageBlockTable value="{!testResults}" var="item">
            <apex:column value="{!item.ApexClassId}"/>
            <apex:column value="{!item.ApexLogId}"/>
            <apex:column value="{!item.ApexTestRunResultId}"/>
            <apex:column value="{!item.AsyncApexJobId}"/>
            <apex:column value="{!item.Message}"/>
            <apex:column value="{!item.MethodName}"/>
            <apex:column value="{!item.Outcome}"/>
            <apex:column value="{!item.QueueItemId}"/>
            <apex:column value="{!item.RunTime}"/>
            <apex:column value="{!item.StackTrace}"/>
            <apex:column value="{!item.TestTimestamp}"/>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

controller

public with sharing class ApexTestResultListController {
    public List<ApexTestResult> testResults {get; private set; }
    
    public ApexTestResultListController() {
        this.testResults = [
            select 
                ApexClassId, ApexLogId, ApexTestRunResultId, AsyncApexJobId
                , Message, MethodName, Outcome, QueueItemId, RunTime
                , StackTrace, TestTimestamp
            from ApexTestResult
        ];
    }
}

他に、ApexTestResultLimits, ApexTestRunResult も作成していますが、これらのコードは Github https://github.com/daitubasa/salesforce-developers-blog-3rd/tree/master/EmployeeManageProject を参照していただければと思います。

では、実際にアクセスしてみます。
まずはシステム管理者:友人Aさんの場合
当然ですが、エラーもなく書いたコードの通りに表示されます。

システム管理者 ApexTestResultの内容を確認
システム管理者 ApexTestResultの内容を確認

次に権限を外した:ロボ子さんの場合
画面一面に「アクセス権がありません」と、親の顔より見た光景が表示されます。

権限がないユーザ ApexTestResultの内容を確認
権限がないユーザ ApexTestResultの内容を確認

事前にデバッグログも仕込んでいたので、権限を外した:ロボ子さんのログを確認します。
画面上ではエラーメッセージが出ていたはずなのですが成功と表示されます。原因解明の手がかりがログに出ていないので、出くわしたら解決に面倒臭そうです。てか、キツい。

代理ログインで実行時のデバッグログ一覧代理ログインで実行時のデバッグログ詳細
代理ログインで実行時のデバッグログ

テストメソッドで実行したらどうなるの?

もう1つの方法として、テストメソッドで確認する方法です。
件のプロファイルに属したユーザを作成し、System.runAsのスコープ内で ApexTestResult オブジェクトにアクセスしてみます。

テストコード (システム管理者のケースと権限なしの2つ用意)

@isTest
private class RegisterEmployeeTest2 {

    @isTest 
    static void testController01() {
        Profile profile = getProfile('システム管理者');
        String uniqueUserName = 'RegisterEmployeeTest' + DateTime.now().getTime() + '@example.com';
        User u = registerUser(profile, uniqueUserName);
        System.runAs(u) {
            ApexTestResultListController con = new ApexTestResultListController();
            System.assertNotEquals(null, con.testResults, 'ApexTestResultの取得に失敗');
        }
    }
    @isTest 
    static void testController02() {
        Profile profile = getProfile('システム管理者_設定・定義を参照するヌキ');
        String uniqueUserName = 'RegisterEmployeeTest' + DateTime.now().getTime() + '@example.com';
        User u = registerUser(profile, uniqueUserName);
        System.runAs(u) {
            ApexTestResultListController con = new ApexTestResultListController();
            System.assertNotEquals(null, con.testResults, 'ApexTestResultの取得に失敗');
        }
    }

    private static Profile getProfile(String name) {
        return [select Id, Name from Profile where Name =: name limit 1];
    }

    private static User registerUser(Profile profile, String userName) {
        User u = new User(
            Alias = 'テスト太郎'
            , Email='daitubasa@example.com'
            , EmailEncodingKey='ISO-2022-JP'
            , LastName='Testing'
            , LanguageLocaleKey='ja'
            , LocaleSidKey='ja_JP'
            , TimeZoneSidKey='Asia/Tokyo'
            , ProfileId = profile.Id
            , UserName = userName
        );
        insert u;
        return u;
    }
}

テストを実行します。
システム管理者で実行したケースは Pass しますが、権限がないユーザで実行したケースは 例外:System.QueryException が発生します。

テスト実行結果テスト Failサマリ
Apexテスト実行結果

ただ、カラムがありませんと表示されているとは言え、このエラーメッセージで原因が「設定・定義を参照する」権限がないことを特定できるかというと、ベテランの方でないとなかなか難しいのではないでしょうか?と、思うわけです。

まとめ

「設定・定義を参照する」権限がないユーザが、

  • VF画面経由でApex テストデータのオブジェクトにアクセスすると、「アクセス権がありません」の一言で終わり正常終了扱いとなる。 デバッグログに発生した例外情報は出力されない。
  • テストメソッドでApex テストデータのオブジェクトにアクセスすると、例外:System.QueryException が発生する。テストケースは Failで終了する。

「ロジックをApexで書いたら、テストコードも合わせて書きましょう。原因特定が少しは楽になるかもしれません。」というオチぺこかな?

おまけ

  • 今回の記事作成にあたり、記事を書いている時間よりも土台のアプリケーションに時間がかかっていることは言わずもがなです。でもモノづくりは楽しい!
  • 土台のアプリケーションに置いて、salesforce 上でドメイン駆動設計でコードを書くのは無理ゲーだ、狂気の沙汰でしかないのでは?と感じている。データ駆動設計で構築されている基盤なので、業務ロジックがApexコード側とSObject(入力規則、数式)側に分散&設計思想に矛盾が生じている。
  • 久しぶりに VSCode + Apex で開発すると、Java の開発環境のありがたみがわかる。
  • 星街すいせいさんは 0期生だったんですね・・・。 すいちゃんは今日もかわいいー!

ホロメンバーの情報は以下リンクから参照しています。 seesaawiki.jp

土台のアプリケーションを作成する上で、代理ログインに関する設定は勉強になりました。「セッションの設定」カテゴリの項目は、構築する上での生産性に関わるのが多いのでは?と思った次第。 システム管理者が代理ログイン後に、再ログインしなくて済む方法