1

私は非常に奇妙な状況に陥っています。

Webアプリケーションで新しいサイトをプロビジョニングするために使用するワークフローがあります。このワークフローは、1つのカスタムワークフローアクティビティを使用して、次のステートメントを使用してサイトをプロビジョニングします。

---わかりやすくするために他のコードは省略されています----

SPSiteCollection.Add()

このステートメントは、アプリケーションプールアカウントがサーバーの全体管理アプリケーションプールアカウントと同じでない場合に、followign例外をスローします。

アクセスが拒否されました。(HRESULTからの例外:0x80070005(E_ACCESSDENIED))Microsoft.SharePoint.SPGlobal.HandleUnauthorizedAccessException(UnauthorizedAccessException ex)at Microsoft.SharePoint.Library.SPRequest.CreateSite(Guid gApplicationId、String bstrUrl、Int32 lZone、Guid gSiteId、Guid gDatabaseId、String bstrDat

たくさんのグーグルと発見の後、私はアプリケーションプールアカウントの許可にゼロを合わせました。

ワークフローコードは、常にシステムアカウント(アプリケーションプールID)で実行されます。新しいSharePointサイトコレクションを作成するには、アプリケーションプールで「SharePoint_Config」データベースにアクセスする必要があります。

私のWebアプリケーションがサーバーの全体管理のアプリケーションプールクレデンシャルで実行されている場合、そのアプリケーションは構成データベースへのすべてのアクセス権を持っています。しかし、私が他のアプリケーションプールIDの下で実行しているときは、権限が少なくなります。構成データベースのアプリケーションプールアカウントにDBO権限を付与しても、例外がスローされます。

私のアプリケーションイベントログには次のエントリがあります:-

イベントソース:Windows SharePoint Services 3イベントカテゴリ:データベースイベントID:3760日付:2010年2月3日時間:2:36:16 AMユーザー:N / Aコンピューター:SHAREPOINT20説明:SQLServerインスタンス上のSQLデータベース'SharePoint_Config' houspsr001'が見つかりません。SQLServerからの追加のエラー情報は以下に含まれています。

ログインで要求されたデータベース「SharePoint_Config」を開くことができません。ログインに失敗しました。ユーザー「DOMAIN\WebAppPool」のログインに失敗しました。

詳細については、ヘルプとサポートセンター( http://go.microsoft.com/fwlink/events.asp )を参照してください。

私の質問は...中央管理者のアプリケーションプールアカウントでそのようなコードを実行することが必須ですか?

これに対する回避策はありますか....?

私の質問

4

2 に答える 2

1

最後に、アクセス拒否の問題が解決されました。以前のメールで申し立てたように、この問題は、アプリケーションプールIDへのアクセス許可が不十分なことが原因でした。

  • サーバーの全体管理は、別のアプリケーションプールIDで実行されていました
  • Webアプリケーションは、異なるアプリケーションプールIDで実行されています。

私のワークフローはElevatedPrevilagesを使用してサイトコレクションをプロビジョニングしていましたが、SharePoint_Configデータベースを変更する権限がなかったため、データベースからAccessDeniedを取得していました。

解決策この問題を解決するには、サーバーの全体管理のアプリケーションプールIDを偽装する必要がありました。CentralAdminアプリケーションプールユーザーになりすますために必要な方法は次のとおりです。

   #region Application Pool Identity Impersonate

        protected static WindowsIdentity CreateIdentity(string User, string Domain, string Password)
        {
            // The Windows NT user token.
            IntPtr tokenHandle = new IntPtr(0);

            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int LOGON32_LOGON_NETWORK = 3;

            tokenHandle = IntPtr.Zero;

            // Call LogonUser to obtain a handle to an access token.
            int returnValue = LogonUser(User, Domain, Password,LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT,out tokenHandle);

            //Check if the logon user method succeeded
            if (returnValue <= 0)
            {
                int ret = Marshal.GetLastWin32Error();
                throw new Exception("LogonUser failed with error code: " + ret);
            }

            //System.Diagnostics.Debug.WriteLine("Created user token: " + tokenHandle);

            //The WindowsIdentity class makes a new copy of the token.
            //It also handles calling CloseHandle for the copy.
            WindowsIdentity id = new WindowsIdentity(tokenHandle);
            CloseHandle(tokenHandle);
            return id;
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern int LogonUser(
            string lpszUsername,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            out IntPtr phToken
            );
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern int ImpersonateLoggedOnUser(
            IntPtr hToken
        );

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern int RevertToSelf();

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern int CloseHandle(IntPtr hObject);

        #endregion

そして、サイトコレクションを作成するための私のコードは次のようになります:-

//Impersonate the logged in user, ApplicationUser, LoginDomain and Password are exposed as property of the class.

WindowsImpersonationContext wiContext = CreateIdentity(this.ApplicationPoolUser, this.LoginDomain, this.SystemPassword).Impersonate();



//Provision new site collection and update the property for new site collection url.

using (SPSite newSiteCollection = spSiteColl.Add(SUGGESTEDURL, TITLE, DESC, LCID, WEBTEMPLATE, PRIMARYOWNER.LoginName, PRIMARYOWNER.Name, PRIMARYOWNER.Email, SECONDARYOWNER.LoginName, SECONDARYOWNER.Name, SECONDARYOWNER.Email))

{

this.SUGGESTEDURL = newSiteCollection.Url;

}



//Reset the impersonation.

wiContext.Undo();
于 2010-02-09T13:48:18.723 に答える
1

ImはSudhirの回答にコメントすることを許可されていないので、Imは私のコメントを回答として投稿します。基本的に、Sudhirがソリューションとして提案しているのと同じコードを使用しました。なりすましは機能しますが、セキュリティ上の欠陥があります。パスワードをプレーンテキスト(管理対象)の文字列として保存すると、ページングのためにメモリ内に移動されたり、ハードディスクに保存されたりする場合があります。これにより、無力化された人があなたの資格情報を簡単にスパイできるようになります。

したがって、この目的にはSecureStringを使用することをお勧めします。これをSecureStringと組み合わせて使用​​する方法は、MSDNで調べることができます。Sudhirのソリューションとの主な違いは、LogonUserの別のオーバーロードを使用することです。

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool LogonUser(String username, String domain, 
                                      IntPtr password, int logonType, 
                                      int logonProvider, ref IntPtr token);

このように使用します(このコードはMSDNからのものです):

// Marshal the SecureString to unmanaged memory.
passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(pwdSecureString);

// Call LogonUser, passing the unmanaged (and decrypted) copy of
// the SecureString password.
returnValue = LogonUser(userName, domainName, passwordPtr,
                        LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, 
                        ref tokenHandle);

// Zero-out and free the unmanaged string reference.
Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr);

このように、パスワードは、ユーザーログインを行うために使用する直前にのみ暗号化されます。その後、プレーンテキストのパスワードはすぐにメモリから解放されます。

于 2010-12-20T14:34:18.100 に答える