Las Aplicaciones High-Trust – III

Escrito por Edin Kapic - 27/08/2015

En el último artículo hablé sobre las aplicaciones high-trust o de alta confianza (también conocidas como S2S, server-to-server) en los entornos de SharePoint 2013. Por defecto, estas aplicaciones usan la autenticación Windows. Veremos lo que hay que hacer para utilizar otro proveedor de autenticación para la app.

La identidad en una high-trust app

Tal como vimos en el artículo anterior, en las high-trust apps es la responsabilidad de la propia app establecer el token del usuario. Es decir, la app le dice explícitamente a SharePoint que usuario está accediendo a ella. Por defecto, la implementación del TokenHelper de las apps de SharePoint en Visual Studio sólo funciona para los usuarios de Windows ya que usa la clase WindowsIdentity internamente.  En la mayor parte de los despliegues de una high-trust app, todos los usuarios dispondrán de su usuario de Windows así que no nos preocuparemos mucho. Sin embargo, cuando no usamos la autenticación Windows es cuando vamos a tener problemas.

Desde SharePoint 2010 existe la posibilidad de utilizar un proveedor de identidad que soporte Claims (o tokens SAML) para la autenticación en las aplicaciones web de SharePoint. De hecho, SharePoint 2013 las usa por defecto. Es relativamente fácil conectar SharePoint con un proveedor de identidad (IdP) compatible como puede ser Active Directory Federation Services (ADFS) o el gratuito pero excelente Identity Server de la empresa Thinktecture[i].

El ejercicio de conectar SharePoint a un proveedor de identidad alternativo pasa por establecer el proveedor de autenticación como proveedor de identidad de confianza. Además, el proveedor de autenticación tiene que registrar SharePoint como "relying party" o consumidor de autenticación de fiar. En uno de los anteriores números de CompartiMOSS, Diego Gatti explicó como conectar SharePoint con ADFS[ii].

Imaginad que disponemos de un SharePoint habilitado para reconocer los usuarios "federados" identificados por un token SAML expedido por un proveedor de identidad ADFS que está disponible en la URL https://idp.migranja.com. Ahora queremos que la app que está alojada en miapp.migranja.com se autentique mediante identidad federada contra SharePoint.

Si hacemos una high-trust app normal como la que vimos en el artículo anterior y la lanzamos desde SharePoint, identificados como un usuario federado, la app pedirá credenciales de Windows al ser redireccionada. Como acabo de explicar, el código estándar utiliza WindowsIdentity y la app en el web.config tiene puesto que se use el módulo de autenticación de Windows.

Arreglando la autenticación de la app

¿Qué podemos hacer para arreglar la autenticación? El primer paso será cambiar la autenticación de la app de Windows a autenticación federada por SAML. Es decir, hay que sustituir en el apartado <system.web> del web.config de la app la línea de autenticación de Windows y poner esta:

<authentication mode="None" />

Con esto le decimos a la app que no use ninguna autenticación. Pero entonces, ¿cómo va a saber la app que usuario está autenticado? Tenemos que añadir dos paquetes de NuGet que habilitan la autenticación federada e instalan las librerías necesarias:

  • Microsoft Token Validation Extension for .NET 4.5.
  • Microsoft ASP.NET Identity Core.

Imagen 1.- El paquete Microsoft.AspNet.Identity.Core 

Imagen 2.- El paquete System.IdentityModel.Tokens.ValidatingIssuerNameRegistry. 

Con estas dos librerías instaladas hay que cambiar otra vez el web.config para habilitar la autenticación federada que se instala como un módulo HTTP.

Al principio de todo del fichero, en la sección <configSections>:

<configSections>
  <section name="system.identityModel"
    type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
  <section name="system.identityModel.services"
    type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>


 

Justo después del elemento </system.web> hay que poner este fragmento que habilita los módulos de autenticación:

<system.webServer>
  <modules>
    <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
    <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
  </modules>
</system.webServer>

 

La parte más importante viene ahora. Agregamos una nueva sección en el web.config con los detalles del proveedor de identidad federado:

<system.identityModel>
  <identityConfiguration>
    <audienceUris>
      <add value="uri:miapp.migranja.com" />
    </audienceUris>
    <securityTokenHandlers>
      <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    </securityTokenHandlers>
    <certificateValidation certificateValidationMode="None" />
    <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
      <authority name="idp.migranja.com">
        <keys>
          <add thumbprint="ABCDEF123456789..." />
        </keys>
        <validIssuers>
          <add name="http://idp.migranja.com/adfs/services/trust" />
        </validIssuers>
      </authority>
    </issuerNameRegistry>
  </identityConfiguration>
