DataWedge Intent API へのアクセス制御

DataWedge 11.0

概要

DataWedge には、DataWedge Intent API へのアクセスを制御し、承認されたアプリのみが DataWedge を構成できるようにするための管理者向けのオプションがあります。DataWedge Intent API はカテゴリ化されているため、管理者は、カテゴリに基づいて特定のアプリに DataWedge API へのアクセス権を付与できます。デフォルトでは、DataWedge は、既存のアプリケーションに影響しないように任意のインテント API を受け入れます。

以前は、デバイス上の任意のアプリケーションで DataWedge パラメータを構成し、DataWedge API を介して構成やステータス通知などの情報を受信できていました。このため、悪意のあるアプリケーションが他のアプリケーション用の DataWedge プロファイルを構成し、それを独自に利を得るために活用できるという潜在的なセキュリティ リスクがありました。たとえば、悪意のあるアプリが IP 出力プラグインの宛先 URI を変更して、データ配信を別のアドレスに転送できていました。

デバイスには、MX バージョン 10.1.1 以降が必要です。

DataWedge Intent API へのアクセスの保護に関するビデオ デモ:

アクセスの制御

DataWedge Intent API へのアクセスを制御するプロセス:

  1. MX の AccessMgr CSP を使用して、承認済みアプリをホワイトリストに登録します。
  2. インテント API カテゴリを指定して、MX の DataWedge Manager を介したインテント API アクセスを制限します。
  3. EMDK を使用して、AccessMgr からアプリ トークンを取得します。
  4. DataWedge Intent にトークンを含めて API にアクセスします。

詳細については、以降のセクションで説明します。

1.承認済みアプリをホワイトリストに登録

DataWedge Intent API へのアクセスを制御する最初の手順では、管理者が、MX の AccessMgr CSP を使用してアプリをホワイトリストに登録します。ホワイトリストを使用することで、リストに指定されているアプリのみを実行でき、承認済みのホワイトリストに登録されていないアプリの使用が制限されます。StageNow または EMDK Profile Manager (Android または Xamarin) を使用して構成を展開し、アプリをホワイトリストに登録します。以下のパラメータを設定します。

  • サービス アクセス アクション: "Allow caller"
  • サービス ID: com.symbol.datawedge.api
  • 呼び出し元パッケージ名の指定: <Com.company.appname など、アプリのパッケージ名を入力>
  • 呼び出し元の署名: <アプリ証明書を含む署名ファイルを選択>

2.DataWedge Intent API を制限

デフォルトでは、すべての DataWedge API は非制御モードになっているため、どのアプリケーションもすべての DataWedge API にアクセスできます。管理者は、StageNow を介して DataWedgeMgr CSP を使用して DataWedge API カテゴリを制御/非制御モードにし、特定の API カテゴリへのアクセスを制限できます。DataWedge Manager「インテント API へのアクセス制御」を参照してください。
注:
       DataWedge 8.1 の場合は、DataWedge 8.1.61 以降が必要です。
       DataWedge 8.2 の場合は、DataWedge 8.2.62 以降が必要です。

API カテゴリ 制御モード
構成 API 非制御
制御
通知 API 非制御
制御
クエリ API 非制御
制御
ランタイム API 非制御
制御

非制御 – すべてのアプリから API にアクセスできます。デフォルト設定です。
制御 – API アクセスを制限します。管理者のみが AccessMgr CSP を使用して、API にアクセスするアプリをホワイトリストに登録できます。

DataWedge API は、以下の 4 つのタイプにカテゴリ化されています。

  • 構成 API - 構成で実行されるアクションに関連する API
  • 通知 API - スキャナ、プロファイル、または構成のステータスの取得に関連する API
  • クエリ API - 情報を取得したり、スキャナを列挙したりする API
  • ランタイム API - 実行時に機能を変更できる API

管理者は、DataWedge Manager を使用して保護するカテゴリを指定できます。デフォルトでは、すべての API カテゴリは非保護モードになっています。

