I got this exception in very easy code and I have running with elevated privileges around it.
It in sharepoint 2010
private void ChangeVersioningOnDocumentLibrary(SPListItem item, SPItemEventProperties properties, SPSite site)
{
string sitename = item[MeetingsCommon.Constants.FIELDS_TEXT_TITLE_NAME].ToString();
string prefix = item[MeetingsCommon.Constants.FIELDS_TEXT_TITLE_NAME].ToString().Substring(0, 2);
bool isConfirmed = item.TaxonomyFieldValueIsGivenValue(properties.AfterProperties, MeetingsCommon.Constants.FIELDS_MEETINGSTATUS_NAME, MeetingsCommon.Constants.TERMVALUE_MEETINGSTATUS_CONFIRMED, 1033);
bool isPublished = item.TaxonomyFieldValueIsGivenValue(properties.AfterProperties, MeetingsCommon.Constants.FIELDS_MEETINGSTATUS_NAME, MeetingsCommon.Constants.TERMVALUE_MEETINGSTATUS_PUBLISHED, 1033);
if (isConfirmed)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPWeb web = site.OpenWeb(prefix + "/" + sitename))
{
if (web.Exists)
{
web.AllowUnsafeUpdates = true;
SPList agendaPoints = web.GetSafeListByName(MeetingsCommon.Constants.LISTS_AGENDAPOINTS_NAME);
agendaPoints.EnableModeration = true;
agendaPoints.DraftVersionVisibility = DraftVisibilityType.Author;
agendaPoints.Update();
web.AllowUnsafeUpdates = false;
}
}
});
}
if (isPublished)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPWeb web = site.OpenWeb(prefix + "/" + sitename))
{
if (web.Exists)
{
web.AllowUnsafeUpdates = true;
SPList agendaPoints = web.GetSafeListByName(MeetingsCommon.Constants.LISTS_AGENDAPOINTS_NAME);
agendaPoints.EnableModeration = false;
agendaPoints.DraftVersionVisibility = DraftVisibilityType.Author;
agendaPoints.Update();
web.AllowUnsafeUpdates = false;
}
}
});
}
}
the problem is that it was using an spsite object coming from outside the RunWithElevatedPriviliges, the spsite object has to be created again inside in order for this to work.
Related
I'm a newbie using c# and i need to create an extension that goes to a directory and retrieves info about the users like username, name and email.
This is the login validation method that i created and it's working.
public void MssValidateUserLDAP(string ssHostname, string ssBaseDN, string ssUsername, string ssPassword, out bool ssOk, out string ssErrorMessage) {
ssOk = false;
ssErrorMessage = string.Empty;
String ssBaseRDN = string.Empty; // stores user RDN for authentication
LdapConnection connection = new LdapConnection(ssHostname);
connection.AuthType = AuthType.Basic;
try
{
SearchRequest searchRequest = new SearchRequest();
// Search parameters
searchRequest.Scope = System.DirectoryServices.Protocols.SearchScope.OneLevel;
searchRequest.DistinguishedName = ssBaseDN;
searchRequest.Filter = ssUsername;
// cast the returned directory response as a SearchResponse object
SearchResponse searchResponse = (SearchResponse)connection.SendRequest(searchRequest);
// enumerate the entries in the search response
foreach (SearchResultEntry entry in searchResponse.Entries)
{
ssBaseRDN = entry.DistinguishedName;
ssOk = true;
}
if (ssBaseRDN != "")
{
connection.Bind(new NetworkCredential(ssBaseRDN, ssPassword));
}
else { ssOk = false; ssErrorMessage = "User not found"; }
}
catch (Exception e)
{
ssErrorMessage = e.GetType().Name + " " + e.Message;
ssOk = false;
}
}
This is what i was able to do, but it's not working and i can't find the reason behind that. Any help would be appreciated!
public void MssSearch(string ssUsername, string ssPassword, string ssPath, out RLUserRecordList ssUsers, out string ssErrorMessage) {
ssErrorMessage = "";
ssUsers = new RLUserRecordList(null);
try
{
RLUserRecordList aux = new RLUserRecordList();
DirectoryEntry rootEntry = new DirectoryEntry(ssPath,ssUsername,ssPassword);
DirectorySearcher searcher = new DirectorySearcher(rootEntry);
foreach(SearchResult result in searcher.FindAll())
{
RCUserRecord u = new RCUserRecord(Convert.ToString(result.Properties["cn"][0]));
aux.Append(u);
}
ssUsers = aux;
}
catch (Exception e){
ssErrorMessage = e.GetType().Name + " " + e.Message;
}
} // MssSearch
We have been able to create a web site. We did this using the information in this link:
https://msdn.microsoft.com/en-us/library/ms525598.aspx
However, we would like to use a port number other that port 80. How do we do this?
We are using IIS 6
If you're using IIS 7, there is a new managed API called Microsoft.Web.Administration
An example from the above blog post:
ServerManager iisManager = new ServerManager();
iisManager.Sites.Add("NewSite", "http", "*:8080:", "d:\\MySite");
iisManager.CommitChanges();
If you're using IIS 6 and want to do this, it's more complex unfortunately.
You will have to create a web service on every server, a web service that handles the creation of a website because direct user impersonation over the network won't work properly (If I recall this correctly).
You will have to use Interop Services and do something similar to this (This example uses two objects, server and site, which are instances of custom classes that store a server's and site's configuration):
string metabasePath = "IIS://" + server.ComputerName + "/W3SVC";
DirectoryEntry w3svc = new DirectoryEntry(metabasePath, server.Username, server.Password);
string serverBindings = ":80:" + site.HostName;
string homeDirectory = server.WWWRootPath + "\\" + site.FolderName;
object[] newSite = new object[] { site.Name, new object[] { serverBindings }, homeDirectory };
object websiteId = (object)w3svc.Invoke("CreateNewSite", newSite);
// Returns the Website ID from the Metabase
int id = (int)websiteId;
See more here
Heres the solution.
Blog article : How to add new website in IIS 7
On Button click :
try
{
ServerManager serverMgr = new ServerManager();
string strWebsitename = txtwebsitename.Text; // abc
string strApplicationPool = "DefaultAppPool"; // set your deafultpool :4.0 in IIS
string strhostname = txthostname.Text; //abc.com
string stripaddress = txtipaddress.Text;// ip address
string bindinginfo = stripaddress + ":80:" + strhostname;
//check if website name already exists in IIS
Boolean bWebsite = IsWebsiteExists(strWebsitename);
if (!bWebsite)
{
Site mySite = serverMgr.Sites.Add(strWebsitename.ToString(), "http", bindinginfo, "C:\\inetpub\\wwwroot\\yourWebsite");
mySite.ApplicationDefaults.ApplicationPoolName = strApplicationPool;
mySite.TraceFailedRequestsLogging.Enabled = true;
mySite.TraceFailedRequestsLogging.Directory = "C:\\inetpub\\customfolder\\site";
serverMgr.CommitChanges();
lblmsg.Text = "New website " + strWebsitename + " added sucessfully";
}
else
{
lblmsg.Text = "Name should be unique, " + strWebsitename + " is already exists. ";
}
}
catch (Exception ae)
{
Response.Redirect(ae.Message);
}
Looping over sites whether name already exists
public bool IsWebsiteExists(string strWebsitename)
{
Boolean flagset = false;
SiteCollection sitecollection = serverMgr.Sites;
foreach (Site site in sitecollection)
{
if (site.Name == strWebsitename.ToString())
{
flagset = true;
break;
}
else
{
flagset = false;
}
}
return flagset;
}
Try the following Code to Know the unUsed PortNo
DirectoryEntry root = new DirectoryEntry("IIS://localhost/W3SVC");
// Find unused ID PortNo for new web site
bool found_valid_port_no = false;
int random_port_no = 1;
do
{
bool regenerate_port_no = false;
System.Random random_generator = new Random();
random_port_no = random_generator.Next(9000,15000);
foreach (DirectoryEntry e in root.Children)
{
if (e.SchemaClassName == "IIsWebServer")
{
int site_id = Convert.ToInt32(e.Name);
//For each detected ID find the port Number
DirectoryEntry vRoot = new DirectoryEntry("IIS://localhost/W3SVC/" + site_id);
PropertyValueCollection pvcServerBindings = vRoot.Properties["serverbindings"];
String bindings = pvcServerBindings.Value.ToString().Replace(":", "");
int port_no = Convert.ToInt32(bindings);
if (port_no == random_port_no)
{
regenerate_port_no = true;
break;
}
}
}
found_valid_port_no = !regenerate_port_no;
} while (!found_valid_port_no);
int newportId = random_port_no;
I have gone though all answer here and also tested. Here is the most clean smarter version of answer for this question. However this still cant work on IIS 6.0. so IIS 8.0 or above is required.
string domainName = "";
string appPoolName = "";
string webFiles = "C:\\Users\\John\\Desktop\\New Folder";
if (IsWebsiteExists(domainName) == false)
{
ServerManager iisManager = new ServerManager();
iisManager.Sites.Add(domainName, "http", "*:8080:", webFiles);
iisManager.ApplicationDefaults.ApplicationPoolName = appPoolName;
iisManager.CommitChanges();
}
else
{
Console.WriteLine("Name Exists already");
}
public static bool IsWebsiteExists(string strWebsitename)
{
ServerManager serverMgr = new ServerManager();
Boolean flagset = false;
SiteCollection sitecollection = serverMgr.Sites;
flagset = sitecollection.Any(x => x.Name == strWebsitename);
return flagset;
}
This simplified method will create a site with default binding settings, and also create the application pool if needed:
public void addIISApplication(string siteName, string physicalPath, int port, string appPoolName)
{
using (var serverMgr = new ServerManager())
{
var sitecollection = serverMgr.Sites;
if (!sitecollection.Any(x => x.Name.ToLower() == siteName.ToLower()))
{
var appPools = serverMgr.ApplicationPools;
if (!appPools.Any(x => x.Name.ToLower() == appPoolName.ToLower()))
{
serverMgr.ApplicationPools.Add(appPoolName);
}
var mySite = serverMgr.Sites.Add(siteName, physicalPath, port);
mySite.ApplicationDefaults.ApplicationPoolName = appPoolName;
serverMgr.CommitChanges();
}
}
}
In properties of site select "Web Site" tab and specify TCP Port.
In studio to debug purpose specify http://localhost:<port>/<site> at tab Web for "Use Local IIS Web Server"
"RunWithElevatedPrivileges": Programmatically in C# it doesn't help me to allow users without manage List permission to upload file to sharepoint list items. My code is:
SPSecurity.RunWithElevatedPrivileges(delegate
{
SPWeb web = SPContext.Current.Site;
// my logic to upload file and edit list item attachments.
});
Complete code
protected void btn_Upload_Click(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter(#"C:\Upload.txt", true);
try
{
if (this.FileUpload1.HasFile)
{
string siteURL = SPContext.Current.Web.Url.ToString();
if (Request["Items"] != null && Request["ListId"] != null)
{
string SelectedItems = Convert.ToString(Request["Items"]);
string[] lstJobsIds = SelectedItems.Split(new string[] { "|" }, StringSplitOptions.None);
SPList list = null;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//SPSite site = SPContext.Current.Site;
using (SPSite site = new SPSite("http://sitrURL"))
{
using (SPWeb web = site.OpenWeb())
{
// Fetch the List
//list = web.Lists["ListName"];
sw.WriteLine("WEb is :" + web);
list = web.Lists["ListName"];
if (lstJobsIds.Length > 0)
{
////site.AllowUnsafeUpdates = true;
////web.AllowUnsafeUpdates = true;
for (int i = 0; i < lstJobsIds.Length; i++)
{
// Get the List item
if (lstJobsIds[i] != null && lstJobsIds[i] != string.Empty)
{
sw.WriteLine(lstJobsIds[i]);
SPListItem listItem = list.GetItemById(int.Parse(lstJobsIds[i]));
// Get the Attachment collection
SPAttachmentCollection attachmentCollection = listItem.Attachments;
Stream attachmentStream;
Byte[] attachmentContent;
sw.WriteLine(this.FileUpload1.PostedFile);
sw.WriteLine(this.FileUpload1.FileName);
attachmentStream = this.FileUpload1.PostedFile.InputStream;
attachmentContent = new Byte[attachmentStream.Length];
attachmentStream.Read(attachmentContent, 0, (int)attachmentStream.Length);
attachmentStream.Close();
attachmentStream.Dispose();
// Add the file to the attachment collection
attachmentCollection.Add(this.FileUpload1.FileName, attachmentContent);
// Update th list item
listItem.Update();
web.AllowUnsafeUpdates = true;
}
}
//web.AllowUnsafeUpdates = false;
//site.AllowUnsafeUpdates = false;
}
sw.Close();
}
}
});
}
}
}
catch (Exception ex)
{
sw.WriteLine(ex);
sw.Close();
}
}
Now When user click on button to upload file he gets HTTP Error 403 Forbidden.
So,how to allow users With limit permission to execute my custom function normally?
Your code is wrong. Always create and dispose off the objects within the RunWithElevatedPrivileges delegate. So you should create new instance of SPweb inside the RunWithElevatedPrivileges block by using 'new' keyword.
Example:
private void yourFunction()
{
SPSite site = SPContext.Current.Site;
SPWeb web = SPContext.Current.Web;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite ElevatedSite = new SPSite(site.ID))
{
using (SPWeb ElevatedWeb = ElevatedSite.OpenWeb(web.ID))
{
// Code Using the SPWeb Object Goes Here
}
}
});
}
Sometimes in custom SharePoint solutions we need to execute custom code using System Account privileges than the current logged in user which may not have sufficient rights to execute custom code. In these situations we use RunWithElevatedPrivileges() method to delegate System Account rights to current logged in user.
In case current user does not have appropriate permissions to execute custom code then he will get “Access Denied” error. To bypass “Access Denied” error we use RunWithElevatedPrivileges() method.
Click on below link for more detailed answer
http://sharepointbag.com/latest/code-snippets/sharepoint/security/5/how-to-use-run-with-elevated-privileges-(rwep)-in-sharepoint/
I am using the following code to create a folder inside my document library. The event get triggered and executed till the last line of my code without any issues. However the folder is not getting created or listed in my document library.
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
string strDashListRoot = "http://win-hmpjltdbh5q:37642";
using (SPSite site = new SPSite(strDashListRoot))
{
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
SPList spl = web.Lists["client_documents"];
spl.Items.Add("", SPFileSystemObjectType.Folder, "Helllworld");
spl.Update();
web.AllowUnsafeUpdates = false;
}
}
}
You need
var i = spl.Items.Add("", SPFileSystemObjectType.Folder, "Helllworld");
i.Update();
instead of
spl.Items.Add("", SPFileSystemObjectType.Folder, "Helllworld");
spl.Update();
(assuming your Add call is fine - it looks OK to me)
(Also, are you sure you need the AllowUnsafeUpdates handling? I wouldn't have expected it to be necessary when you're in an ItemAdded handler.)
I developed the following code based on Rawling's answer:
private static void CreateFolder(SPWeb web, SPList spList, SPListItem currentItem, string folderName)
{
if (currentItem.FileSystemObjectType != SPFileSystemObjectType.Folder)
{
string itemUrl = web.Url + "/" + currentItem.Url.Substring(0, currentItem.Url.LastIndexOf('/'));
var folder = spList.Items.Add(itemUrl, SPFileSystemObjectType.Folder, folderName);
string folderUrl = itemUrl + "/" + folder.Name;
if (!FolderExists(folderUrl, web))
{
try
{
folder.Update();
}
catch (Exception)
{
throw;
}
}
}
}
public static bool FolderExists(string url, SPWeb web)
{
if (url.Equals(string.Empty))
{
return false;
}
try
{
return web.GetFolder(url).Exists;
}
catch (ArgumentException)
{
throw;
}
catch (Exception)
{
throw;
}
}
No matter what I do, before and after for title are always null. This is an item updated receiver in the meetings or event list
!
[public override void ItemUpdated(SPItemEventProperties properties)
{
Logger.LogDebug("MeetingCalendarEvents", "ItemUpdated(SPItemEventProperties properties)", "BEGIN");
base.ItemUpdated(properties);
try
{
base.EventFiringEnabled = false;
SPSite site = properties.Web.Site;
string sitename= properties.BeforeProperties\["Title"\].ToString();
SPWeb web = site.RootWeb.Webs\[sitename\];
web.AllowUnsafeUpdates = true;
string prefix = properties.BeforeProperties\["Title"\].ToString().Substring(0, 2);
web.Title = properties.AfterProperties\["Title"\].ToString();
DateTime eventDate = properties.AfterProperties.GetValueAsDateTime(MeetingsCommon.Constants.FIELDS_EVENTDATE_NAME);
if (eventDate != DateTime.MinValue)
{
string titleMeetingCalendarItem = eventDate.ToString("yyyyMMdd");
titleMeetingCalendarItem = string.Format("{0}{1}", prefix, titleMeetingCalendarItem);
properties.AfterProperties.SetAfterPropertyValue("Title", titleMeetingCalendarItem);
web.ServerRelativeUrl = "/" + titleMeetingCalendarItem;
}
web.Update();
web.AllowUnsafeUpdates = false;
base.EventFiringEnabled = true;
}
catch (Exception ex)
{
Logger.LogError("MeetingCalendarEvents", "ItemUpdated(SPItemEventProperties properties)", ex);
properties.ErrorMessage = ex.Message;
properties.Cancel = true;
}
finally
{
base.EventFiringEnabled = true;
}
Logger.LogDebug("MeetingCalendarEvents", "ItemUpdated(SPItemEventProperties properties)", "END");
}]
answer here:
http://www.synergyonline.com/Blog/Lists/Posts/Post.aspx?ID=122