REACH APIを使用すると、TeamViewerはRMMまたはMDMソリューションに統合するためのAPIを提供します。これにより、無人アクセスおよび遠隔のリモートコントロールセッションの開始が可能になります。
この記事ではREACH APIの背後にある基本的な概念を説明し、APIを管理ソリューションに統合するためのご案内致します。
さらに各トピックに分け、情報の詳細を提供できるよう構成されています。 最初の章では、基本的なアプローチについて説明し、特定のセキュリティー・メカニズムが適用された理由を概説します。 次に、TeamViewerによって開発されたVendorExampleAppとも呼ばれる例示的な統合のソースコードの例に基に説明します。
最後の章では、Androidに統合を実装するための詳細について概説します。
統合機能は、基本ライセンスパッケージには含まれませんのでご注意ください。AddOnsとして別途購入する必要があります。詳細については、当社のウェブサイトをご覧ください: http://www.teamviewer.com/ja/integrations
_____
📌注意: この記事のすべてのコード例は、MTIライセンスを用いて表示します。
Copyright(c)2018 TeamViewer GmbH
本ソフトウェアおよび関連するドキュメンテーションファイル(以下「本ソフトウェア」といいます)のコピーを取得すると、本ソフトウェアを制限なく使用、複製、改変、マージする権利が得られ、、本ソフトウェアのコピーを発行、配布、サブライセンス許諾、および/または販売すること、および本ソフトウェアが提供されている人に、以下の条件に従うことを許可します。
上記の著作権表示およびこの許可通知は、本ソフトウェアのすべてのコピーまたは実質的な部分に含まれるものとします。
「本ソフトウェアは、商品性、特定の目的への適合性および侵害の保証を含むが、明示的にも黙示的にも、いかなる種類の保証もなく、現状のまま提供されます。作者または著作権者は、本ソフトウェアまたはその使用に関連して発生したり、その使用に起因するなどの、いかなる場合において、ソフトウェアに関する契約違反、その他の損害賠償その他の損害賠償の責任は負わないものとします。」
ソフトウェアを再使用または再配布する場合は、該当する場合は、付属のソフトウェアのライセンスを第三者から尊重してください。
_____
最終的にREACH APIの背後にある概念は、3つのユースケースに分かれます。
ロールアウトは、デバイスと管理ソリューションの間で暗号化キーを交換するために使用されます。これらの暗号化キーは、制御フェーズと登録解除フェーズで使用され、デバイスとのすべての通信が安全であることを保証します。
以下の図は、登録フローを示しています。
管理ソリューションエージェント(MSA)は、デバイス上で実行する必要があるコンポーネントです。このエージェントは、ロールアウトフェーズを正常に完了するために必要なデータを取得するため、デバイスの管理者権限を持っていている必要があります。
ロールアウトを開始するために、MSAは、TeamViewerクライアントの起動時およびこのTeamViewerクライアントへの成功および失敗したロールアウト要求のたびに書き込まれる特別なファイル(ステップ1)を読み取ります。
📌注意: ステップ1は、プラットフォームごとに異なる場合があります。ファイルアプローチは、WindowsおよびmacOSプラットフォームにのみ適用されます。ただし、ロールアウトに提供されるデータはすべてのプラットフォームで同じです。 Androidの詳細については、Androidの章を参照してください。
このファイルには、グローバル一意識別子(GUID)とデバイスのRemotecontrolID(TeamViewer ID)の両方を含むRolloutKey(ROKは1つの要求に対して有効で、API応答の復号化に使用されます)が含まれています。
ロールアウトデータ、許可設定一式とともにRemotecontrol IDとGUIDを使用して、API呼び出し(POST / oem / devices / createdevicekey)を作成して新しいデバイスキーを作成します(手順3)。
このAPIコールは、TeamViewerバックエンドからターゲットTeamViewerクライアントへの通信を開始しています。
データが有効な場合、TeamViewerクライアントは将来のリモートコントロールセッション用の鍵ペアを作成しています。
TeamViewerクライアントは、新しく作成されたキーペアの秘密鍵(= DeviceKey)をRolloutKeyで暗号化し、このKeyペアの識別子とともに、APIコールへの応答として廃止トークンを送信し、TeamViewer バックエンドを通過しますステップ4)。
管理ソリューションは、以前取得したRolloutKeyを使用してDeviceKeyを復号化する必要があります。解読プロセスを簡略化するために、DeviceKeyは標準のPEMフォーマットを使用して暗号化されています。
DeviceKeyとDeviceKeyIDは制御フェーズで使用され、Decommission token(廃棄トークン)はDeviceKeyの登録を解除するために必要です。
📌注意: 復号化されたDeviceKey、DeviceKeyIDおよび廃止トークンは、管理ソリューション側で安全な方法で保存する必要があります。
最初のステップを完了すると、今から登録デバイスへのリモートコントロールセッションを開始することができます。リモートコントロールセッションを開始するには、以下のプロセスが適用されます。
リモートコントロールは、DeviceKeyとDeviceKeyIDがリモートコントロールセッションを開始するために必要とされるため、デバイスの登録が成功した後にのみ可能です。
最初のステップは、RemotecontrolID、DeviceKeyID、およびcontrole typeのパラメータを持つWebAPI呼び出し(POST / oem / devices / requestcontrol)です。これらのパラメータは、DeviceKeyがAPI呼び出し内で要求されたコントロールパーミッションを持っているかどうかを確認された後、対象のクライアントに渡されます。
要求の認証が成功した後、対象のTeamViewerクライアントは、セッションパスワードと同様の1回限り使用出来るsecret(ハッシュメソッド認証メッセージ、HMAC)を生成します。
HMACは、制御要求を介して受信したデータとTeamViewerクライアントによって生成された他のデータ(Target Nonce、DeviceSecret)に基づいて計算されます。
HMACを計算した後、クライアントは、DeviceKeyIDを介してAPIコールで指定されたDeviceKeyでDeviceSecretを暗号化します。
DeviceSecretは、ターゲットコールと、プレースホルダYOURMASTERSECRETを含むTeamViewer プロトコルURL( "teamviewerapi://")のURLテンプレートとともに、APIコール応答パラメータEncryptedDeviceSecretとして返されます。
ISVの実装では、DeviceKeyを使用してEncryptedDeviceSecretを復号化し、復号化されたデバイスシークレット、ターゲットナンス、および要求制御APIコールで送信されたその他の情報に基づいてHMACを計算する必要があります。
HMACを計算したら、有効なTeamViewerプロトコルURLを作成するために、プレースホルダYOURMASTERSECRETをHMACに置き換える必要があります。
接続を開始するには、HMACを含む完全なURLを発信元TeamViewerクライアントに提示する必要があります。
これは、ブラウザまたはコマンドラインパラメータ(TeamViewerがインストールされ、TeamViewer アプリケーションに関連付けられている場合、TeamViewer procotolはオペレーティングシステムに登録されています)として発生します。
ソースTeamViewerクライアントは、現在、ターゲットクライアントへの接続を確立するためにHMACを含むURLの情報を使用するようになります。
DeviceKeyがまったく使用されない場合は、DeviceKeyの登録を解除することができます。この図は、基本原則を示しています。
DeviceKeyの登録を解除するには、WebAPI呼び出しDELETE / oem / devices / unregisterが使用されます。
正常に実行されるためには、正しいキー、デバイスのRemotecontrolID、およびロールアウトフェーズ中にPOST / oem / devices / createdevicekey APIコール応答で発行されたdecommsion tokenを識別するためのDeviceKeyIDが必要です。
この情報は、デバイス上のTeamViewerクライアントによって処理されます。
APIの情報がクライアントの情報と一致する場合、ロールアウトフェーズで作成されたキーペアのローカル部分が削除され、WbeAPIを通じて確認が返されます。
この処理の完了後は、このDeviceKeyを使用して、それ以上リモートコントロールセッションを確立することはできません。
このガイドに従って実際に統合を実行するには、統合のさまざまなフェーズにていくつかの情報が必要となります。
ベンダーIDは、ISVのTeamViewer担当者によって提供されています。
テナント管理権限を持つベンダーアカウントのスクリプトトークンを使用して、テナントアカウントを作成することができます。
たとえば、Postmanのようなツールを使ってWebAPI呼び出しを発行することができます。
最後に、デバイスキーを作成し、制御を要求し、デバイスキーを削除する権限を持つテナントアカウントのスクリプトトークンが必要です。
💡ヒント: スクリプトトークンの作成方法については、こちらをご覧くださいませ。
統合の例として、提供されるコード例では次のテクノロジとライブラリを使用します。
Androidの場合、次の情報がさらに必要です。
AppKeyは、Androidデバイス上のMSAの署名であり、AppKeyIDは、アカウントIDとともにインデックスとして使用されます。両方の値は、WebコンソールにAppKeyを登録するためのWebAPIの応答と共に戻ってきます。
💡ヒント: 説明の間に使用されるすべての値は、具体的な値に置き換えり必要があります。
次の図は、ベンダー側の部品の概要を簡単に示しています。ここでは、統合が行われる必要があります。
API呼び出しは、任意のHTTPクライアントクラスで実行できます。
このWebAPIコールの事前条件は、TeamViewerクライアントによって書き込まれたロールアウトファイルから情報を読み取ることです。
このファイルは、Windowsおよび管理者権限を持つmacOsプラットフォームで読み取ることができます。
Android搭載端末では、公開データにアクセスする前に、MSAアプリの登録が必要です。これは、以下のAndroid統合の章で個別に説明されています。
ここの例では、VendorExampleAppで提供されているコードをソースコードで参照しています。まず、JSON本体を作成する必要があります。これは、例えば、次のようなデータクラスの作成のようなデータクラスを使用して行うことができます。
RemotecontrolIDとRequestIDの情報は、ロールアウトファイルに由来することを注意してください。
request bodyの作成
var createDeviceKeyRequest = new CreateDeviceKeyRequest { key_permissions = "unattended", remotecontrol_id = "r124124124", request_id = "{8c4fa1a7-9d1c-41e9-be17-70e95c289080}", tenant_id = "t0001" };
そのデータクラスを作成して情報で埋めて、URLとメソッドを指定し、HTTP要求ヘッダーに必要な認証情報を入力してから、上記の直列化データクラスを含むJSON本体を追加することで、WepAPI呼び出しを発行できます。
HTTPヘッダーに権限を追加するには、TeamViewer (Classic) Management Consoleを使用してアプリケーションスクリプトトークンを作成する必要があります。
このスクリプトトークンがWebAPI呼び出しを実行するための正しい権限を持っていることを確認する必要があります。
これらのアクセス許可は、スクリプトトークンを所有するアカウントがテナントである場合にのみ、そのスクリプトトークンに対して許可することができます。
応答を解析し、応答値を含む非直列化データ・クラスを戻すコールを発行する次のボックスのコード例を参照してください。このサンプルコードは、ベンダーのアプリケーションから取得したものです。
DeviceSecretKeyのリクエスト
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(apiUrl + "/api/v1/oem/devices/createdevicekey"); webReq.Method = "POST"; webReq.ContentType = "application/json"; webReq.Headers.Add("Authorization", "Bearer "+accessToken); using (var streamWriter = new StreamWriter(webReq.GetRequestStream())) { var createSecretKeyRequestJson = JsonConvert.SerializeObject(createDeivceKeyRequest); streamWriter.Write(createDeviceKeyRequestJson); streamWriter.Flush(); streamWriter.Close(); } var httpResponse = (HttpWebResponse) await webReq.GetResponseAsync(); if (httpResponse == null) { throw new InvalidDataException("No response received"); } var responseStream = httpResponse.GetResponseStream(); if (responseStream == null) { throw new InvalidDataException("No response stream received."); } using (var streamReader = new StreamReader(responseStream)) { var result = streamReader.ReadToEnd(); return JsonConvert.DeserializeObject<CreateDeviceKeyResponse>(result);
APIレスポンスでは、暗号化されたDeviceKeyを所有しています。
PEM形式の暗号化されたDeviceKeyを復号するために、ここではBouncyCastleをライブラリとして選択しました。
Java用のBouncyCastleも利用できます。しかし、すべての言語がPEMファイルを扱うためのライブラリがあるはずです。
暗号化アルゴリズムは、APIリクエストから取得したPEMファイルに直接記述されています。
例:
"-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,309AA16\n-----END RSA PRIVATE KEY-----\n"
セキュリティ上の理由により、ライブラリを使用して作業を処理することを強くお勧めします。ライブラリには正しいアルゴリズムが自動的に識別されるためです。
アルゴリズム自体にセキュリティ上の問題がある場合は、それを変更することができます。
適切なライブラリが使用されている場合は、ISV側で変更する必要はありませんが、手動による実装はそれほど柔軟性がありません。
Bouncy Castleを使用すると、PEMキーの解読は次の例のようにコード化されます。
より簡単にするため、BouncyCastleライブラリで処理をし、文字列として格納できるので、deviceKeyは解読されたPEM形式の文字列として格納します。
PEMキーの解読
TextReader textReader = new StringReader(encryptedDeviceKey); PemReader pemReader = new PemReader(textReader, new PasswordFinder(password)); object deviceKeyObject = pemReader.ReadObject(); AsymmetricCipherKeyPair rsaPrivatekey = (AsymmetricCipherKeyPair)deviceKeyObject; TextWriter tw = new StringWriter(); var pemWriter = new PemWriter(tw); pemWriter.WriteObject(rsaPrivatekey.Private); pemWriter.Writer.Flush(); string deviceKey = tw.ToString(); return deviceKey;
この手順を実行すると、WebAPI呼び出しの応答で返されたDeviceKeyIDとRemotecontrolIDとともに、管理ソリューションのコンテキストでDeviceKeyを格納することが重要です。
さらに、最終的にDeviceKeyの登録を解除する必要があるdecommsion tokenを保持する必要もあります。
前のフェーズのデータであるDeviceKeyとDeviceKeyIDにより、登録されたデバイスに対してリモートコントロールセッションを確立できます。
リモートコントロールの要求時に、ロールアウトフェーズで権限を要求したものと同じコントロールタイプを使用することが重要です。
この場合も、最初にデータクラスインスタンスがWebAPI呼び出しに必要な情報で埋められます。
要求制御データクラス
var requestControlRequest = new RequestControlRequest() { control_type = "attended", device_key_id = "{114fa1a7-abab-41e9-be17-70e95c289080}", remotecontrol_id = "r124124124", tenant_id = "t0001", tenant_nonce = "243dd78d07324ab7befa41390d08d35f" };
このデータインスタンスを使用すると、次のC#コードのようにWebAPI呼び出しを発行できます。
再度URLが追加され、次にHTTP authorization-headerにスクリプトトークンが追加され、最後にシリアル化されたデータクラスインスタンスがJSON本体として追加されます。
要求が応答と共に返されると、データは、TeamViewerリンク用のテンプレートを提供する独自のデータクラスインスタンスに逆シリアル化できます。
このリンクは、ハッシュメソッド認証メッセージ(HMAC)で完了します。
リモートコントロールの呼び出し
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(apiUrl + "/api/v1/oem/devices/requestcontrol"); webReq.Method = "POST"; webReq.ContentType = "application/json"; webReq.Headers.Add("Authorization", "Bearer " + accessToken); using (var streamWriter = new StreamWriter(webReq.GetRequestStream())) { var requestControlRequestJson = JsonConvert.SerializeObject(requestControlRequest); streamWriter.Write(requestControlRequestJson); streamWriter.Flush(); streamWriter.Close(); } var httpResponse = (HttpWebResponse)(await webReq.GetResponseAsync()); if (httpResponse == null) { throw new InvalidDataException("No response received"); } var responseStream = httpResponse.GetResponseStream(); if (responseStream == null) { throw new InvalidDataException("No response stream received."); } using (var streamReader = new StreamReader(responseStream)) { var result = streamReader.ReadToEnd(); return JsonConvert.DeserializeObject<RequestControlResponse>(result);
API応答はリンクテンプレートのみを返すので、リンクはHMACで完了する必要があります。
HMACを作成するsecretはAPIレスポンスで暗号化されて返されるため、最初のステップではsecretを復号化します。
解読のキーは、展開フェーズ中にAPI応答で受信されたDeviceKeyです。
DeviceKeyがPEM形式の文字列として格納されるとき、コードの最初の部分はこの文字列をBouncyCastle( "AsymmetricCipherKeyPair"型変数)に適した構造に変換します。
PreMasterSecretの復号化
using (var reader = new StringReader(DeviceKey)) { //Convert to right format var bytesToDecrypt = encryptedDeviceSecret.FromBase64SafeUrl(); //--------DECRYPT WITH PEM DEVICE KEY-------------// AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair) new PemReader(reader).ReadObject(); var decryptEngine = new OaepEncoding(new RsaEngine()); decryptEngine.Init(false, keyPair.Private); var decryptedDeviceSecret = decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length); }
解読されたDeviceSecret、TenantID、ターゲットのRemotecontrolID、ターゲットおよびテナントナンスを使用して、セキュリティライブラリBouncyCastleを使用して実装される次の例のようにHMACを作成できます。
Mastersecretの生成
//---------HMAC Values to be hashed, recombined in a string ------------// var hashVerifier = $"{tenantNonce}{targetNonce}{tenantId.Substring(1)}{remotecontrolId.Substring(1)}"; HMACSHA512 hmacsha512 = new HMACSHA512(decryptedDeviceSecret); byte[] hashmessage = hmacsha512.ComputeHash(Encoding.UTF8.GetBytes(hashVerifier)); var masterSecret = hashmessage.ToBase64SafeUrl();
結果は文字列YOURMASTERSECRETの代わりにTeamViewerリンクテンプレートに入れられます。
完了した文字列を使用すると、TeamViewer エンタープライズクライアントがインストールされているシステムのインターネットブラウザでリンクを開くか、このリンクをTeamViewer.exeの呼び出しのコマンドラインに渡すことでリモートコントロールセッションを確立できます。
登録解除デバイス呼び出しには、登録解除を正常に実行するために次のパラメータが必要です。
前のフェーズと同様に、この特定の呼び出しのデータクラスインスタンスを作成し、WebAPIへの今後の呼び出しの具体的なデータで埋めなければなりません。
データ構造の作成
var unregisterDeviceRequest = new UnregisterDeviceRequest { tenant_id = "t0001", remotecontrol_id = "r124124124", device_key_id = "{114fa1a7-abab-41e9-be17-70e95c289080}", decommission_token = _mState.LastDecommissionToken };
WebAPI呼び出しURLを追加し、メソッド、アプリケーションスクリプトトークンをHTTP認証ヘッダーに追加し、最終的に以前に作成したデータクラスのシリアル化されたコンテンツをJSON形式で追加します。
登録の解除
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(apiUrl + "/api/v1/oem/devices"); webReq.Method = "DELETE"; webReq.ContentType = "application/json"; webReq.Headers.Add("Authorization", "Bearer " + accessToken); using (var streamWriter = new StreamWriter(webReq.GetRequestStream())) { var unregisterDeviceRequestJson = JsonConvert.SerializeObject(unregisterDeviceRequest); streamWriter.Write(unregisterDeviceRequestJson); streamWriter.Flush(); streamWriter.Close(); } var httpResponse = (HttpWebResponse)await webReq.GetResponseAsync(); if (httpResponse == null) { throw new InvalidDataException("No response received"); } var responseStream = httpResponse.GetResponseStream(); if (responseStream == null) { throw new InvalidDataException("No response stream received."); } using (var streamReader = new StreamReader(responseStream)) { var result = streamReader.ReadToEnd(); return;
この場合、返される結果にはデータは含まれません。
操作の成功は、204でなければならない戻り値(HTTPの共通戻り値も参照)をチェックすることによってのみ認証できます。
Android(適切な管理特権の分離がない)のプラットフォームの制限により、展開は他のプラットフォームと異なります。 MSAの認証は、TeamViewer Androidアプリと通信する前に実行する必要があり、RolloutKeyは別の方法で取得されます。
MSAのSignature Key(ここからAppKeyと呼ばれる)のSHA-256ハッシュは、WebAPIコールPOST "/ oem / appregistrations"を使用して16進文字列としてTeamViewerに登録する必要があります。
この登録ステップは、AppKeyごとに1回だけ必要であり、PostmanのようなRESTクライアントで行うことができます。
TeamViewerアプリケーションとMSAとの間の通信は、REACH登録時に受け取ったAIDLファイルに記載されているように、ネイティブAndroid Binderインターフェイスを使用します。https://developer.android.com/reference/android/os/Binder.html
他の呼び出しの前に、verifyメソッドを呼び出す必要があります。 verifyメソッドには、MSA AppKeyの登録に使用されたアカウントのAccountIDと、登録時に返されたKeyIDが必要です。認証が成功した場合は、Binderサービスのメソッドを呼び出すことをお勧めします。以上を行わないと、SecurityExceptionがスローされます。
アプリの登録を除いてAndroidの主な違いは、RolloutKeyの取得方法です。ロールアウトデータを含むファイルは、TeamViewerアプリのプライベートアプリケーションストレージに書き込まれます。この情報はTeamViewerアプリケーションでのみ読み取ることができます。そのため、MSAアプリはBinderインターフェイス経由で展開データを要求する必要があります。BinderインタフェースでrequestPreKeyDataメソッドを使用してロールアウトデータを正常に取得したら、REACH APIのデバイスのロールアウトの章で説明したのと同じ方法で処理を進めることができます。