通过工作流程提供新网站集的权限

问题描述:

我陷入了一个非常奇怪的境地。通过工作流程提供新网站集的权限

我有一个工作流程,我用它在我的web应用程序上提供新的站点。此工作流程使用一个自定义工作流程活动来使用后续声明来配置站点。

---其他代码被遗漏的清晰----

SPSiteCollection.Add()

本声明抛出异常followign当我的应用程序了池帐户不一样的*管理应用程序了池帐户。

访问被拒绝。 (从HRESULT异常:0X80070005(E_ACCESSDENIED)) 在 Microsoft.SharePoint.SPGlobal.HandleUnauthorizedAccessException(UnauthorizedAccessException EX)在 Microsoft.SharePoint.Library.SPRequest.CreateSite(GUID gApplicationId,字符串bstrUrl,的Int32 lZone,的Guid gSiteId ,的Guid gDatabaseId, 字符串bstrDat

很多谷歌上搜索和发现我已经归零到应用程序了池帐户的权限之后。

工作流代码总是在牛逼运行他系统帐户(应用程序池标识)。为了创建新的SharePoint网站集,应用程序池需要访问“SharePoint_Config”数据库。

当我的Web应用程序在Central Admin的应用程序池凭证下运行时,它具有对配置数据库的所有访问权限。但是,当我运行在任何其他应用程序池权限较低的应用程序。它会抛出异常,即使我将DBO权限授予配置数据库中的应用程序池帐户。

我的应用程序了事件日志有以下条目: -

事件来源:的Windows SharePoint Services 3事件类别:数据库 事件ID:3760日期:2010年2月3日 时间:2:36: 16 AM用户:N/A 计算机:SHAREPOINT20描述: SQL数据库'SharePoint_Config' SQL Server实例'houspsr001'未找到 。来自SQL Server的其他错误信息 包含在下面。

无法打开数据库 登录请求的“SharePoint_Config”。登录失败。用户'DOMAIN \ WebAppPool'登录失败 。

欲了解更多信息,请参阅帮助和 支持中心在 http://go.microsoft.com/fwlink/events.asp

我的问题是......是否可以在*管理的应用程序池帐户下运行此类代码。

任何解决方法为此....?我的问题

最后,拒绝访问的问题已解决。正如我在以前的电子邮件中所示,这个问题是由于我的应用程序池标识权限不足。

  • *管理是根据不同的应用程序池标识
  • Web应用程序在不同的应用程序池标识运行运行。

我的工作流正在使用ElevatedPrevilages设置网站集,并且由于它没有修改SharePoint_Config数据库的权限,所以它从数据库中获取拒绝访问。

解决方案 为了解决此问题,我必须模拟*管理的应用程序池标识。以下是模拟*管理员应用程序池用户所需的方法。

#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(); 

作为即时通讯不允许的Sudhir的回答发表评论,张贴林的话我作为一个答案。我基本上使用了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); 

这种方式,密码是唯一的加密在我们用它来做用户登录之前。之后,明文密码立即从内存中释放。

+0

感谢您提高本答案彬福德,我相信它会帮助有需要的人:) – 2013-05-20 19:51:52