views:

252

answers:

1

I am stuck onto a very strange situation.

I have a workflow that i use to provision new site on my web application. This workflow uses one custom workflow activity to provision the site using followoing statement.

---other code omited for clarity----

SPSiteCollection.Add()

This statement is throwing followign exception when my applicaiton pool account is not same as Central Admin applicaiton pool account.

*Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) at Microsoft.SharePoint.SPGlobal.HandleUnauthorizedAccessException(UnauthorizedAccessException ex) at Microsoft.SharePoint.Library.SPRequest.CreateSite(Guid gApplicationId, String bstrUrl, Int32 lZone, Guid gSiteId, Guid gDatabaseId, String bstrDat*

after a lot of googling and findings i have zeroed down to the Applicaiton Pool account permission.

The workflow code always runs under the System account (the applicaiton pool identity). In order to create new SharePoint site collection, the application pool requires access to "SharePoint_Config" database.

When my web application is running under the applicaiton pool credential of Central Admin, it has all the access to the configuration database. But when i am running the under any other applicaiton pool identity which has less permission. it throws exception, even if i give DBO permission to the applicaiton pool account in the Configuration database.

My applicaiton event log has following entry :-

Event Source: Windows SharePoint Services 3 Event Category: Database Event ID: 3760 Date: 2/3/2010 Time: 2:36:16 AM User: N/A Computer: SHAREPOINT20 Description: SQL Database 'SharePoint_Config' on SQL Server instance 'houspsr001' not found. Additional error information from SQL Server is included below.

Cannot open database "SharePoint_Config" requested by the login. The login failed. Login failed for user 'DOMAIN\WebAppPool'.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

My question is...is it mendatory to run such code under the applicaiton pool account of central admin.

Any workaround for this....?

My question

A: 

Hi,

Finally the access denied issue has been resolved. As I motioned in my previous email, the issue was due to insufficient permission to my application pool identity.

  • Central Admin was running under a different application pool identity
  • Web applications are running under a different application pool identity.

My workflow was using the ElevatedPrevilages to provision a site collection, and it used to get Access Denied from the database since it did not had permission to modify SharePoint_Config database.

Resolution In order to resolve this issue i had to impersonate the application pool identity of Central Admin. Here is the required method for impersonating Central Admin application pool user.

   #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

And then my code to create site collection looks like:-

//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 Kesharwani