インテント API カテゴリ インテント API
構成 API 構成の取得
無効アプリ リストの取得
プロファイルの複製
プロファイルの作成
プロファイルの削除
プロファイル名の変更
構成の設定
無効なプロファイルを無視の設定
無効アプリ リストの設定
構成の復元
構成のインポート
通知 API プロファイルの切り替え (通知の登録/登録解除)
スキャナ ステータス (通知の登録/登録解除)
構成変更 (通知の登録/登録解除)
クエリ API スキャナの列挙
アクティブ プロファイルの取得
DataWedge ステータスの取得
バージョン情報の取得
スキャナ ステータスの取得
プロファイル リストの取得
無効なプロファイルを無視の取得
ランタイム API DataWedge の有効化/無効化
スキャナ入力プラグインの有効化/無効化
スキャナ パラメータの切り替え
SimulScan パラメータの切り替え
ソフト スキャン トリガ
ソフト RFID トリガ
プロファイルの切り替え
デフォルト プロファイルの設定
デフォルト プロファイルのリセット
スキャナの切り替え
レポート オプションの設定

「DataWedge API」を参照してください。

3.トークンを取得

ホワイトリストに登録されたアプリケーションのみが、DataWedge サービス ID を呼び出してトークンを生成できます。アプリケーションでは、EMDK ProfileManager API を使用して AccessMgr CSP からトークンを取得する必要があります。

トークンを生成するには、EMDK Profile Manager を使用してプロファイルを作成します。

  1. EMDK Profile Manager (Android または Xamarin) を開きます。
  2. MX 10.1 以降を使用して新しいプロファイルを作成し、RequestToken などの名前を指定します。
  3. [使用可能な機能] リストで、[Access Manager] を選択して機能として追加します。
  4. Access Manager が [選択された機能] の下に表示されます。
  5. Access Manager のパラメータ セクションで、以下を設定/入力します。
    • サービス アクセス アクション: “Request Token”
    • サービス ID: com.symbol.datawedge.api

EMDK Profile Manager で生成された EMDKConfig.xml のサンプル:

    <?xml version="1.0" encoding="UTF-8"?><!--This is an auto generated document. Changes to this document may cause incorrect behavior.--><wap-provisioningdoc>
    <characteristic type="ProfileInfo">
        <parm name="created_wizard_version" value="7.3.2"/>
    </characteristic>
    <characteristic type="Profile">
        <parm name="ProfileName" value="RequestToken"/>
        <parm name="ModifiedDate" value="2020-03-23 20:01:24"/>
        <parm name="TargetSystemVersion" value="9.1"/>
        <characteristic type="AccessMgr" version="8.3">
        <parm name="emdk_name" value=""/>
        <parm name="ServiceAccessAction" value="7"/>
        <parm name="ServiceIdentifier" value="com.symbol.datawedge.api"/>
        </characteristic>
    </characteristic>
    </wap-provisioningdoc>

