Changing the masterpage of individual pages in SharePoint/MOSS 2007
0 CommentsPublished by Ciaran McAuliffe on Sunday, December 17, 2006 at 7:12 PM.
It is possible to change the masterpage of a page in SharePoint/MOSS 2007 by using SharePoint Designer or by adjusting the values of the ~masterurl/default.master and the ~masterurl/custom.master. But what if you want to be able to change a page without using the designer and what if you want your page to use a different masterpage besides the two mentioned above, or even switch them. The snippet of code below will allow you to do it. Unfortunately when you get a SPFile object you cannot just cast it into an aspx page and change its masterpage value, so the code snippet downloads the file, finds the MasterPageFile attribute by using a regular expression, changes it and uploads it again. This piece of code would probably be best used by turning it into a webpart or a control in the settings areas of a website, which would list pages and then the master pages you could apply to them.
Uri fileUri = new
Uri("http://mysite:26195/mysubweb/Documents/Forms/AllItems.aspx");
string masterPageRegEx = @"MasterPageFile=""[^""]*""";
string masterPageUpdate = "MasterPageFile=\"{0}\"";
string masterPage =
"~SiteCollection/_catalogs/masterpage/mymaster.master";
//string masterPage = "~masterurl/default.master";
//string masterPage = "~masterurl/custom.master";
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(fileUri.OriginalString))
{
using (SPWeb associatedWeb = site.OpenWeb())
{
string folderName = string.Empty;
for (int i = 0; i < fileUri.Segments.Length - 1; i++)
folderName += fileUri.Segments[i];
///the GetFolder function does not like it while
///the folder path begins with a '/' so we remove
///it here
folderName = folderName.Replace(
associatedWeb.ServerRelativeUrl + "/", string.Empty);
SPFolder folder = associatedWeb.GetFolder(folderName);
if (folder != null)
{
string fileName =
fileUri.Segments[fileUri.Segments.Length - 1];
SPFile f = folder.Files[fileName];
if (f.Exists)
{
///download the file and convert it to a string
byte[] file = f.OpenBinary();
System.Text.Encoding enc = System.Text.Encoding.ASCII;
string myString = enc.GetString(file);
RegexOptions options = RegexOptions.None;
Regex regex = new Regex(masterPageRegEx, options);
string result = regex.Replace(myString,
string.Format(masterPageUpdate, masterPage));
///I have found that sometimes the file ends
///up starting with '???', this will cause
///problems if you upload it like this, so
///this makes sure the file begins as it should
while (result[0] != '<')
result = result.Remove(0, 1);
///turn the file back into a byte array to we can upload it
byte[] myByteArray = new byte[result.Length];
int i = 0;
foreach (char c in result.ToCharArray())
{
myByteArray[i] = (byte)c;
i++;
}
///add the file to the folder
folder.Files.Add(fileName, myByteArray, true);
}
}
}
}
});
Stopping the ASP.Net Web Site Administration Tool adding a namespace to your web.config
0 CommentsPublished by Ciaran McAuliffe on Tuesday, December 12, 2006 at 8:52 PM.
There is a bug in ASP.NET 2.0 (I don't know if this is a problem in v1.1) which causes some things to go a bit crazy if you add the http://schemas.microsoft.com/.NetConfiguration/v2.0 namespace to the configuration node of your web.config. I don't think many people go out of their way to add this into the web.config but it can be added in by other applications, such as the ASP.Net Web Site Administration Tool.
One way to stop it from adding this in is by modifying the WebAdminPage.cs class of the ASP.Net Web Site Administration Tool (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ASP.NETWebAdminFiles\). The function below is used to save the web.config, and you will notice the NamespaceDeclared property on the Configuration is allways set to be true. This is where the problem is.
public void SaveConfig(Configuration config) {
RemotingManager.ShutdownTargetApplication();
config.NamespaceDeclared = true;
// check if session expired
if (String.IsNullOrEmpty(ApplicationPath) ||
String.IsNullOrEmpty((string)Session[APP_PHYSICAL_PATH])) {
Server.Transfer("~/home2.aspx");
}
config.Save(ConfigurationSaveMode.Minimal);
}
If you change the statement from...
config.NamespaceDeclared = true;
to
config.NamespaceDeclared = false;
...the namespace will no longer be added to the web.config. I have not found anyside side-effects to making this change.
This may also help you solve the problem in SharePoint/MOSS 2007 where you suddenly get alot of File Not Found errors on pages and errors in your Event Log looking for the Microsoft.SharePoint, Version=11.0.0.0... dll (see the following post http://www.infusionblogs.com/blogs/kguenther/archive/2006/06/27/608.aspx for more info.)
SharePoint 2007 anonymous user access permissions
0 CommentsPublished by Ciaran McAuliffe on at 8:35 PM.
I am currently working with a MOSS 2007 site which has anonymous access and uses forms authentication with the AspNetSqlMembershipProvider. For some reason anonymous users were able to get the Forms pages belonging to lists i.e. ListName/Forms/AllItems.aspx etc. I did not want anonymous users to be able to access these areas, and I expected them to be redirected to the login screen if they tried to access them. I created a site using the Publishing site definition and it had the desired functionality, but for some reason my own site definition would not obey this rule.
After some investigation it turned out that the problem was occuring because an extra permission (SPBasePermissions.ViewFormPages) had been added to the Anonymous Permission mMsk for the web, allowing anonymous users access to the Form pages. To fix the problem all I had to do was run the code below to remove the SPBasePermissions.ViewFormPages permission and reset the Anonymous Permission Mask to its default state. I am still unsure as to what added in the extra permission because my site was a direct copy of the Publishing site definition. I have a feeling it maybe related to the stsadm tool which I used to create the site and all of its configurations.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
string siteUrl = "http://mysite";
using (SPSite site = new SPSite(siteUrl))
{
SPWebCollection webs = site.AllWebs;
foreach (SPWeb web in webs)
{
using (web)
{
if (web.HasUniqueRoleAssignments)
{
web.AnonymousPermMask64 = SPBasePermissions.ViewListItems |
SPBasePermissions.ViewVersions |
SPBasePermissions.Open |
SPBasePermissions.ViewPages |
SPBasePermissions.UseClientIntegration;
}
}
}
}
});
How to impersonate a Forms user
0 CommentsPublished by Ciaran McAuliffe on Monday, December 4, 2006 at 9:24 AM.
Impersonating a Windows account can be quite easy especially if you have seen great articles such as this http://dotnetjunkies.com/WebLog/victorv/archive/2005/06/30/128890.aspx . But there is less discussion about impersonating forms users, and it took me quite a while to figure out how to do it. With a little inspiration from the FormsAuthentication, Identities and Role - based Security with a database article by Peter A. Bromberg. This is handy if you are using something like the AspNetSqlMembershipProvider. You could set this up a bit better and build a class in a similar way to Victor Vogelpoel did in the link above.
IPrincipal _originalUser = HttpContext.Current.User;
try
{
System.Web.HttpCookie c =
System.Web.Security.FormsAuthentication.GetAuthCookie
("Administrator", false);
FormsAuthenticationTicket a =
new FormsAuthenticationTicket(
LandingPageSettings.Settings.FormsUser, false, 1000);
FormsIdentity b = new FormsIdentity(a);
// Get Forms Ticket From Identity object
FormsAuthenticationTicket ticket = b.Ticket;
// Retrieve stored user-data (our roles from db)
string userData = ticket.UserData;
string[] roles = userData.Split(',');
// Create a new Generic Principal Instance
// and assign to Current User
HttpContext.Current.User = new GenericPrincipal(b, roles);
//your code goes here
}
finally
{
HttpContext.Current.User = _originalUser;
}
One of the major pain points for me in SharePoint 2003 was having to impersonate a user who had almighty powers so I could achieve some mere mortal functionality for a regular user. Usually you would end up impersonating the App Pool or putting an entry in the web.config file with a user name and password to use, and then do your magic from there. One place you would have to do this was if you wanted to check a users permissions, no, no, you can't do that, unless you have godly powers. I hoped this would be fixed in 2007, and it wasn't, but what I found out instead was far awesomerer. What I found was this Elevation of Privilege . Microsoft listened and all was good.
All you have to do is stick your code inside this block and all will be fine, your code will now run with the permissions it needs.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
// do things assuming the permission of the "system account"
});