none
How to set custom access denied pages in SharePoint 2013?

    General discussion

  • Hi everybody,

    in SharePoint 2010 custom access denied or other error pages could be easily set by setting the new path to the webapp-properties by using webApp.UpdateMappedPage. In SharePoint 2013 this seems to be ignored. The MSDN-entry seems to be out of date and just copied from SharePoint 2010: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebapplication.updatemappedpage.aspx

    A possible workaround could be writing a HttpModule that checks the requested url for accessdenied.aspx and redirects to a custom page but there must be another more best practice way to achieve this behaviour??


    • Edited by LoneSurvivor82 Wednesday, April 24, 2013 12:31 PM
    • Changed type LoneSurvivor82 Monday, April 29, 2013 8:41 AM I think, this topic is worth to start a discussion about it...
    Wednesday, April 24, 2013 12:30 PM

All replies

  • I found a workaround to redirect to a custom access denied page but I'm not happy with it.

    I created a HttpModule which uses static method SPCustomRedirect.RegisterRedirectHandler to register a class inheriting ISPCustomRedirectHandler to the current HttpContext. In this class there is a method GetRedirectUrl that returns the path to my custom access denied page.

    Now at last a value must be written to the HttpRequest.Querystring named "CustomRedirect". But to add something to the QueryString-NameValueCollection I must use reflection to make it writable because it's readonly. After setting the value, I reset the property to readonly.

    For clearness, I post the code-snippet from the HttpModule below:

    HttpRequest request = HttpContext.Current.Request;
    
    NameValueCollection QS = request.QueryString;
    QS = (NameValueCollection)request.GetType().GetField("_queryString", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(request);
    PropertyInfo readOnlyInfo = QS.GetType().GetProperty("IsReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
    readOnlyInfo.SetValue(QS, false, null);
    QS["CustomRedirect"] = "CustomAccessDenied";
    readOnlyInfo.SetValue(QS, true, null);
    
    SPCustomRedirect.RegisterRedirectHandler("CustomAccessDenied", new CustomAccessDenied());  

    This is the redirectHandler-class I register in the last line:

    public class CustomAccessDenied : ISPCustomRedirectHandler
    {
        public string GetRedirectUrl(string key)
        {
            string serverRelativeUrl = string.Empty;
    
            var ctx = HttpContext.Current.Items["DefaultSPContext"];
            if (ctx != null)
            {
                serverRelativeUrl = ((SPContext)ctx).Web.ServerRelativeUrl;
    
                if (serverRelativeUrl.Equals("/"))
                {
                    serverRelativeUrl = string.Empty;
                }
            }
                	
            return string.Format("{0}/_layouts/15/myCode/CustomAccessDenied.aspx", serverRelativeUrl);
        }
    }

    This works fine but I really don't like the need to add a value to the querystring by reflection or the need to do this for every page-request...

    What's your opinion for this?

    Thursday, April 25, 2013 12:43 PM
  • Hi, i have the same problem assigning a custom access denied page. Can you please provide your solution with the httphandler? I want to take look if it works for me. I find it also not so good to use a httphandler on all page loads, but if nothing other works it could a good work around.

    What does the others think about the idea?

    Tuesday, June 04, 2013 7:11 PM
  • This is an identified issue and will hopefully be resolved in a future hotfix. Here are the results of my findings:  http://blog.randomdust.com/index.php/2013/07/custom-access-denied-page-in-sharepoint-2013/

    http://blog.randomdust.com

    Thursday, July 04, 2013 6:13 AM
  • Hi LoneSurvivor82,

    The SPCustomRedirect.RegisterRedirectHandler doesn't work in my code. The redirect is not done. The method context_BeginRequest is being called becouse I can debbug it, but implementation of ISPCustomRedirectHandler is not.

    When I try to call HttpContext.Current.Response.Redirect I'm getting 403 error, becouse user doesn't have permissions to display the page. I need to redirect to the same site coll(http://server/sites/test ->http://server/sites/test/_layouts/15/MyAccessDenied.aspx) not to the host (http://server/_layouts/15/MyAccessDenied.aspx). The user can reach http://server/_layouts/15/MyAccessDenied.aspx but doesn't have permissions for http://server/sites/test/_layouts/15/MyAccessDenied.aspx.

    Do you have any sugestions what might be wrong?

    Wednesday, September 25, 2013 3:39 PM
  • I've fixed 403 error.

    My custom page that is placed in layouts folder inherits(code behind) from Microsoft.SharePoint.ApplicationPages.AccessDeniedPage and now user can display it even it doesn't have permissions for the site coll.

    SPCustomRedirect.RegisterRedirectHandler doesn't work for me, but I do a typical HttpContext.Current.Response.Redirect and it works.


    • Edited by Kamil_F Thursday, September 26, 2013 3:15 PM
    Thursday, September 26, 2013 3:14 PM
  • Hi, I don't quite understand what you're doing here. Where have you put the first snippet? When is that running? Thanks

    Friday, April 11, 2014 11:20 AM
  • I can confirm that the issue with the SPCustomLayouts custom AccessDenied not taking effect has been fixed in the April 2014 CU - http://www.toddklindt.com/blog/Regressions/SP2013Apr2014CU.aspx. I was able to successfully apply a custom Access Denied page:

    I created and successfully applied the custom Access Denied page to each of the web applications via the following steps:

    1. Create the \CustomPages folder and Custom File in the Path Specified, Copy to Each WFE Server:
    c:\Program files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\CustomPages\CustomAccessDenied.aspx

    2. PowerShell Command Used to Apply Setting:Set-SPCustomLayoutsPage –Identity "AccessDenied" –RelativePath "/_layouts/15/custompages/CustomAccessDenied.aspx" -WebApplication "http://<web application URL>" 

    3. PowerShell to Review Custom Layouts Pages Applied:
    Get-SPCustomLayoutsPage –WebApplication "http://<web application URL>" 

    No IISReset or other cycling of service should be necessary. When you now get sent to the AccessDenied.aspx it will be serving the contents of the custom page you've created dynamically.

    Please note the regressions in that CU and balance against your requirements accordingly.


    Keith Tuomi | Twitter: @itgroove_keith | Blog: http://yalla.itgroove.net

    Please click "Propose As Answer" if a post solves the problem or "Vote As Helpful" if a post has been useful to you.

    Monday, July 07, 2014 10:27 PM
  • Watch which UI your site is using. With the recent CUs (April 2014 and beyond), I've been able to get Set-SPCustomLayoutsPage to work for AccessDenied in a 2013 UI site, but not a 2010 UI site.
    Wednesday, August 20, 2014 7:33 PM
  • As it turns out, the question about the UI is quite important. If your site is using the 2013 UI, you're fine: By default Get-SPCustomLayoutsPage, Set-SPCustomLayoutsPage, and Microsoft.SharePoint.Administration.SPWebApplication.UpdateMappedPage(...) work with a CompatibilityLevel = 15. That's right, CompatibilityLevel! There is an undocumented parameter on these cmdlets and method (presumably added with the April 2014 CU). If your site is using the 2010 UI, you'll need to specify a CompatibilityLevel = 14 when using these cmdlets or method. Just be sure to give the correct path for the correct hive/UI: The path must start with "/_layouts/15/" for the 2013 UI (CompatibilityLevel = 15, or omitted), and must start with "/_layouts/" for the 2010 UI (CompatibilityLevel = 14).

    Just be sure you deploy your custom pages to both hives. For me, I had packaged the pages in a farm solution. Just needed to deploy the pages to both hives by specifying CompatibilityLevel = All when executing Install-SPSolution. (Unfortunately, there's no way to do this from the deployment in CA.)

    Of course, this means you are able to have different pages for each of the mapped pages for each of the hives. Want one Access Denied page for the 2010 UI and a different one for the 2013 UI? No problem!

    Wednesday, August 20, 2014 9:49 PM
  • It did not work for me until I did an IISRESET
    Thursday, July 14, 2016 9:11 PM
  • Hi,

    Similar issue here on SP2013 server.

    I've ran 

     Get-SPCustomLayoutsPage -WebApplication "http://webappNAME.net/"

    Page RelativePath                                                 
     ---- ------------                                                 
    AccessDenied /_layouts/15/custompages/Custom_AccessDenied.aspx               
    Confirmation                                                              
    Error                                                              
    Login                                                              
    RequestAccess /_layouts/15/custompages/Custom_AccessDenied.aspx               
    Signout                                                              
    WebDeleted   

    Still, when a user with no access hits the site, gets redirected to regular AccessDenied.aspx page.

    I've ran IISRESET and same result.

    My SP DB is beyond the April 2014 CU  everyone is suggesting. 

    The SET command i've used:

     Set-SPCustomLayoutsPage -webapplication "http://webappNAME.net/" -Identity AccessDenied -RelativePath "/_layouts/15/custompages/Custom_AccessDenied.aspx" -CompatibilityLevel 15

    Suggestions?

    Thanks

    Thursday, September 29, 2016 1:52 AM