This section shows you how to build and register a simple SSO provider, and describes exception handling for the provider.
Downloads To download the sample provider, see SharePoint Server 2007: Software Development Kit.
Example
You create an SSO provider assembly in Microsoft Visual Studio 2005 by creating a class library project. Add a reference to the Microsoft.SharePoint.Portal.SingleSignon.dll (found in the %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\12\ISAPI directory) to your project. Implement the ISsoProvider interface, as shown in the following example.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.Services;
using Microsoft.SharePoint.Portal.SingleSignon;
namespace SampleSSOProvider
{
/// <summary>
/// SimpleSSOProvider
/// </summary>
public class SimpleSSOProvider: ISsoProvider
{
public Application.ApplicationInfo[] GetApplicationDefinitions()
{
//NOTE: Used by SpsSsoProvider, not necessary for SimpleSSOProvider
throw new NotSupportedException();
}
public Application.ApplicationField[] GetApplicationFields(string AppID)
{
//NOTE: Used by SpsSsoProvider, not necessary for SimpleSSOProvider
throw new NotSupportedException();
}
public Application.ApplicationInfo GetApplicationInfo(string AppID)
{
Application.ApplicationInfo applicationInfo = new Application.ApplicationInfo("SimpleSSOProvider", "SimpleSSOProvider", Application.ApplicationType.GroupWindows, "sso@litwareinc.com");
Application.ApplicationInfo applicationInfo = new Application.ApplicationInfo("SimpleSSOProvider","SimpleSSOProvider",Application.ApplicationType.GroupWindows,"sso@litwareinc.com", (SsoCredentialContents)((Int32)SsoCredentialContents.UserName + (Int32)SsoCredentialContents.Password + (Int32)SsoCredentialContents.WindowsCredentials));
*/
return applicationInfo;
}
public Uri GetCredentialManagementURL(string AppID)
{
//NOTE: Used by SpsSsoProvider, not necessary for SimpleSSOProvider
throw new NotSupportedException();
}
public SsoCredentials GetCredentials(string AppID)
{
//Note: Used by SpsSsoProvider, necessary for any SimpleSSO Provider. Implementation discussed in detail in the next section of this topic
}
public SsoCredentials GetCredentialsUsingTicket(string Ticket, string AppID)
{
//NOTE: Used by SpsSsoProvider, necessary for Simple SSO Provider when used by Excel Services.
//TODO: Implement Ticket management code; currently just return SsoCredentials
return GetCredentials(AppID);
}
public string GetCurrentUser()
{
//NOTE: Used by SpsSsoProvider, not necessary for SimpleSSOProvider
throw new NotSupportedException();
}
public SsoCredentials GetSensitiveCredentials(string AppID)
{
//NOTE: Used by SpsSsoProvider, necessary for Simple SSOProvider when used by Excel Services
//TODO: Implement Sensitive Credential method, for sample just returning basic credentials
return GetCredentials(AppID);
}
public SsoProviderInfo GetSsoProviderInfo()
{
//TODO: Used by SpsSsoProvider, necessary for any SimpleSSOProvider
}
public string GetTicket()
{
//NOTE: Used by SpsSsoProvider, necessary for SimpleSSOProvider when used by Excel Services
//TODO: Implement Ticket management code; currently just return a string
return "No Ticket Management";
}
public void PutIdentityOnRequest(ref System.Web.Services.Protocols.HttpWebClientProtocol request, string AppID)
{
//NOTE: Used by SpsSsoProvider, not necessary for SimpleSSOProvider
throw new NotSupportedException();
}
public void PutIdentityOnRequestUsingTicket(ref System.Web.Services.Protocols.HttpWebClientProtocol request, string Ticket, string AppID)
{
//NOTE: Used by SpsSsoProvider, not necessary for SimpleSSOProvider
throw new NotSupportedException();
}
}
}
At a minimum, you must implement the GetCredentials and GetSsoProviderInfo methods. The SimpleSSOProvider class that we created returns new credentials based on the current user and the application identifier (AppID) we supplied. We can obtain information about the current user using the CurrentPrincipal property of the thread we are executing on (System.Threading.Thread.CurrentPrincipal). The following code shows the implementation of the GetCredentials method.
public SsoCredentials GetCredentials(string AppID)
{
//NOTE: Used by SpsSsoProvider, necessary for any SimpleSSOProvider
System.Diagnostics.Trace.WriteLine("Entering SimpleSSOProvider::GetCredentials");
System.Diagnostics.Trace.Indent();
// Retrieve the logged in user's information
string domain = System.Environment.UserDomainName;
System.Diagnostics.Trace.WriteLine("User domain is " + domain);
try {
System.Diagnostics.Trace.WriteLine("Context user:" + System.Threading.Thread.CurrentPrincipal.Identity.Name);
// Start building an SsoCredentials object to store two values - UserName and Password
SsoCredentials creds = new SsoCredentials();
creds.Evidence = new System.Security.SecureString[2];
switch (AppID){
case "AdventureWorks":
System.Diagnostics.Trace.WriteLine("Application is AdventureWorks");
if (System.Threading.Thread.CurrentPrincipal.IsInRole("InternalSales"))
{
System.Diagnostics.Trace.WriteLine("User is in InternalSales? " + System.Threading.Thread.CurrentPrincipal.IsInRole("InternalSales"));
// Provide components for the InternalAccess account token
creds.Evidence[0] = MakeSecureString(domain + "\\InternalAccess");
creds.Evidence[1] = MakeSecureString("pass@word1");
}
else
{
// Provide components for the ExternalAccess account token
creds.Evidence[0] = MakeSecureString(domain + "\\ExternalAccess");
creds.Evidence[1] = MakeSecureString("pass@word1");
}
break;
default:
throw new SingleSignonException(SSOReturnCodes.SSO_E_APPLICATION_NOT_FOUND);
}
// Put the UserName/Password values into the credential object
creds.UserName = creds.Evidence[0];
creds.Password = creds.Evidence[1];
System.Diagnostics.Trace.Unindent();
return creds;
}
catch(SingleSignonException ex) {
System.Diagnostics.EventLog.WriteEntry("SimpleSSOProvider", "Caught SSO Exception: " + ex.ToString());
throw;
}
catch(Exception ex) {
System.Diagnostics.EventLog.WriteEntry("SimpleSSOProvider", "Caught Exception: " + ex.ToString());
throw new SingleSignonException(SSOReturnCodes.SSO_E_EXCEPTION, ex);
}
}
The SsoProvider implementation does not require SsoCredentialsContents, but certain other client applications might expect SsoCredentialsContents. In the example provided, Excel Services will attempt to connect to resources with a Windows logon using the UserName and Password that were set. If no value was provided for WindowsCredentials, the UserName and Password would be set on the connection string.
|
Name
|
Description
|
|---|
|
None
|
No evidence provided.
|
|
UserName
|
Set if UserName exists.
|
|
Password
|
Set if Password exists.
|
|
Evidence
|
Set if using extended fields (up to five total, including UserName and Password)
|
|
MappedGroup
|
Set if application definition is a Group definition.
|
|
WindowsCredentials
|
Set if application definition is Windows Authentication.
|
The GetSsoProviderInfo method simply returns information about the provider, such as the Vendor name and Version, as shown in the following code.
public SsoProviderInfo GetSsoProviderInfo()
{
//NOTE: Used by SpsSsoProvider, necessary for any SimpleSSOProvider
SsoProviderInfo ssoProvInfo = new SsoProviderInfo();
ssoProvInfo.AssemblyName = Assembly.GetExecutingAssembly().FullName;
ssoProvInfo.Vendor = "AdventureWorks";
ssoProvInfo.Version = "1.0";
return ssoProvInfo;
}
If the SSO provider will be consumed by Excel Services, you must also provide an implementation for the GetCredentialsUsingTicket and GetTicket methods.
The SimpleSsoProvider class that we created shows a very simple example of an SSO provider. A real-life implementation must retrieve credentials from a secure repository and protect any values while they are stored in memory.
The SsoCredentials object returned by GetCredentials uses the SecureString class to store the UserName and Password properties, as well as all Evidence values. SecureString encrypts its data so it cannot be deciphered easily.
Exception Handling
Our SimpleSSOProvider throws an instance of SingleSignonException and uses standard SSOReturnCodes fields if it cannot properly determine the AppID. The following table shows some common SSOReturnCodes fields for several error cases.
|
Name
|
Description
|
|---|
|
SSO_E_ACCESSDENIED
|
Access is denied.
|
|
SSO_E_CREDS_NOT_FOUND
|
Credentials could not be found for the requested user or application.
|
|
SSO_E_SSO_NOT_CONFIGURED
|
The SSO provider service is not configured properly.
|
|
SSO_E_APPLICATION_NOT_FOUND
|
The application definition cannot be found.
|
|
SSO_E_EXCEPTION
|
The SSO provider service threw an exception.
|
Registering the Provider
To install the SimpleSSOProvider, you must register it in the global assembly cache and then register it with the ProviderAdmin console application (located in the bin directory of the Office SharePoint Server 2007 installation). The ProviderAdmin application replaces the current SSO provider with the one you specify. In a server farm environment, you must register the new SSO provider with each computer in the farm. The following procedures show you how to register the provider and how to remove a custom provider and reinstate the original.
To register the SimpleSSOProvider
To remove a custom SSO provider and reinstate the original SSO provider