</system.identityModel>

 

Aquí hay que especificar cuatro parámetros que diferirán entre varios entornos de federación y las apps.

  • El identificador de la app como Relying Party en el proveedor de identidad (uri:miapp.migranja.com). Puede ser un URI o una URL. Esto sirve para que el proveedor de identidad sepa que app le está pidiendo autenticación.
  • La URL del proveedor de identidad (idp.migranja.com).
  • La URL de la federación del proveedor de identidad (http://idp.migranja.com/adfs/services/trust). La app usará esta URL para realizar la autenticación.
  • La huella del certificado digital con el que se firman los tokens del proveedor de identidad (ABCDEF123456789...). Esto sirve para que la app pueda validar que el token está bien firmado y que no está falseado.

Una última edición del fichero web.config para configurar bien las cookies de autenticación:

<system.identityModel.services>
  <federationConfiguration>
    <cookieHandler requireSsl="true" />
    <wsFederation passiveRedirectEnabled="true"
      issuer="https://idp.migranja.com/adfs/ls/"
      realm="uri:miapp.migranja.com"
      requireHttps="true" />
  </federationConfiguration>
</system.identityModel.services>

 

Aquí tenemos que decirle a nuestra app la URL de login del proveedor de identidad (https://idp.migranja.com/adfs/ls/) y repetir el identificador de la app como realm (uri:miapp.migranja.com).

Este último punto requiere un poco más de explicación. La app primero intentará ir a la URL de federación del proveedor de identidad. Si no dispone de la cookie de autenticación, el propio proveedor nos redireccionará a la pantalla de login, después de la cual se nos redireccionará a nuestra app. El último punto en el web.config sirve para que nuestra app reconozca esa redirección y sepa extraer el token correcto.

La modificación del código de TokenHelper

Después de todo el trabajo en el web.config, hay que modificar el fichero TokenHelper para que use la identidad de autenticación correcta. Para ello disponemos del código creado por Wictor Wilén llamado SharePointContextSaml[i]. Es un fichero llamado SharePointContextSaml.cs que añadiremos a nuestra solución.

Cambiaremos el fichero TokenHelper.cs para que se declare como partial.

public static partial class TokenHelper { … }

En el fichero SharePointContext.cs cambiaremos el constructor para inicializar el nuevo proveedor de contexto de SharePoint con SAML.

static SharePointContextProvider()
    {
    if (!TokenHelper.IsHighTrustApp())
    {
        SharePointContextProvider.current = new SharePointAcsContextProvider();
    }
    else
    {
        if(HttpContext.Current.User.Identity.AuthenticationType == "Federation") {
            SharePointContextProvider.current = new SharePointHighTrustSamlContextProvider();
        } else {
            SharePointContextProvider.current = new SharePointHighTrustContextProvider();
        }
    }
}

Y finalmente en el web.config añadiremos tres parámetros de configuración.

<add key="spsaml:ClaimProviderType" value="SAML"/>
<add key="spsaml:TrustedProviderName" value="IdP Migranja"/>
<add key="spsaml:IdentityClaimType" value="SMTP"/>

 

El primero especifica si usamos la autenticación SAML o FBA, ya que el código soporta las dos opciones. El segundo es el nombre del proveedor de autenticación definido en SharePoint. El último es el atributo identificador del usuario en la base de datos de perfiles. Por defecto es el correo electrónico (SMTP) pero se admiten también SIP o UPN.

¡Nuestra app high-trust ya está lista para utilizar claims en su comunicación con SharePoint!

Conclusión

Hemos visto que habilitar la autenticación no Windows en las apps high-trust no es difícil pero sí que es un proceso tedioso y donde es fácil equivocarse. Si sólo una de las múltiples configuraciones que hemos tenido que hacer está mal, la autenticación no funcionará.

Con este artículo acabo la serie sobre las high-trust apps de SharePoint. Espero haberos acercado una opción de desarrollo de la que no se habla mucho y que creo que dará buenos resultados para los nuevos desarrollos on-premises para los que sería deseable que estén preparados para su despliegue en la nube. ¡Un saludo y nos vemos en uno de los próximos números!

 

Edin Kapić
Arquitecto SharePoint
edin.kapic@sogeti.com
@ekapic
www.edinkapic.com


 

[i] https://github.com/wictorwilen/SharePointContextSaml

[i] https://github.com/IdentityServer/IdentityServer2

[ii] http://www.compartimoss.com/revistas/numero-11

***