SharePoint Developer Support Team Blog

The Official blog of the SharePoint Developer Support Team

November, 2012

  • HOW TO: Prevent users from pressing back button after signing out from a SharePoint site

    This blog post is a contribution from Charls Tom Jacob, an engineer with the SharePoint Developer Support team.

    Scenario:

    In SharePoint, the sign out is complete only when you actually close the browser window.  As shown below, SharePoint asks you to close the browser after sign out: “You must close your browser to complete the sign out process”.  If the browser is Internet Explorer, it goes an extra mile showing the confirmation box to close the current window and closes it if you say yes.  This is done by calling the window.close() JavaScript function on the page load.

    image

    But that’s not the case with other browsers (Firefox, Chrome etc.,), which does not allow closing the window using script.  Again, IE leaves it to the user to decide whether to close the window or not.

    Problem:

    You might be using your SharePoint site to store any sensitive information like order/purchase details or even credit card numbers, or anything that’s confidential.  You have wide variety of users who are technical and non-technical, who access the site from the intranet/extranet or from public internet cafes.  Suppose the user is viewing or editing some items and decides to sign out of the site, without bothering to close the browser window, anyone can get to the previous page simply by pressing the browser back button, leaving the sensitive data open to others.

    This happens as the page is served from the browser cache and not loaded from the server.  If you reload the page, SharePoint senses that you have logged out of the site and takes you to the login page.  Of course caching is a good thing as it helps to serve the pages faster, but this is a downside as it’s controlled by the browser and not the server.

    Solution:

    Now coming back to the title of the blog, most easy solution would be to prevent users from pressing the back button – ultimately to disable it!  But that’s not going to be very easy, you may find ‘n’ number of techniques claiming to do that but none of them would serve the purpose across different browsers.

    So in the SharePoint context (rather ASP.NET), solution is to develop a custom master page and a few lines of code, instructing the browser not to cache the page.  When the page is not cached, browser will force itself to send a request to the server each time the page is requested.  You many not want to do this for all the pages/sites as it again impacts performance.

    Here I won’t be going into the details of how to set the master page dynamically, but use a custom master page on a site, that does no cache, hence “secures” your data after a sign out.

    Steps:

    1. Created a master page using Visual Studio.  Call it NoCache.master.

    2. To preserve the look and feel, copy the contents from your site master page (Download the master page from the master page gallery).

    3. Modify the Master tag as below:

    <%@ Master language="C#" Inherits="MasterPageWithCodeBehind.MasterPageModule.NoCache, MasterPageWithCodeBehind, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ea0870212dba35bb" %>

    4. Implement the code-behind as below:

    namespace MasterPageWithCodeBehind.MasterPageModule
    {
        public class NoCache : MasterPage
        {
            protected System.Web.UI.HtmlControls.HtmlGenericControl divRibbonContainer;
     
            protected void Page_Load(object sender, EventArgs e)
            {
                // IE
                Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
     
                // Others
                Response.Cache.SetNoStore();
     
                Response.Write("This is a custom master page that prevents caching!!");
            }
        }
    }

    This code instructs the browser not to cache the page.

    5. Deploy this master page and set it as your site’s default master page.

    6. Sign out from the SharePoint site, press back button.  You will be taken to the SharePoint login page, instead of the last page you visited!

    Again, this is not “the best” way to accomplish this, of course as we will be missing out on the goodness that caching has to offer.  But this is one of the ways!

    Hope you found this helpful Smile

  • HOW TO: Customizing SharePoint AppWeb web template

    This blog post is a contribution from Mustaq Patel, an engineer with the SharePoint Developer support team.

    SharePoint Apps provides a great deal of flexibility and how much we can do with it. Using WebTemplate we can direct AppWeb (the SPWeb under which the App is hosted) to use any other Site Template instead of out of box “App” SiteTemplate.

    All restrictions and other attributes that applies to WebTemplate in SharePoint 2010 or SharePoint 2013 sites, applies to WebTemplate in SharePoint Apps. 

    For information on WebTemplate in SharePoint apps see below article

    http://msdn.microsoft.com/en-us/library/fp179925(v=office.15).aspx

    For WebTemplates in SharePoint 2010 see below article

    http://blogs.msdn.com/b/vesku/archive/2010/10/14/sharepoint-2010-and-web-templates.aspx#webtemplate

    For this walkthrough we will apply Team Site (STS#1) template to Appweb that gets provisioned when SharePoint hosted app is deployed in onprem. Below are the steps

    1. Create a SharePoint hosted App project using VS2012.
    2. Right click the project in Solution Explorer and click > Add new item > Empty Element.  Name it “CustomWebTemplate”.
    3. Go to \15\TEMPLATE\SiteTemplates\sts\xml and copy the ONET.xml file and paste it in the CustomWebTemplate folder that is created in the project as a result of the above step.
    4. Include the onet.xml to the project, make sure the deploymentType is ‘ElementFile’ in onet.xml’s properties window.
    5. Open onet.xml and we will start modifying it as below:
      1. Remove all <Configuration></Configuration> but the one with ID=0.  In WebTemplate we can only have Configuration with ID=0.
      2. Remove all <modules></modules>.  There should be no <modules> in a webtemplate.
      3. Remove <serverEmailFooter>
    6. Open the Elements.xml of CustomWebTemplate and paste below xml:
    7. Note that BaseTemplateName is the internal name of the site definition on which the web template ultimately derives.  This is the value of the Name attribute of the template element in WebTemp*.xml file.  BaseTemplateID is the value of the ID attribute of the template element in a WebTemp*.xml file.
    8. Right click AppManifest.xml and click > View Code.
    9. Before </Properties> copy below xml.
    10. Change FeatureId as per yours, it’s the ID of the feature that deploys the WSP in an App.  You can get it by double clicking the .feature file in Features folder.  This properties window has Feature ID.
    11. Also change the ID value in step 9 as per yours.  It’s the combination of Feature ID that you got in step 10 and Name of the WebTemplate in WebTemplate element in step 6.  Separate it with a hash symbol ( # ), also note the curly brackets ( {} ).
    12. Save all changes and deploy the app.  Once deployed browse the app.  You will notice that the App is now using team site template instead of App template.  You will see familiar quick navigation and site settings.

    clip_image002

    Hope this helps!

  • RunWithElevatedPrivileges does not work with UserProfile API

    This blog post is a contribution from Aaron Miao, an engineer with the SharePoint Developer Support team.

    RunWithElevatedPrivileges executes the specified method with Full Control rights even if the user does not otherwise have Full Control. This is not true for User Profile API.

    To reproduce, with code below in a web part:

    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        using (SPSite site = new SPSite("http://yourserver/"))
        {
            try
            {
                SPServiceContext context = SPServiceContext.GetContext(site);
                ProfileSubtypeManager psm = ProfileSubtypeManager.Get(context);
                string subtypeName = ProfileSubtypeManager.GetDefaultProfileName(ProfileType.Organization);
                ProfileSubtype subType = psm.GetProfileSubtype(subtypeName);
                OrganizationProfileManager opm = new OrganizationProfileManager(context);
                OrganizationProfile parentOrg = opm.RootOrganization;
                OrganizationProfile profile = opm.CreateOrganizationProfile(subType, parentOrg); // Requires privileges
                profile.DisplayName = "Test Group " + DateTime.Now.ToString("MMMM dd H mm ss");
                UserProfileManager upm = new UserProfileManager(context);
                UserProfile userProfile = upm.GetUserProfile(true);
                profile.AddMember(userProfile.RecordId, OrganizationMembershipType.Leader);
                profile.Commit();
            }
            catch(Exception ex)
            {
                string err = ex.StackTrace;
            }
        } 
    });

    If the user, regardless the user is farm administrator or site administrator or normal user, who runs the code is not in User Profile Service Application (UPA) Administrators and does not have “Manage Profiles” permission, the code will throw exception below:

    Attempted to perform an unauthorized operation.
    at Microsoft.Office.Server.UserProfiles.OrganizationProfileManager.CreateOrganizationProfile(ProfileSubtype subtype, ProfileBase parentProfile)

    at UserProfileTestWP.UPATestWebPart.UPATestWebPart.<btn_Click>b__0()

    SharePoint requires a user or group to be added to Administrators for User Profile Service Application with “Manage Profiles” permission (shown below like test1) in order to peroform the task like above in code sample.

    image

    Workaround

    In case your business needs require users apart from Administrators for User Profile Service Application to be able to create organization profiles (not sure why you’d want that though), the workaround is to set HttpContext.Current to null like code below.

    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        HttpContext httpCtx = HttpContext.Current;
        HttpContext.Current = null;
     
        using (SPSite site = new SPSite("http://yourserver/"))
        {
            // code omitted here
        } // end of using
        HttpContext.Current = httpCtx;
    });

    The workaround makes the service account of User Profile Service Application to execute the code. The service account should be in Administrators for User Profile Service Application with Full Control permission.

    Setting Network Service as service account of User Profile Service Application may not work.