Microsoft InfoPath 2010
The official blog of the Microsoft InfoPath team

Advanced server-side authentication for data connections, part 2

Advanced server-side authentication for data connections, part 2

Rate This
  • Comments 4

In the first part of this series I introduced the concepts involved in three tier authentication. Now let's drill into the details and work with some code.

 

Using Office Single Sign-on  with individual mapping

 
An Office Single Sign-on (SSO) application definition, can be set up in one of three ways:  individual, group, or group using restricted credentials.  An InfoPath form published to the server can use either of the first two.  However, in order to use individual credentials, the SSO database must contain a separate username and password for each user who connects to the form.  A typical server application would check whether the connecting user had credentials in the database, and redirect to a credentials management page when appropriate to allow the user to enter their credentials.  While InfoPath Forms Services does not do this generically for forms that use SSO, it’s possible to implement a solution for an individual form or a set of forms the same way an Office Server application would, by using the Pluggable SSO API.
 
The general approach is to have users link to an ASP.NET page rather than directly to the form.  The ASP.NET page attempts to get the user’s credentials from the SSO database, and based on the result either redirects to the form or to a credential management page  which allows the user to input their credentials.
 
Enough talk.  Let’s get our hands dirty.
 
My code assumes that you have defined an SSO application definition called MyApp and that the application is set up to use individual credentials.  I also assume that that have an administrator-approved form template called myform.xsn activated on the site collection, and that the form uses one or more data connections that reference the MyApp application.
 
In order to use SSO to make the data connection, you must be using data connection settings in a UDC file on the server.  To add the reference to the MyApp app definition, you add an Authentication element to the UDC file.  The authentication element must be the last subelement of the ConnectionInfo element, and it looks like this:
 
<udc:Authentication>
  <udc:SSO AppId="MyApp" CredentialType="NTLM"></udc:SSO>
</udc:Authentication>
 
To create the redirector page, the first thing is to add a new ASP.NET page to the root site of your SharePoint server.  Find the home directory of your root site by opening up Internet Services Manager and checking the Home Directory page of the properties page for the web application.  Open this web in Visual Studio and add a new ASP.NET page.  In the properties  for the page, enable session state.  Finally, add a reference to the Microsoft.SharePoint.Portal.SingleSignon namespace.
 
Once this is done, the new page should look like this:
 
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SingleSignonRedirector.aspx.cs" Inherits="SingleSignonRedirector" EnableSessionState="True" %>
<%@ Import Namespace="Microsoft.SharePoint.Portal.SingleSignon" %>
 
Open the code file for the page, and add a using statement for the SingleSignon namespace
 
using Microsoft.SharePoint.Portal.SingleSignon;
 
The code itself is relatively straightforward.  Start by using the pluggable API to get a reference to the installed SSO provider.
 
ISsoProvider provider = SsoProviderFactory.GetSsoProvider();
 
(this call will fail if no provider is installed, or if the Single Signon service is not running)
 
Your page will run under the credentials of the user attempting to access the form, so when you call GetCredentials, SSO will return a credential for that user, or throw SingleSignonCredsNotFoundException if the credential does not exist.
 
try
{
   SsoCredentials credentials = provider.GetCredentials("MyApp");
}
catch (SingleSignonCredsNotFoundException)
 
In the event that the credentials are not found, you can get the URL of the credentials management page for the installed provider.
 
Uri CredentialsManagementUrl = provider.GetCredentialManagementURL("MyApp");
 
Now, at this point you could simply redirect to the credentials management URL.  However, you would miss part of the magic of the credentials management page.  The credentials management page supplied with the Office single Sign-on provider will redirect back to the referring page once the user has entered valid credentials.  I chose to handle this by presenting a link to the user to allow them to click through to the credentials management page.
 
Response.Write("<P>Before you can access this form, you must enter credentials to access backend data.</P>");
Response.Write("<P><A href=\"" + CredentialsManagementUrl.ToString() + "\">Click here to enter your credentials</A></P>");
Response.End();
 
An alternate approach could be to add the HTTP referer header to the response before performing a redirect.  Either way, once the user has entered their credentials, the redirector page will be called again.  This time the GetCredentials call will succeed, and the page will redirect on to the form.
 
Here’s the complete code-behind for the page:
 
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.SharePoint.Portal.SingleSignon;
 
public partial class SingleSignonRedirector : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ISsoProvider provider = SsoProviderFactory.GetSsoProvider();
        try
        {
            SsoCredentials credentials = provider.GetCredentials("MyApp");
        }
        catch (SingleSignonCredsNotFoundException)
        {
            Uri CredentialsManagementUrl = provider.GetCredentialManagementURL("MyApp");
            Response.Write("<P>Before you can access this form, you must enter credentials to access backend data.</P>");
            Response.Write("<P><A href=\"" + CredentialsManagementUrl.ToString() + "\">Click here to enter your credentials</A></P>");
            Response.End();
        }
        catch (Exception ex)
        {
            Response.Write("<P>Single Sign-on returned an error:  " + ex.Message + "</P>");
            Response.End();
        }
 
        // Good to go - on to the form
Response.Redirect( "http://myserver/formservertemplates/myform.xsn?openin=browser" );
       
    }
}
 
Getting jiggy with it
For a real-world application, there are a few more things I might do to this page to round out the implementation.  Depending on the needs of the specific application, one or more of the following might apply:
 
  • Loop through multiple Application IDs to allow the user to enter credentials for each
  • Attempt to log on the user using the SSO credentials to verify that the credentials are valid and have not expired
  • Use this code in a page which hosts the form in question using the XmlformView control
  • Create a generic page which takes the URL to the form and the Application ID as query parameters
With a little bit of ingenuity, you can use this approach to create a seamless end-to-end experience to satisfy any scenario.
 
In my next and final post in this series, I'll talk about how to use a web service proxy for authentication. Stay tuned!
 
- Nick
Program Manager
Leave a Comment
  • Please add 5 and 2 and type the answer here:
  • Post
  • This is the final segment of my three part series. In the first part of this series I introduced the...
  • Recently lots of Microsoft partners and customers are interest in the Form Server/Form Services in MOSS

  • Hi, It&#39;s been a while since I posted. As you may imagine, July wasn&#39;t the most popular month

  • I have been trying to figure out how to handle the SingleSignonCredsNotFoundException that you wrote about.  I thought your code would work nicely in my .aspx page, but I'm getting an error page instead:

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.Runtime.InteropServices.COMException: Cannot complete this action.

    [COMException (0x80004005): Cannot complete this action.

    Please try again.]

    Until I get this exception handling to work, I will keep getting this error:

    [SingleSignonCredsNotFoundException: A call into SPS Single Sign-on failed. The error code returned was '-2140995583'.]

Page 1 of 1 (4 items)