This might an odd question, but what I would like to achieve is a functionality that would allow specific users to view SharePoint pages as if they were logged in as different users.
Let's say we have a Student page and a Staff page. I am not a student, but I would like to log in as one to be able to view the Student page as a student would. Does that make sense? So, in a way, impersonation.
I have found some impersonation code, and it works fine, but it is not what I want. I was able to impersonate a user in a separate SPWeb object. But, how do I change the current user context of the active SPWeb object?
Here's what I've got:
private void ImpersonateUser()
{
string siteURL = "http://mywebsite/";
SPSite parentSite = new SPSite(siteURL);
SPUserToken systemToken = parentSite.SystemAccount.UserToken;
using (SPSite site = new SPSite(siteURL, systemToken))
{
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
OpenUserContext(web, siteURL, #"domain\studentuser");
}
}
}
private void OpenUserContext(SPWeb web, string siteURL, string user)
{
try
{
SPUser ensure = web.EnsureUser(user);
SPSite impSite = new SPSite(siteURL, ensure.UserToken);
SPWeb impWeb = impSite.OpenWeb();
// Do something as impersonated user
label1.Text = "Currently logged in as: " + impWeb.CurrentUser.ToString() + "(" + impWeb.CurrentUser.Name + ")";
}
catch (Exception ex) { label1.Text = ex.Message + "<br>" + user; }
}
Thanks a lot.
While SharePoint does allow your code to interact with it while impersonating a user, it has no support to allow you to browse and view things as if you were another user.
You can, however, code your customizations to take in to account your desire and add the impersonation logic to them (but that's up to you to implement and SP will not help you there). Project Server does something like what you are asking but only when it comes to Project Server owned elements.
If your impersonation code is executing behind a custom .aspx page in SharePoint, you can programmatically add an xsltlistviewwebpart to the page to display one or more list views under your impersonated context.
Related
I am very new in SharePoint (I am using SharePoint 2013) and I am experiencing a strange problem. This is very strange because in another section of my application it works fine (in another subsite).
So basically into SharePoint I have a SharePoint list named Protocollo.
My code contains the following lines that add a document (a file) into a subfolder of the previous SharePoint List:
internal static int InsertItem(Dictionary<string, object> prot, Documento doc, bool assignVisibility, bool newItem)
{
int state = 0;
SPListItem item = null;
UOR currUOR = null;
List<UOR> path = new List<UOR>();
SPWeb web = SPContext.Current.Web;
string siglaAOO = web.Properties["sigla_aoo"];
DBConnection dbConfig = ArxeiaProtocollo.Util.ProtUtils.InitializeDBConnection();
dbConfig.Database = siglaAOO;
string username = web.CurrentUser.LoginName;
try
{
SPList list = web.Lists["Protocollo"];
web.AllowUnsafeUpdates = true;
SPFolderCollection folders = list.RootFolder.SubFolders;
SPFolder annoFolder;
DateTime dateProt = Convert.ToDateTime(prot["Data protocollo"]);
try
{
annoFolder = folders[dateProt.Year.ToString()];
}
catch
{
annoFolder = folders.Add(dateProt.Year.ToString());
}
SPFolder meseFolder;
try
{
meseFolder = annoFolder.SubFolders[dateProt.Month.ToString("D2")];
}
catch
{
meseFolder = annoFolder.SubFolders.Add(dateProt.Month.ToString("D2"));
}
SPFolder dayFolder;
try
{
dayFolder = meseFolder.SubFolders[dateProt.Day.ToString("D2")];
}
catch
{
dayFolder = meseFolder.SubFolders.Add(dateProt.Day.ToString("D2"));
}
SPFile spFile = dayFolder.Files.Add(doc.Nome, doc.File, true);
............................................................
............................................................
............................................................
}
As you can see the previous code retrievce the Protocollo list from the current website allowing updates on it by:
SPList list = web.Lists["Protocollo"];
web.AllowUnsafeUpdates = true;
Then into this list it creates (it doesn't exist) a gerarcic folders structure for year (annoFolder), month (meseFolder) and day (dayFolder).
It works fine, I tried to delete these folder structure from my SharePoint site and performing this method it is created again, infact this is what I obtained:
As you can see it correctly creates this folder structure into my SharePoint list (named Protocollo) into the current website.
Ok finnally my code try to insert a document into the last subfolder (the dayfolder) by:
SPFile spFile = dayFolder.Files.Add(doc.Nome, doc.File, true);
I am passing to the Add() method: the name of the file, the byte array representing the file and the true boolean value.
The problem is that performing this line I obtain the following exception that is not providing information:
{Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.}
Then in my front end it appears a "denied access" popup window.
The strange thing is that another sites in my SharePoint that uses the same code have no problem. Another strange thing is that manually uploading the file into this location of the list it works fine so I think that it should not be a user permission problem.
Some idea? What can I try to do to solve this strange problem?
SharePoint codes run using the Application Pool user in IIS not the user that you have logged in to SharePoint, so it is common to get an access denied error even when you have access. So I would suggest you check the permission for the AppPool account on the Protocollo library. Or you can use SPSecurity.RunWithElevatedPrivileges if you have trust in the user that will run the code.
Beware of the pitfalls though.
Here is a sample usage:
Guid siteId = SPContext.Current.Site.ID;
Guid webId = SPContext.Current.Web.ID;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(siteId))
{
using (SPWeb web = site.OpenWeb(webId))
{
// Your code here
}
}
});
I have a fairly odd requirement to be able to impersonate a user, when I'm already impersonating another, using C#.
I'm writing an app to allow the management of Active Directory users. This app will provide the ability for anyone in the company to view and maintain certain details about themselves (some of which will not actually be saved to Active Directory, but some of which will), for managers to be able to view and maintain details about their team, and for HR to be able to view and maintain details about anyone.
For obvious reasons I don't want to develop or test this against the live domain. We have recently ported all users over to this domain from another domain, which means I can actually test against the old domain without affecting anything. However, to enable me to do this I have to impersonate my old account on the old domain, which I do on loading the application.
Although for me everything will work fine as I'm setup as a domain admin, going forward obviously not all users will be domain admins, and won't be able to write to AD under their own account, and therefore we have another domain admin user setup specifically for this application, whenever data needs to be saved to AD that user is impersonated. This was working great before when I was testing against an Active Directory I'd setup on a virtual machine because I was logging onto the local domain, however that didn't allow me to step through the code in Visual Studio so debugging was slow, and hence I've stopped using that virtual machine and am using this old domain. Now I'm already impersonating another user (i.e. my old domain account), when it then tries to impersonate the domain admin user it fails with an "System.Security.SecurityException: Access is denied." exception. The line this fails on is just writing out some debugging information using "WindowsIdentity.GetCurrent().Name".
If I change my code so I'm actually logging in using the new domain admin rather than my old account, the first time it goes through it logs in successfully (so the credentials are correct), however when it then goes through and tries to do the same again to write to AD it fails with the above exception. Therefore I think it must be a problem with trying to do a nested impersonate.
Is it possible to do a nested impersonate?
Below is the code I'm using:
private static WindowsImpersonationContext ImpersonateUser(out string result, string sUsername,
string sDomain, string sPassword)
{
// initialize tokens
var pExistingTokenHandle = new IntPtr(0);
var pDuplicateTokenHandle = new IntPtr(0);
// if domain name was blank, assume local machine
if (sDomain == "")
{
sDomain = Environment.MachineName;
}
try
{
result = null;
const int logon32ProviderDefault = 0;
// create token
const int logon32LogonInteractive = 2;
// get handle to token
var bImpersonated = LogonUser(sUsername, sDomain, sPassword,
logon32LogonInteractive,
logon32ProviderDefault,
ref pExistingTokenHandle);
// did impersonation fail?
if (!bImpersonated)
{
var nErrorCode = Marshal.GetLastWin32Error();
result = "LogonUser() failed with error code: " + nErrorCode + "\r\n";
}
// Get identity before impersonation
result += string.Format("Before impersonation: {0}\r\n", WindowsIdentity.GetCurrent().Name);
var bRetVal = DuplicateToken(pExistingTokenHandle, (int)SecurityImpersonationLevel.SecurityImpersonation,
ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (bRetVal)
{
// create new identity using new primary token
var newId = new WindowsIdentity(pDuplicateTokenHandle);
var impersonatedUser = newId.Impersonate();
// check the identity after impersonation
result += "After impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n";
return impersonatedUser;
}
else
{
var nErrorCode = Marshal.GetLastWin32Error();
CloseHandle(pExistingTokenHandle); // close existing handle
result += "DuplicateToken() failed with error code: " + nErrorCode + "\r\n";
return null;
}
}
finally
{
// close handle(s)
if (pExistingTokenHandle != IntPtr.Zero)
{
CloseHandle(pExistingTokenHandle);
}
if (pDuplicateTokenHandle != IntPtr.Zero)
{
CloseHandle(pDuplicateTokenHandle);
}
}
}
When this is called for the nested impersonation which fails, "bImpersonated" is actually "true", as is bRetVal, which suggests its worked, however when it gets to "WindowsIdentity.GetCurrent().Name" it fails with the exception above.
I hope this makes sense, and would appreciate any assistance.
I have a SharePoint 2010 site hosted on a remote server and I want to add users to one of the SharePoint groups automatically from another machine using C#. I've tried using web services as mentioned all over the internet as under:
class Program
{
static void Main(string[] args)
{
SPUserGroupRef.UserGroup usrGrpService = new SPUserGroupRef.UserGroup();
System.Net.NetworkCredential netCred = new System.Net.NetworkCredential(<my username>, <my password>, <my domain name>);
usrGrpService.Credentials = netCred;
usrGrpService.AddUserToGroup(<group name>, <new user full name>, <domain\new user name>, <new user email address>, <notes>);
}
}
Note:
1. SPUserGroupRef is the web service reference to http:///_vti_bin/usergroup.asmx
2. All the angle-bracketed entities mentioned above in the code are strings.
1st 3 lines of code inside Main execute fine but the 4th line fails with "Exception of type Microsoft.SharePoint.SoapServer.SoapServerException was thrown". I am pretty new to SharePoint so may be I am missing something here. Can someone help me figure out how to get over this issue or may be suggest another approach that might work (but remember my SharePoint site is hosted on a remote server, not on my local machine.
why dont you use Sharepoint 2010 client object model,I have not tested below code, but it should work.
namespace ClientObjectModel
{
class Program
{
static void Main(string[] args)
{
// Add a new user to a particular group
string siteURL = "http://serverName:1111/sites/SPSiteDataQuery/";
ClientContext context = new ClientContext(siteURL);
GroupCollection groupColl = context.Web.SiteGroups;
Group group = groupColl.GetById(7);
UserCreationInformation userCreationInfo = new UserCreationInformation();
userCreationInfo.Email = "";
userCreationInfo.LoginName = #"DomainName\UserName";
userCreationInfo.Title = "SharePoint Developer";
User user = group.Users.Add(userCreationInfo);
context.ExecuteQuery();
}
}
}
Microsoft.SharePoint and Microsoft.SharePoint.Client
let me know if it works?
I'm trying to fix some code (that I didn't write) that inserts an item into a SharePoint list. The problem is the code works for anonymous users, but if the user is logged in via ASP.NET forms authentication, it gets an UnauthorizedAccessException when calling the Update method of the SPListItem. When it works, as an anonymous user, I can see the the SPUser of the SPListItem's SPWeb is the SharePoint system account. But when the user is logged in with Forms Authentication, the SPUser is null. Can someone explain this behavior and how to fix it?
Originally only the top block of code was in the RunWithElevatedPrivileges delegate, but I tried moving it all inside. I'll insert some using blocks once I get it working:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
rootWeb = SPContext.Current.Site.RootWeb;
rootWeb.AllowUnsafeUpdates = true;
currentWeb = SPContext.Current.Web;
currentWeb.AllowUnsafeUpdates = true;
try
{
// Get site information
SPList franDir = rootWeb.GetList("/Lists/Directory");
SPQuery query = new SPQuery();
query.Query = "<Where><Eq><FieldRef Name='Subsite'/><Value Type='Text'>" + currentWeb.Name +
"</Value></Eq></Where>";
SPListItemCollection items = franDir.GetItems(query);
SPList l = rootWeb.GetList("/Lists/Request");
SPListItem li = l.Items.Add();
li["Location"] = siteName;
//...set more fields
li.Update();
}
catch (Exception ex)
{
rootWeb.Dispose();
logger.ErrorException("An error occured adding item", ex);
throw ex;
}
rootWeb.Dispose();
});
Thanks to #AlexeiLevenkov I see that this doesn't work because I'm using an existing instance of the SP objects which were created using the default privileges. As proof that the code does nothing, when running as an anonymous user the code succeeds even without the RunWithElevatedPrivileges call. I made this change and it took care of it.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
rootWeb = new SPSite(SPContext.Current.Site.ID).RootWeb;
Thanks a lot!
I access the AD properties thru the below method. It works fine in my Local VHD (where I'm the domain/local/enterprise Admin) - but the same doesn't work when I access from a Domain user(who has only local admin access).
But the same Domain user(only with local admin access) access all the AD property details using the ADExplorer(SysInternal) tools.
Is it because that is unmanaged code and have Windows APIs to access and in .Net I need domain admin or some privilege ?
Or is there another way - which I'm missing in .Net to access the AD Properties without having an extra domain-level-privilege ??
public void getCurrentUserADDetails(string UserName)
{
string ladpQueryStr = "LDAP://sp.com";
DirectoryEntry dirEntry = new DirectoryEntry(ladpQueryStr);
DirectorySearcher srch = new DirectorySearcher(dirEntry);
srch.Filter = "(cn=" + UserName.ToLowerInvariant().Trim() + ")";
srch.PropertiesToLoad.Add("name");
srch.PropertiesToLoad.Add("memberOf");
srch.PropertiesToLoad.Add("prop123");
SearchResult searcResult = srch.FindOne();
if (searcResult != null)
{
ResultPropertyCollection propertiesCollection = searcResult.Properties;
List<DisplayClass> grdDataList = new List<DisplayClass>();
foreach (string strKey in propertiesCollection.PropertyNames)
{
DisplayClass dispC = new DisplayClass();
dispC.pName = strKey;
dispC.pValue = Convert.ToString(propertiesCollection[strKey][0]);
grdDataList.Add(dispC);
}
dataGridView1.DataSource = grdDataList;
}
}
This is going to run in ASP.Net
thanks in advance :)
I assume you're using integrated authentification - in order for this to work you have to setup account delegation, unless you're running your application on a domain controller. This is a pretty tricky process, but there are a ton of info in Google.
By using Explicit authentication and changing the Search filter, i got the results.
DirectoryEntry dirEntry = new DirectoryEntry(path, username, password, AuthenticationType);