Whether you love or hate InfoPath forms, they occasionally do make things easier. However, the form viewer page comes from the FormServerPage type, which inherits directly from System.Web.UI.Page, meaning that it permits anonymous users to view the page and, consequentially, your form. None of the SharePoint access permissions, aside from folder-level permissions have any affect. Unfortunately, the page is located in the root layouts folder, so changing those permissions aren’t possible. You can, of course, set permissions to the Forms Library where your form lives, but that doesn’t keep the user from getting to the page and getting a particularly obtuse error message and no navigation to get back.
But what if you want to secure this page? Say you have an application that you want only authenticated users to access, how would you do it?
The short answer is to control all links on your site and force everyone through Authenticate.aspx, which will require the user to log in if they haven’t already. That’s the easy part and it makes sound logical sense. You need the user authenticated, so force them through the authentication routine. SharePoint’s authentication routine is pretty standard and one of three things can happen once you send the user through Authenticate.aspx:
- If the user is already logged in, they continue on to your page unabated
- If the user isn’t logged in, they must log in and then they’re redirected to your page
- If the user refuses to log in, they get to see the Access Denied page
That’s all well and good, but the tricky part of the authentication routine is getting the parameters for Authenticate.aspx correct so the user is redirected appropriately. Specifically, Authenticate.aspx has a Source parameter that sets where the user gets redirected to once they’re authenticated. Because URLs are very sensitive, this isn’t just your garden variety link, it’s been URL encoded instead.
URL encoding takes all of the sensitive URL parts (? & / < >) and converts them to their hexadecimal equivalents. If this encoding weren’t done, the browser would get confused as to which page to request. To avoid browser confusion and gnashing of teeth by users, we’ll need to use URL encoding.
All of this is made worse, however, by the fact that the FormServer.aspx page has its own Source parameter to set where to redirect the user once they leave the form. This URL is also URL encoded. Thankfully, the .NET framework has a class in the System.Web namespace called HttpUtility that provides a UrlEncode method to do most of the heavy lifting for you. Still, it’s not as simple as calling UrlEncode and that’s it. We’ll work backwards towards the solution.
The first step is to determine where you want your users to end up after they’ve submitted or closed the form. Usually this is just your home page (i.e. http://site/Pages/default.aspx). You can include this entire URL as the redirect parameter, but you can take advantage of not leaving the web application to shorten it to a relative URL instead (i.e. /Pages/default.aspx).
Once you know where you want the user to go after they’re done with your form, you need to take that URL and pass it through HttpUtility.UrlEncode. This will give you the value for the Source parameter to FormServer.aspx. For the case we’re working with, it’s:
Now that you’ve got your Source parameter for FormServer.aspx, you need to open the form on the FormServer.aspx page in your browser and replace the existing Source parameter with your new Source parameter and Go to that page. Make sure to test that you can submit/close the form and that you get redirected to the page you replaced and not the original page.
Take this new relative URL for the FormServer.aspx page (i.e. /_layouts/FormServer.aspx?XsnLocation=/FormServerTemplates/AuthorApplication1.xsn&Source=%2fPages%2fdefault%2easpx) and, for this URL to pass through Authenticate.aspx correctly, we need to really understand what happens behind the scenes during a SharePoint authentication check. Authenticate.aspx actually gets loaded twice. So one call to HttpUtility.UrlEncode will not suffice and you’ll end up getting to FormServer.aspx but your parameters will be screwed up. So you need to do two calls to HttpUtility.UrlEncode, passing in the result of the first call into the second.
The end result should look something like this:
Now, you can use that as the Source parameter for a call to Authenticate.aspx, leaving you with a link that looks like:
There you have it! Provided you control the links on your own site, you can force users to authenticate before accessing your InfoPath forms. Of course, this approach works for all pages, not just InfoPath forms.