CLR 開発者向けサンプル フォームのセキュリティ機能
Microsoft Office InfoPath 2003 SDK |
CLR 開発者向けサンプル フォームのセキュリティ機能
CLR 開発者向けサンプル フォームは、次のような処理を行うセキュリティ機能を提供するために、各種の COM (Component Object Model) インターフェイスへの参照を取得しています。
- サンプル フォームの URL フィールドでユーザーが指定した .xml ファイルに対するアクセス許可をチェックします。
- Web での初期化やスクリプトの実行、およびサンプル フォームでのアクセスに備えて、CLRSample オブジェクトの安全を確保しやすくします。
CLR 開発者向けサンプル フォームのコードでは、次に示す目的を果たすために、次の COM インターフェイスへの参照を取得します。
COM インターフェイス | 目的 |
---|---|
IObjectSafety | スクリプトの実行に備えて CLRSample オブジェクトの安全を確保します。 |
IObjectWithSite | CLRSample オブジェクトとそのコンテナ間の連携をサポートします。 |
IServiceProvider | 他のオブジェクトにカスタム サポートを提供するオブジェクトを取り出すしくみを定義します。 |
IInternetHostSecurityManager | セキュリティ アクセス許可をチェックします。 |
IInternetSecurity Manager | セキュリティ アクセス許可をチェックします。 |
ICLRSample | CLRSample オブジェクトを定義します。 |
.xml ファイルに対するアクセス許可のチェック
CLRSample クラスの LoadData プライベート メンバ関数によって、サンプル フォームの URL フィールドで指定した .xml ファイルをダウンロードするアクセス許可をユーザーが所有しているかどうかを判断します。ユーザーがフォームで [Get Data] をクリックすると、フォームのコードの OnClick イベント ハンドラによって CLRSample オブジェクトのインスタンスが作成され、パブリック GetText メンバ関数が呼び出されます。次に、この関数によってプライベート LoadData 関数が呼び出されます。
この LoadData 関数によって、指定ファイルをダウンロードする前に一連のセキュリティ チェックが行われます。まず、IInternetHostSecurityManager インターフェイスの GetSecurityId メソッドを使用して、呼び出し側プログラムのドメインのセキュリティ ID が取得されます。次に、IInternetHostSecurityManager インターフェイスの同じメソッドを使用して、このファイルのドメインの ID が取得されます。その後、CLR 開発者向けサンプル フォームでは、セキュリティ チェックだけの目的で、これらのインターフェイスへの参照が取得されます。
2 つの ID を比較するため、LoadData 関数によって ID が 1 組の配列に格納され、同じ長さかどうかがチェックされます。同じ長さの場合は、簡単なループ処理によってバイト単位で比較されます。2 つの ID が同一である場合、ドメインは同一なので、ダウンロードが許可されます。
2 つの ID が同一でない場合でも、2 つのドメイン間でクロス ドメイン アクセスが許可される可能性があります。それを判断するため、LoadData 関数によって、IInternetHostSecurityManager インターフェイスの ProcessUrlAction メソッドに URLACTION_CROSS_DATA_DOMAIN フラグが渡されます。このフラグを渡すと、複数ドメインのデータ ソースへのアクセスをリソースに許可するかどうかを判断するよう指示することになります。ProcessUrlAction メソッドによって、サイレント アクセスが許可されることを表す URL アクション ポリシー フラグ URLPOLICY_ALLOW が返された場合は、LoadData 関数によって fAllowDownload フラグが true に設定され、ダウンロードが行われます。このフラグが返されない場合は、未承認アクセス例外がスローされます。プライベート LoadData メンバ関数の実装を次に示します。
private object LoadData(string sDataURL)
{
bool fAllowDownload = false; // by default, assume the download is not permitted
byte[] pbSecId;
uint cbSecId;
byte[] pbUrlSecId;
uint cbUrlSecId;
System.UInt32 dwPolicy = URLPOLICY_DISALLOW;
// Get security Id for caller.
pbSecId = new byte[MAX_SIZE_SECURITY_ID];
cbSecId = (uint)pbSecId.Length;
m_oInternetHostSecurityManager.GetSecurityId(pbSecId, ref cbSecId, 0);
// Get security Id for URL resource.
pbUrlSecId = new byte[MAX_SIZE_SECURITY_ID];
cbUrlSecId = (uint)pbUrlSecId.Length;
m_oInternetSecurityManager.GetSecurityId(sDataURL, pbUrlSecId, ref cbUrlSecId, 0);
// Compare the two security ids; allow the download if the contents are identical
// because that indicates that the callee the resource being downloaded are from
// the same domain.
// Start by simply checking that both byte arrays are the same length.
if (cbSecId == cbUrlSecId)
{
// Loop through the Security Id arrays and ensure each byte is identical.
// Break out of the loop if a difference is found.
uint cbIndex = 0;
for ( ; cbIndex<cbSecId && cbIndex<MAX_SIZE_SECURITY_ID; cbIndex++)
{
if (pbSecId[cbIndex] != pbUrlSecId[cbIndex])
break;
}
// If the loop completed normally then we must have found each byte to be the same.
if (cbIndex == cbSecId)
fAllowDownload = true;
}
// Determine whether the current security policy allows cross-domain access.
if (fAllowDownload == false)
{
m_oInternetHostSecurityManager.ProcessUrlAction(
URLACTION_CROSS_DOMAIN_DATA,
ref dwPolicy,
(uint)Marshal.SizeOf(dwPolicy),
0,
0,
PUAF_NOUI,
0);
if (dwPolicy == URLPOLICY_ALLOW)
fAllowDownload = true;
}
if (fAllowDownload)
{
// Create the XmlDocument and load the XML data.
m_domExternalData = new XmlDocument();
m_domExternalData.Load(sDataURL);
}
else
{
m_domExternalData = null;
throw new UnauthorizedAccessException();
}
return m_domExternalData;
}
IObjectWithSite COM インターフェイスでは、COM オブジェクトとそれをインスタンス化したホスト コンテナにあるサイト オブジェクト間の通信が可能になります。CLR 開発者向けサンプル フォームのコードには、IObjectWithSite インターフェイスの 2 つのメソッド、つまり SetSite と GetSite が実装されています。CLRSample オブジェクトによってこれらのメソッドを使用して、IServiceProvider インターフェイスへの参照の取得と解放を行い、このインターフェイスによって、ユーザーのアクセス許可チェックに使用する IInternetSecurityManager および IInternetHostSecurityManager インターフェイスをサポートします。このインターフェイスの詳細については、Microsoft Developer Network (MSDN) にある Microsoft Platform Software Development Kit で "IObjectWithSite" を検索してください。
IObjectWithSite インターフェイス メソッドの実装を次に示します。
public void SetSite(Object pUnkSite)
{
IServiceProvider oSP;
object ppvInternetHostSecurityManager;
object ppvInternetSecurityManager;
// AddRef the new site.
if (pUnkSite != null)
Marshal.AddRef(Marshal.GetIUnknownForObject(pUnkSite));
// Release the existing site if there is one and set the new site.
if (m_pUnkSite != null)
Marshal.Release(Marshal.GetIUnknownForObject(m_pUnkSite));
m_pUnkSite = pUnkSite;
// Call QueryInterface on the site for IServiceProvider.
oSP = (IServiceProvider)pUnkSite;
// Get IInternetSecurityManager interface from site.
Guid SID_SInternetSecurityManager = new Guid("79eac9ee-baf9-11ce-8c82-00aa004ba90b");
Guid IID_IInternetSecurityManager = new Guid("79eac9ee-baf9-11ce-8c82-00aa004ba90b");
oSP.QueryService(ref SID_SInternetSecurityManager, ref IID_IInternetSecurityManager, out ppvInternetSecurityManager);
m_oInternetSecurityManager = (IInternetSecurityManager)ppvInternetSecurityManager;
// Get IInternetHostSecurityManager interface from site.
Guid SID_SInternetHostSecurityManager = new Guid("3af280b6-cb3f-11d0-891e-00c04fb6bfc4");
Guid IID_IInternetHostSecurityManager = new Guid("3af280b6-cb3f-11d0-891e-00c04fb6bfc4");
oSP.QueryService(ref SID_SInternetHostSecurityManager, ref IID_IInternetHostSecurityManager, out ppvInternetHostSecurityManager);
m_oInternetHostSecurityManager = (IInternetHostSecurityManager)ppvInternetHostSecurityManager;
}
public void GetSite(ref Guid iid, out IntPtr ppvSite)
{
if (m_pUnkSite != null)
{
// AddRef and return the site.
Marshal.QueryInterface(Marshal.GetIUnknownForObject(m_pUnkSite), ref iid, out ppvSite);
Marshal.AddRef(ppvSite);
}
else
{
// Return E_FAIL if site is not set.
throw new COMException();
}
}
}
Web でのスクリプト実行に備えた CLRSample** オブジェクトの安全確保**
Web でのスクリプトの実行や、CLR 開発者向けサンプル フォームでのアクセスに備えて CLRSample オブジェクトの安全を確保しやすくするため、このオブジェクトには IObjectSafety COM インターフェイスのメソッドが実装されています。InfoPath フォームでは、スクリプトの実行に対して安全であることが明確ではないソフトウェア コンポーネントの使用が既定で制限されています。スクリプトの実行に対して安全であることが明確ではないコンポーネントにフォームからアクセスしようとすると、ユーザーにセキュリティ警告メッセージが表示されますこのサンプル フォームで採用している方法の代わりに、このサンプル フォームを "完全信頼済み" にすることもできます。完全信頼済みフォームの詳細については、「完全信頼済みフォームの詳細情報」を参照してください。
サンプル フォームのコードの GetDataFromDocLogic 関数によって CLRSample オブジェクトがインスタンス化されると、オブジェクトのコンストラクタによってこのクラスのメンバ変数 m_uintSupportedSafety が設定され、オブジェクトの安全変数が初期化されます。この場合、信頼できないデータと信頼できない呼び出し側の両方に対してこのインターフェイスは安全です。
public CLRSample()
{
m_uintSupportedSafety = INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACESAFE_FOR_UNTRUSTED_CALLER;
}
CLRSample オブジェクトがインスタンス化される前に、Microsoft JScript ホスト コンテナによって IObjectSafety COM インターフェイスの GetInterfaceSafetyOptions メソッドが呼び出されます。コンストラクタが設定した値をこのメソッドが返すことで、ユーザーにセキュリティ警告を表示せずにオブジェクトの作成をビジネス ロジック コードに許可します。
IObjectSafety インターフェイス メソッドの実装を次に示します。
public void GetInterfaceSafetyOptions(ref Guid iid, out uint optionsSupported, out uint optionsEnabled)
{
// return current safety settings
optionsSupported = m_uintSupportedSafety;
optionsEnabled = m_uintSupportedSafety;
}
public void SetInterfaceSafetyOptions(ref Guid iid, uint optionsSetMask, uint optionsEnabled)
{
// If we are asked to set options we don't support then fail.
if ((optionsSetMask & m_uintSupportedSafety) != optionsSetMask)
throw new Exception();
// Set the safety options we have been asked to.
m_uintCurrentSafety = (m_uintCurrentSafety & ~optionsSetMask) | (optionsSetMask & optionsEnabled);
}