EMDK の ProcessProfile API を使用して、安全にアクセスできるように、目的の DataWedge API インテントに渡されるトークンを生成します。トークンを生成するためのサンプル コードを以下に示します。

    import android.content.Context;
    import android.os.AsyncTask;
    import android.text.TextUtils;
    import android.util.Xml;

    import com.symbol.emdk.EMDKManager;
    import com.symbol.emdk.EMDKResults;
    import com.symbol.emdk.ProfileManager;

    import org.xmlpull.v1.XmlPullParser;
    import org.xmlpull.v1.XmlPullParserException;

    import java.io.StringReader;

    public class TokenOperations implements EMDKManager.EMDKListener {

        static Object syncObj = new Object();
        Context mContext;
        // Provides the error type for characteristic-error
        private String errorType = "";
        // Provides the parm name for parm-error
        private String parmName = "";
        // Provides error description
        private String errorDescription = "";
        // Provides error string with type/name + description
        private String errorString = "";
        private String mToken = "";
        //Assign the profile name used in EMDKConfig.xml
        private String profileName = "";
        //Declare a variable to store ProfileManager object
        private ProfileManager profileManager = null;
        //Declare a variable to store EMDKManager object
        private EMDKManager emdkManager = null;


        public TokenOperations(Context context)
        {
            this.mContext = context;
        }

        public String getErrorDescription()
        {
            return errorDescription;
        }

        public String generateToken()
        {
            EMDKResults results = EMDKManager.getEMDKManager(mContext, this);

            //Check the return status of EMDKManager object creation.
            if(results.statusCode == EMDKResults.STATUS_CODE.SUCCESS) {
                //EMDKManager object creation success
            }else {
                //EMDKManager object creation failed
            }


            try {
                synchronized (syncObj) {
                    syncObj.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (emdkManager != null) {
                emdkManager.release();
                emdkManager = null;
            }

            return mToken;

        }

        @Override
        public void onOpened(EMDKManager emdkManager) {

            this.emdkManager = emdkManager;
            //Get the ProfileManager object to process the profiles
            profileManager = (ProfileManager) emdkManager.getInstance(EMDKManager.FEATURE_TYPE.PROFILE);
            profileName = "RequestToken";
            new ProcessProfileTask().execute("");
        }

        @Override
        public void onClosed() {

            //This callback will be issued when the EMDK closes unexpectedly.
            if (emdkManager != null) {
                emdkManager.release();
                emdkManager = null;
            }
        }

        private void parseXML(XmlPullParser myParser) {
            int event;
            try {
                // Retrieve error details if parm-error/characteristic-error in the response XML
                event = myParser.getEventType();
                while (event != XmlPullParser.END_DOCUMENT) {
                    String name = myParser.getName();
                    switch (event) {
                        case XmlPullParser.START_TAG:
                            if (name.equals("parm-error")) {
                                parmName = myParser.getAttributeValue(null, "name");
                                errorDescription = myParser.getAttributeValue(null, "desc");
                                errorString = " (Name: " + parmName + ", Error Description: " + errorDescription + ")";
                                return;
                            }
                            else if (name.equals("parm")) {
                                String parmName = myParser.getAttributeValue(null, "name");
                                if(parmName.equalsIgnoreCase("ServiceAccessToken"))
                                {
                                    //Retrieved Token will be saved to a variable
                                    mToken = myParser.getAttributeValue(null, "value");

                                    return;
                                }

                            }
                            break;
                        case XmlPullParser.END_TAG:

                            break;
                    }
                    event = myParser.next();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private class ProcessProfileTask extends AsyncTask<String, Void, EMDKResults> {

            @Override
            protected EMDKResults doInBackground(String... params) {

                parmName = "";
                errorDescription = "";
                errorType = "";
                mToken = "";

                EMDKResults resultsReset = profileManager.processProfile(profileName, ProfileManager.PROFILE_FLAG.RESET, params);
                EMDKResults results = profileManager.processProfile(profileName, ProfileManager.PROFILE_FLAG.SET, params);

                return results;
            }

            @Override
            protected void onPostExecute(EMDKResults results) {

                super.onPostExecute(results);

                String resultString = "";

                //Check the return status of processProfile
                if(results.statusCode == EMDKResults.STATUS_CODE.CHECK_XML) {

                    // Get XML response as a String
                    String statusXMLResponse = results.getStatusString();

                    try {
                        // Create instance of XML Pull Parser to parse the response
                        XmlPullParser parser = Xml.newPullParser();
                        // Provide the string response to the String Reader that reads
                        // for the parser
                        parser.setInput(new StringReader(statusXMLResponse));
                        // Call method to parse the response
                        parseXML(parser);

                        if (TextUtils.isEmpty(parmName) && TextUtils.isEmpty(errorType) && TextUtils.isEmpty(errorDescription) ) {

                            resultString = "Profile update success.";
                            if(!TextUtils.isEmpty(mToken))
                            {
                                resultString = "";
                            }
                        }
                        else {

                            resultString = "Profile update failed." + errorString;
                        }

                        synchronized (syncObj) {
                            syncObj.notify();
                        }

                    } catch (XmlPullParserException e) {
                        resultString =  e.getMessage();
                    }
                }
            }
        }
    }

4.API にアクセス

トークンが生成されたら、それを、DataWedge に送信する呼び出し元アプリケーションのパッケージ名とともにインテント API 呼び出しに含める必要があります。DataWedge でインテントを受信すると、そのトークンが特定のアプリケーションに対して有効かどうかが確認されます。トークンが有効な場合、DataWedge でそのインテントが処理されます。トークンが無効な場合は、以下のいずれかのエラー コードが発生します。

  • メイン エラー コード: APPLICATION_NOT_AUTHORIZED
  • サブ エラー コード:
    • TOKEN_EXPIRED: トークンの有効期限が切れています。アプリケーションは、新しいトークンを取得する必要があります。
    • MX_NOT_INITIALIZED: MX が初期化されていません。これは通常、リブート直後に発生します。
    • FAILED_TO_VERIFY_APPLICATION: 呼び出し元のアプリケーションを確認できません (トークンが無効である、アプリケーションがホワイトリストに登録されていないなど)。

以下の複数の API 用のソース コード サンプルが用意されています。

例 1: 構成の取得

    Intent i = new Intent();
    i.setAction("com.symbol.datawedge.api.ACTION");
    i.setPackage("com.symbol.datawedge");
    i.putExtra("APPLICATION_PACKAGE", getPackageName());
    i.putExtra("TOKEN", "291f7f7c-1479-4813-9639-2d4ab31e37b9");
    i.putExtra("com.symbol.datawedge.api.GET_CONFIG", "Profile0 (default)");
    this.sendBroadcast(i);

例 2: DataWedge の有効化/無効化

    Intent i = new Intent();
    i.setAction("com.symbol.datawedge.api.ACTION");
    i.setPackage("com.symbol.datawedge");
    i.putExtra("APPLICATION_PACKAGE", getPackageName());
    i.putExtra("TOKEN", "<token here>"););
    i.putExtra("SEND_RESULT","LAST_RESULT");
    i.putExtra("com.symbol.datawedge.api.ENABLE_DATAWEDGE", true);
    sendBroadcast(i);

例 3: 構成の設定

    Bundle bMain = new Bundle();
    bMain.putString("PROFILE_NAME", "Profile009");
    bMain.putString("PROFILE_ENABLED", "true");
    bMain.putString("CONFIG_MODE", "CREATE_IF_NOT_EXIST");

    Bundle bConfig = new Bundle();
    bConfig.putString("PLUGIN_NAME","BARCODE");
    bConfig.putString("RESET_CONFIG","true");


    Bundle paramList = new Bundle();
    paramList.putString("scanner_selection","auto");
    paramList.putString("decoder_code11", "true");

    bConfig.putBundle("PARAM_LIST", paramList);

    bMain.putBundle("PLUGIN_CONFIG", bConfig);

    Intent i = new Intent();
    i.setAction("com.symbol.datawedge.api.ACTION");
    i.setPackage("com.symbol.datawedge");
    i.putExtra("APPLICATION_PACKAGE", getPackageName());
    i.putExtra("TOKEN", "<token here>"););
    i.putExtra("com.symbol.datawedge.api.SET_CONFIG", bMain);
    i.putExtra("SEND_RESULT","LAST_RESULT");
    i.putExtra("COMMAND_IDENTIFIER", "SET_CONFIG");
    this.sendBroadcast(i);

使用上の注意

  • DataWedge API が「制御」に設定されており、デバイスが再起動したときに、ホワイトリストに登録されたアプリケーションから「制御」グループにインテント API を送信すると、エラーが返される場合があります。MX フレームワークが初期化を完了しなかったため、リブート完了後しばらく待ってからインテントを送信して、このエラーを回避してください。
  • トークンは、以下の状況で期限切れになります。
    • デバイスの日付または時刻が、トークンのタイムスタンプより前に設定されている。
    • トークンを生成してからデバイスのクロックで 24 時間が経過した。
    • 自動時刻更新により、デバイスの時刻が戻ったか、24 時間を超えて進んだ。
  • インテント API が保護モードになっている場合、DataWedge を使用する既存の Zebra アプリが期待どおりに機能しないことがあります。たとえば、ランタイム API が保護モードになっている場合、エンタープライズ キーボード バージョン 4.0 以前ではエンタープライズ キーボードのスキャン ボタンは機能しません。

関連ガイド: