Tutorial: implementación de un proveedor de SSO conectable

De forma predeterminada, Microsoft Office SharePoint Server 2007 ofrece el servicio de inicio de sesión único (SSO) de Microsoft para el almacenamiento y la asignación de credenciales para su uso en las conexiones a sistemas back-end o de terceros. Muchas compañías ya han desarrollado un sistema de almacenamiento de credenciales interno o usan una solución distinta del servicio de inicio de sesión único de Microsoft. Como una alternativa al mantenimiento de la asignación de credenciales en dos lugares, Office SharePoint Server 2007 ofrece un mecanismo llamado SSO conectable. Esta característica permite especificar un proveedor de SSO alternativo en lugar del proveedor de SSO estándar en Office SharePoint Server 2007.

Requisitos previos

Antes de compilar el proveedor de SSO, debe configurar el entorno. Este tutorial supone que ya ha configurado Office SharePoint Server 2007, ha instalado una copia de la base de datos AdventureWorks 2000 del Centro de descarga de Microsoft, y se ha asegurado de que el nombre de dominio sea LITWAREINC. Si está utilizando un nombre de dominio diferente, deberá ajustar los ejemplos de código de este tutorial.

Se supone que los grupos y cuentas de dominio que figuran en la siguiente tabla están presentes.

ExternalPartners

Grupo de dominio

InternalSales

Grupo de dominio

Tom Tompson

Usuario del dominio

Jerry Jones

Usuario del dominio

InternalAccess

Usuario del dominio

ExternalAccess

Usuario del dominio

Para obtener instrucciones completas sobre cómo configurar la base de datos y las cuentas de usuario necesarias, consulte el archivo README.txt suministrado con la base de datos AdventureWorks 2000.

Implementación de un proveedor de inicio de sesión único

El reemplazo del proveedor de SSO predeterminado en Office SharePoint Server 2007 implica la implementación de la interfaz Microsoft.SharePoint.Portal.SingleSignon.ISsoProvider****, mediante su instalación en la memoria caché de ensamblados global y el registro del nuevo proveedor de SSO con Office SharePoint Server 2007.

Sólo se puede registrar un proveedor de SSO para Office SharePoint Server 2007. Al registrar un nuevo proveedor de SSO, se reemplaza la clase predeterminada SpsSsoProvider en Office SharePoint Server 2007. Debido a que sólo puede haber un proveedor de SSO en uso en un determinado momento, se recomienda que detenga el servicio de inicio de sesión único de Microsoft cuando use un proveedor de SSO personalizado.

Será necesario implementar los métodos GetCredentials y GetSsoProviderInfo de la interfaz ISsoProvider para crear un proveedor de SSO mínimamente funcional. Este tutorial muestra cómo crear un proveedor de SSO simple y usarlo para obtener acceso a los datos a través del Catálogo de datos profesionales.

En este tutorial, el proveedor de SSO personalizado asigna los usuarios que se encuentran en el grupo InternalSales a la cuenta de usuario InternalAccess para recuperar datos de producto de la base de datos AdventureWorks 2000.

Creación del proveedor

Esta sección muestra cómo crear y registrar un proveedor de SSO simple y describe el control de excepciones para el proveedor.

Descargas    Para descargar el proveedor de ejemplo, consulte SharePoint Server 2007: Kit de desarrollo de software.

Ejemplo

Se puede crear un ensamblado de proveedores de SSO en Microsoft Visual Studio 2005 mediante la creación de un proyecto de biblioteca de clases. Agregue una referencia a Microsoft.SharePoint.Portal.SingleSignon.dll (que se encuentra en el directorio %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\12\ISAPI ) a su proyecto. Implemente la interfaz ISsoProvider como se muestra en el ejemplo siguiente.

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();
        }
    }
}

Como mínimo, debe implementar los métodos GetCredentials y GetSsoProviderInfo. La clase SimpleSSOProvider creada devuelve nuevas credenciales basadas en el usuario actual y el identificador de aplicación (AppID) suministrado. Podemos obtener información sobre el usuario actual con la propiedad CurrentPrincipal property del subproceso que estamos ejecutando en (System.Threading.Thread.CurrentPrincipal). En el código siguiente se muestra la implementación del método GetCredentials.

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);
    }
}

La implementación de SsoProvider no requiere SsoCredentialsContents, pero es posible que algunas aplicaciones cliente esperen SsoCredentialsContents. En el ejemplo proporcionado, Excel Services intentará conectarse a los recursos con un inicio de sesión de Windows que usa los valores de UserName y Password que se establecieron. Si no se suministró ningún valor para WindowsCredentials, UserName y Password se establecerán en la cadena de conexión.

Nombre Descripción

None

No se suministró evidencia.

UserName

Establece si existe UserName.

Password

Establece si existe Password.

Evidence

Establece si se usan campos extendidos (hasta un total de cinco, incluidos UserName y Password)

MappedGroup

Establece si la definición de aplicación es una definición de Group.

WindowsCredentials

Establece si la definición de aplicación es Autenticación de Windows.

El método GetSsoProviderInfo simplemente devuelve información sobre el proveedor, como el nombre de proveedor y la versión, como se muestra en el siguiente código.

        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;
        }

Si Excel Services consumirá el proveedor de SSO, también deberá proporcionar una implementación para los métodos GetCredentialsUsingTicket y GetTicket.

La clase SimpleSsoProvider creada muestra un ejemplo muy sencillo de un proveedor de SSO. Una implementación de la vida real debe recuperar las credenciales de un repositorio seguro y proteger los valores mientras están almacenados en memoria.

El objeto SsoCredentials devuelto por GetCredentials usa las propiedades de la clase SecureString para almacenar las propiedades de UserName y Password, así como todos los valores de Evidence. SecureString cifra los datos de manera que no puedan descifrarse fácilmente.

Control de excepciones

El proveedor SimpleSSOProvider genera una instancia de SingleSignonException y usa campos SSOReturnCodes estándar si no se puede determinar correctamente AppID. En la siguiente tabla se muestran algunos campos SSOReturnCodes comunes para varios casos de error.

Nombre Descripción

SSO_E_ACCESSDENIED

Se ha denegado el acceso.

SSO_E_CREDS_NOT_FOUND

No se encontraron las credenciales para el usuario o aplicación solicitados.

SSO_E_SSO_NOT_CONFIGURED

El servicio del proveedor de SSO no está configurado correctamente.

SSO_E_APPLICATION_NOT_FOUND

No se puede encontrar la definición de la aplicación.

SSO_E_EXCEPTION

El servicio del proveedor de SSO generó una excepción.

Registro del proveedor

Para instalar SimpleSSOProvider, debe registrarlo en la memoria caché de ensamblados global y, a continuación, registrarlo con la aplicación de consola ProviderAdmin (ubicada en el directorio Bin de la instalación de Office SharePoint Server 2007. La aplicación ProviderAdmin reemplaza el proveedor de SSO actual con el especificado. En un entorno de granja de servidores, debe registrar el nuevo proveedor de SSO con cada uno de los equipos de la granja de servidores. Los procedimientos siguientes muestran cómo registrar el proveedor y cómo quitar un proveedor personalizado y restablecer el original.

Para registrar SimpleSSOProvider

  • La herramienta ProviderAdmin toma el nombre completo del ensamblado y el nombre de la clase que implementa la interfaz ISsoProvider. Para registrar SimpleSSOProvider en este ejemplo, la herramienta ProviderAdmin ejecuta el comando siguiente.

    Microsoft.SharePoint.Portal.SingleSignon.ProviderAdmin.exe 
    "SampleSSOProvider, Version=1.0.0.0, Culture=neutral, 
    PublicKeyToken=e447e624e7099fd1" 
    "SampleSSOProvider.SimpleSSOProvider"
    

Para quitar un proveedor de SSO personalizado y restablecer el proveedor de SSO original

  • Para quitar un proveedor personalizado de SSO y restablecer el proveedor de SSO original en Office SharePoint Server 2007, anule el registro del proveedor de SSO mediante el comando siguiente.

    Microsoft.SharePoint.Portal.SingleSignon.ProviderAdmin.exe /u
    

Acceso al proveedor de inicio de sesión único

Los elementos web u otros componentes que necesitan tener acceso a un proveedor de SSO ya no deberían usar el objeto Credentials. El uso del objeto Credentials sólo recupera el proveedor de SSO predeterminado que se incluye con Office SharePoint Server 2007, incluso si se ha registrado un nuevo proveedor mediante la herramienta ProviderAdmin. Para obtener una referencia a ISsoProvider actualmente registrado, use el siguiente procedimiento.

Para obtener una referencia al proveedor de SSO actualmente registrado

  • Use el método GetSsoProvider en la clase SsoProviderFactory para obtener una referencia al ISsoProvider actualmente registrado. El código puede usar el método GetCredentials en la interfaz ISsoProvider para obtener las credenciales de la aplicación, de la siguiente manera.

    ISSOProvider issop;
    issop = SsoProviderFactory.GetSsoProvider();
    SsoCredentials ssocred = issop.GetCredentials("AdventureWorks");
    

La clase SsoCredentials proporciona acceso a las credenciales a través de la clase SecureString. Se pueden usar varios métodos diferentes para convertir una instancia de SecureString a un formato que se pueda usar, como el método SecureStringToBSTR tal como se muestra en el siguiente ejemplo.

ISsoProvider provider = SsoProviderFactory.GetSsoProvider();
SsoCredentials creds = provider.GetCredentials("AdventureWorks");
IntPtr pUserName = IntPtr.Zero;
try
{
pUserName = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(creds.UserName);
//NOTE: After this has been converted to a String object, it remains in 
//memory until the garbage collector collects it.
String userName = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(pUserName);
}
finally
{
// Free zero out and free the BSTR pointers.
if (IntPtr.Zero != pUserName)
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(pUserName);
}
}

Uso del proveedor de inicio de sesión único desde el Catálogo de datos profesionales

Además del acceso que se dispone desde los elementos web al proveedor de SSO predeterminado, también se puede usar el proveedor de SSO personalizado desde aplicaciones registradas del Catálogo de datos profesionales.

Para usar el proveedor de SSO personalizado con el Catálogo de datos profesionales

  • Para usar un proveedor de SSO personalizado con un sistema de línea de negocio (LOB) de base de datos, modifique el esquema del Catálogo de datos profesionales para agregar las propiedades SsoApplicationId y SsoProviderImplementation a la etiqueta XML LOBSystemInstance como se muestra a continuación.

    <LobSystemInstance Name="AdventureWorks2000(SampleSSO)">
    <Properties>
    <Property Name="AuthenticationMode" Type="System.String">WindowsCredentials</Property>
    <Property Name="SsoApplicationId" Type="System.String">AdventureWorks</Property>
    <Property Name="SsoProviderImplementation" Type="System.String">SampleSSOProvider.SimpleSSOProvider, SampleSSOProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e447e624e7099fd1</Property>
    
    <!—Database connection properties elided -->
    </Properties>
    </LobSystemInstance>
    

Dado que el proveedor devuelve las credenciales de Windows, la propiedad AuthenticationMode se establece para recibir WindowsCredentials. Cuando el Catálogo de datos profesionales recupera las credenciales desde el proveedor de SSO, ejecutará una llamada a LogonUser() para configurar la suplantación antes de intentar obtener acceso a la base de datos.

En el ejemplo, se asigna a un usuario a las cuentas InternalAccess o ExternalAccess para recuperar datos de productos de una base de datos de AdventureWorks 2000.

Para obtener más información sobre el esquema de Catálogo de datos profesionales, incluida la configuración necesaria para implementar SSO para los sistemas de LOB de servicio web, consulte LobSystemInstance en Catálogo de datos profesionales: modelo de metadatos.

Pasos siguientes

La capacidad para reemplazar el proveedor de SSO predeterminado de Office SharePoint Server 2007 le permite integrar mejor los sitios de SharePoint con las inversiones ya realizadas en su empresa. Puede hacer uso de almacenes de credenciales preexistentes desarrollados internamente o proporcionados como parte de un paquete de terceros. Podrá entonces obtener acceso al proveedor personalizado desde elementos web o desde objetos del Catálogo de datos profesionales para aprovechar al máximo el proveedor de SSO personalizado.