Issue With Programmatically Impersonating a User in a Web-Part : Sharepoint
This is a discussion on Issue With Programmatically Impersonating a User in a Web-Part within the Sharepoint forums in Microsoft Tools category; I'm trying to impliment a web-part that will allow select users (ones that are added to a custom sharepoint list) to Add, Edit and Delete user accounts on a Server. The client isn't using active directory yet, so I'm simply creating local machine accounts. I thought I had everything up and running, if I hit the web-part logged in with administrator privelages, the impersonation works, Prints out the correct name BEFORE impersonation, AFTER impersonation, and then AFTER UNDOING impersonation. It also creates, edits or deletes the user account appropriately. However, if I'm not logged in as a user that has ...
| Sharepoint Microsoft sharepoint portal server development, administration and related discussions |
![]() |
| | LinkBack | Thread Tools |
|
#1
| |||
| |||
| that are added to a custom sharepoint list) to Add, Edit and Delete user accounts on a Server. The client isn't using active directory yet, so I'm simply creating local machine accounts. I thought I had everything up and running, if I hit the web-part logged in with administrator privelages, the impersonation works, Prints out the correct name BEFORE impersonation, AFTER impersonation, and then AFTER UNDOING impersonation. It also creates, edits or deletes the user account appropriately. However, if I'm not logged in as a user that has Administrator privelages, the impersonation fails (kinda the whole point for impersonation..). Any help would be MUCH appreciated. namespace UserAdministration { using System; using System.Configuration; using System.Data; using System.Drawing; using System.Web; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using System.DirectoryServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Security.Principal; using Microsoft.SharePoint; using Microsoft.SharePoint.WebControls; /// <summary> /// Summary description for AddUser. /// </summary> /// public class AddUser : System.Web.UI.UserControl { #region Declarations //Error Message Label protected System.Web.UI.WebControls.Label lblErrorMessage; //Text and Check Boxes protected System.Web.UI.WebControls.TextBox txtUserName; protected System.Web.UI.WebControls.TextBox txtFullName; protected System.Web.UI.WebControls.TextBox txtDescription; protected System.Web.UI.WebControls.TextBox txtPassword; protected System.Web.UI.WebControls.TextBox txtConfirmPassword; protected System.Web.UI.WebControls.CheckBox cbPasswordExpire; //Buttons protected System.Web.UI.WebControls.Button btnSave; //Variables private string currentUser; const int ADS_UF_DONT_EXPIRE_PASSWD = 0x10000; #endregion #region Page Load private void Page_Load(object sender, System.EventArgs e) { } #endregion #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Web Form Designer. // InitializeComponent(); base.OnInit(e); } /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.btnSave.Click += new System.EventHandler(this.btnSave_Click); this.Load += new System.EventHandler(this.Page_Load); } #endregion #region Classes #region Save Button Class private void btnSave_Click(object sender, System.EventArgs e) { if(authorizeUser() == true) { string strImpersonationUserName = ConfigurationSettings.AppSettings["ImpersonationUser"].ToString(); string strImpersonationDomain = ConfigurationSettings.AppSettings["ImpersonationDomain"].ToString(); string strImpersonationPassword = ConfigurationSettings.AppSettings["ImpersonationPassword"].ToString(); Response.Write("UserName: " + strImpersonationUserName + "<BR>Domain: " + strImpersonationDomain + "<BR>Password: " + strImpersonationPassword); if (ValidateFields()) { ImpersonateUser(strImpersonationUserName, strImpersonationDomain, strImpersonationPassword); } } else { lblErrorMessage.ForeColor = System.Drawing.Color.Red; lblErrorMessage.Text = "You do not have permission to manage user accounts"; } } #endregion #region Validate Fields Class /// <summary> /// Checks that all fields are valid and sets the error message or returns true. /// </summary> /// <returns>Boolean value determining whether the form is valid or not</returns> private bool ValidateFields() { bool returnValue = true; lblErrorMessage.Text = ""; if ( (txtUserName.Text.Trim() == "") || (txtFullName.Text.Trim() == "") || (txtDescription.Text.Trim() == "") || (txtPassword.Text.Trim() == "") || (txtConfirmPassword.Text.Trim() == "") ) { returnValue = false; lblErrorMessage.ForeColor = System.Drawing.Color.Red; lblErrorMessage.Text = "All fields are required.<p>"; } if (txtPassword.Text.Trim() != txtConfirmPassword.Text.Trim()) { returnValue = false; lblErrorMessage.ForeColor = System.Drawing.Color.Red; lblErrorMessage.Text += "Password fields do not match"; } return returnValue; } #endregion #region Add New User Class /// <summary> /// Adds a new user to the local machine /// </summary> private void AddNewUser() { Response.Write("Current User (In Add New User Class): " + WindowsIdentity.GetCurrent().Name + "<BR>"); try { DirectoryEntry AD = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer"); DirectoryEntry NewUser = AD.Children.Add(txtUserName.Text.Trim(), "user"); NewUser.Invoke("SetPassword", new object[] {txtPassword.Text.Trim()}); NewUser.Invoke("Put", new object[] {"Description", txtDescription.Text.Trim()}); NewUser.Invoke("Put", new object[] {"FullName", txtFullName.Text.Trim()}); NewUser.CommitChanges(); if (cbPasswordExpire.Checked) { int val = (int)NewUser.Properties["UserFlags"].Value; NewUser.Invoke("Put", new object[] {"UserFlags", val | ADS_UF_DONT_EXPIRE_PASSWD}); NewUser.CommitChanges(); } lblErrorMessage.ForeColor = System.Drawing.Color.Blue; lblErrorMessage.Text = "User " + txtUserName.Text.Trim() + " added successfully!"; ResetForm(); } catch (Exception ex) { lblErrorMessage.ForeColor = System.Drawing.Color.Red; lblErrorMessage.Text += "<p>Error Adding User: " + ex.Message; } } #endregion #region Reset Form Class /// <summary> /// Resets the form. /// </summary> private void ResetForm() { txtUserName.Text = ""; txtFullName.Text = ""; txtDescription.Text = ""; txtPassword.Text = ""; txtConfirmPassword.Text = ""; cbPasswordExpire.Checked = false; } #endregion #region Authorize User Class /// <summary> /// Checks whether the current user has authorization or not. /// </summary> /// <returns>Boolean value of whether or not the user has authorization.</returns> private bool authorizeUser() { currentUser = getCurrentUser(); try { SPSite currentSiteCollection = SPControl.GetContextSite(Context); SPWeb currentWeb = currentSiteCollection.OpenWeb(); SPList userList = currentWeb.Lists["Wss Admin List"]; if (userList != null) { //An SPQuery object represents a query in a list view SPQuery query = new SPQuery(); //the query must be in CAML format query.Query = "<Where><Eq><FieldRef Name='LinkTitle'/><Value Type='Text'>" + currentUser + "</Value></Eq></Where>"; SPListItemCollection hits = userList.GetItems(query); if(hits.Count > 0) return (true); else return (false); } else { return (false); } } catch(Exception ex) { lblErrorMessage.Text = ex.Message; return false; } } #endregion #region Get Current User Class /// <summary> /// Gets the currently logged in user /// </summary> /// <returns>String containing the currently logged in user.</returns> private string getCurrentUser() { string user = System.Security.Principal.WindowsIdentity.GetCurrent().Name; System.Text.RegularExpressions.Regex rx = new System.Text.RegularExpressions.Regex(".+\\\\"); string trimmedUser = rx.Replace(user, ""); return trimmedUser; } #endregion #region Impersonate User Class [DllImport("advapi32.dll", SetLastError=true)] public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); // [DllImport("kernel32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)] // private unsafe static extern int FormatMessage(int dwFlags, ref IntPtr lpSource, // int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr *Arguments); [DllImport("kernel32.dll", CharSet=CharSet.Auto)] public extern static bool CloseHandle(IntPtr handle); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); public WindowsImpersonationContext ImpersonateUser(string strUsername, string strDomain, string strPassword) { // initialize tokens IntPtr pExistingTokenHandle = new IntPtr(0); IntPtr pDuplicateTokenHandle = new IntPtr(0); pExistingTokenHandle = IntPtr.Zero; pDuplicateTokenHandle = IntPtr.Zero; // if domain name was blank, assume local machine if (strDomain == "") strDomain = System.Environment.MachineName; try { const int LOGON32_PROVIDER_DEFAULT = 0; // create token const int LOGON32_LOGON_INTERACTIVE = 2; const int SecurityImpersonation = 2; // get handle to token bool boolImpersonated = LogonUser(strUsername, strDomain, strPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle); if(boolImpersonated == false) { int intErrorMessage = Marshal.GetLastWin32Error(); Response.Write("LogonUser failed with error code: " + intErrorMessage); return null; } //Display User Before Impersonation - COMMENT OUT BEFORE DEPLOYING Response.Write("Current User (Before Impersonation): " + WindowsIdentity.GetCurrent().Name + "<BR>"); bool boolRetVal = DuplicateToken(pExistingTokenHandle, SecurityImpersonation, ref pDuplicateTokenHandle); // did DuplicateToken fail? if (boolRetVal == false) { int intErrorCode = Marshal.GetLastWin32Error(); // close existing handle CloseHandle(pExistingTokenHandle); Response.Write("DuplicateToken() failed with error code: " + intErrorCode); return null; } else { // create new identity using new primary token WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle); Response.Write("pfft."); WindowsImpersonationContext impersonatedUser = newId.Impersonate(); // Display User After Impersonation - COMMENT OUT BEFORE DEPLOYING Response.Write("Current User (After Impersonation): " + WindowsIdentity.GetCurrent().Name + "<BR>"); //Call AddNewUser method AddNewUser(); impersonatedUser.Undo(); // Display User After Undoing Impersonation - COMMENT OUT BEFORE DEPLOYING Response.Write("Current User (After Undoing Impersonation): " + WindowsIdentity.GetCurrent().Name + "<BR>"); return impersonatedUser; } } catch (Exception ex) { lblErrorMessage.Text = "Real Exception" + ex.Message; return null; } finally { // close handle(s) if (pExistingTokenHandle != IntPtr.Zero) CloseHandle(pExistingTokenHandle); if (pDuplicateTokenHandle != IntPtr.Zero) CloseHandle(pDuplicateTokenHandle); } } #endregion #endregion } } |
|
#2
| |||
| |||
| And before someone asks, I'm using SmartPart and creating my web-parts as usercontrols. |
|
#3
| |||
| |||
| I'd start by making some changes to your impersonation code. Yours looks a little more complicated than it has to be, plus you've got application logic mixed in there with it. Try this code instead: To start impersonating the Sharepoint domain service account: WindowsIdentity objOriginalUser = WindowsIdentity.GetCurrent(); RevertToSelf(); WindowsIdentity.GetCurrent().Impersonate(); To stop: objOriginalUser.Impersonate(); To start impersonating a specific account: WindowsImpersonationContext wic = CreateIdentity(ACCOUNTNAME,DOMAIN,PASSWORD).Impersonate(); To stop: wic.Undo(); And you'll need this code to call that previous code: using System.Security.Principal; using System.Runtime.InteropServices; ////////////////////////////////////// #region Impersonation code 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. bool returnValue = LogonUser(User, Domain, Password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, ref tokenHandle); if (false == returnValue) { 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)] private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("kernel32.dll", CharSet=CharSet.Auto)] private extern static bool CloseHandle(IntPtr handle); [DllImport("advapi32.dll")] static extern bool RevertToSelf(); #endregion "ptranfa@gmail.com" wrote: > I'm trying to impliment a web-part that will allow select users (ones > that are added to a custom sharepoint list) to Add, Edit and Delete > user accounts on a Server. The client isn't using active directory yet, > so I'm simply creating local machine accounts. I thought I had > everything up and running, if I hit the web-part logged in with > administrator privelages, the impersonation works, Prints out the > correct name BEFORE impersonation, AFTER impersonation, and then AFTER > UNDOING impersonation. It also creates, edits or deletes the user > account appropriately. > > However, if I'm not logged in as a user that has Administrator > privelages, the impersonation fails (kinda the whole point for > impersonation..). Any help would be MUCH appreciated. > > |
|
#4
| |||
| |||
| It just occured to me that you may also be having an issue with the security context under which your smart part is running. I'd recommend following Jan Tielen's advice in the article http://weblogs.asp.net/jan/archive/2...23/414699.aspx regarding custom code policy files, if you haven't already done so. "Joe" wrote: > I'd start by making some changes to your impersonation code. Yours looks a > little more complicated than it has to be, plus you've got application logic > mixed in there with it. Try this code instead: > > To start impersonating the Sharepoint domain service account: > > WindowsIdentity objOriginalUser = WindowsIdentity.GetCurrent(); > RevertToSelf(); > WindowsIdentity.GetCurrent().Impersonate(); > > To stop: > objOriginalUser.Impersonate(); > > > To start impersonating a specific account: > > WindowsImpersonationContext wic = > CreateIdentity(ACCOUNTNAME,DOMAIN,PASSWORD).Impersonate(); > > To stop: > > wic.Undo(); > > > > And you'll need this code to call that previous code: > > using System.Security.Principal; > using System.Runtime.InteropServices; > ////////////////////////////////////// > > > #region Impersonation code > 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. > bool returnValue = LogonUser(User, Domain, Password, > LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, > ref tokenHandle); > > if (false == returnValue) > { > 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)] > private static extern bool LogonUser(String lpszUsername, String > lpszDomain, String lpszPassword, > int dwLogonType, int dwLogonProvider, ref IntPtr phToken); > > [DllImport("kernel32.dll", CharSet=CharSet.Auto)] > private extern static bool CloseHandle(IntPtr handle); > > [DllImport("advapi32.dll")] > static extern bool RevertToSelf(); > > #endregion > > > > "ptranfa@gmail.com" wrote: > > > I'm trying to impliment a web-part that will allow select users (ones > > that are added to a custom sharepoint list) to Add, Edit and Delete > > user accounts on a Server. The client isn't using active directory yet, > > so I'm simply creating local machine accounts. I thought I had > > everything up and running, if I hit the web-part logged in with > > administrator privelages, the impersonation works, Prints out the > > correct name BEFORE impersonation, AFTER impersonation, and then AFTER > > UNDOING impersonation. It also creates, edits or deletes the user > > account appropriately. > > > > However, if I'm not logged in as a user that has Administrator > > privelages, the impersonation fails (kinda the whole point for > > impersonation..). Any help would be MUCH appreciated. > > > > |
|
#5
| |||
| |||
| Thank you. I've been instructed to stand the web-part up in its current state (it works fine for people with administrative privelages on the machine) as an interim solution. I tried using the reverttoself method of impersonation late yesterday and it wouldn't work either. The default identity that the site uses is Network Service and it was tossing Access Denied errors as well. I was wrong in stating that the impersonation worked if I was logged in as an Administrator, the development virtual server I was given had the default identity for IIS set to the Administrator account, so of course it worked, I changed it, un-installed and re-installed a fresh copy of WSS to fix some errors in the previous installation inconsistencies, and realized I was wrong. The problem is that this is for a DoD client and I can't make too many changes on the server without huge political overhead and they need this up and running COB today. I just started this job on Monday ![]() |
|
#6
| |||
| |||
| You should have your Sharepoint site running under its own application pool, and that application pool should have its identity configured as a domain account that has power user or administrator privileges on the server. That's the cause of your impersonation problems -- the identity Sharepoint is running under (network service) doesn't have rights to do what you want it to do. As you've found, though, this is trumped by having an actual administrator log in to the site. I'm not sure what other issues you'll run into (if any) with your current setup. I think problems will arise if you start adding other servers to your Sharepoint environment. Do you have any good Sharepoint books? The Resource Kit, by Bill English, is pretty comprehensive, and a lot of it is available online. http://www.microsoft.com/technet/win...t/default.mspx "ptranfa@gmail.com" wrote: > Thank you. I've been instructed to stand the web-part up in its current > state (it works fine for people with administrative privelages on the > machine) as an interim solution. > > I tried using the reverttoself method of impersonation late yesterday > and it wouldn't work either. The default identity that the site uses is > Network Service and it was tossing Access Denied errors as well. > > I was wrong in stating that the impersonation worked if I was logged in > as an Administrator, the development virtual server I was given had the > default identity for IIS set to the Administrator account, so of course > it worked, I changed it, un-installed and re-installed a fresh copy of > WSS to fix some errors in the previous installation inconsistencies, > and realized I was wrong. > > The problem is that this is for a DoD client and I can't make too many > changes on the server without huge political overhead and they need > this up and running COB today. > > I just started this job on Monday ![]() > > |
|
#7
| |||
| |||
| SharePoint provides options to create sites with different types of locales available out of the box. Suppose we have a SharePoint site built using the English locale and we want to change the existing site to some other locale then this can be achieved using the following piece of code. Changing the locale of the site helps display the date and number formats with their respective decimal and group separators. Eliza |
![]() |
| Thread Tools | |
| |
| ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Adding web part programmatically | usenet | Sharepoint | 4 | 02-09-2010 08:34 AM |
| Impersonating user | usenet | DOTNET | 4 | 09-12-2007 02:43 PM |
| Impersonating user | usenet | Inetserver | 1 | 09-12-2007 12:41 PM |
| Programmatically Changing the URL of a Page Viewer web part | usenet | Sharepoint | 1 | 01-24-2007 05:25 PM |
| Programmatically specify client cert as part of web service call | usenet | Java | 2 | 01-11-2004 08:31 AM |



