Issue With Programmatically Impersonating a User in a Web-Part



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.




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
}
}

.