SharePoint 2013. Una Provider-Hosted que no es una Provider-Hosted

Como ya sabemos todos, SharePoint 2013 implementa un nuevo modelo o paradigma de desarrollo denominado Aplicaciones. En este nuevo modelo se ha pensado bastante en la seguridad y el acceso a la información de SharePoint y es por esto por lo que sólo podemos usar el modelo de objetos de cliente (CSOM), con las limitaciones que esto conlleva.

 

Teniendo claras estas limitaciones, se abre un mundo de posibilidades donde nos encontraremos todo tipo de desarrolladores (no sólo los que sabemos SharePoint) y en el que incluimos la necesidad de movilidad y las soluciones implementadas en la tan beneficiosa nube. En Encamina este concepto lo llamamos SharePoint Everyware, buscando la sinergia entre «Ágil» y «Enterprise» y aprovechando SharePoint como capa de servicio para las Aplicaciones que nos demandan los clientes.

El reto que se nos plantea es: ¿Cómo podemos saltarnos esas limitaciones pero manteniendo el concepto y diseño de Aplicación?

Adrián Díaz y un servidor llevamos unos días haciendo pequeñas pruebas de concepto, buscando una arquitectura desacoplada, al igual que las Aplicaciones, pero que nos permita el uso del modelo de objetos de servidor (SSOM), patrones del tipo Repository o Service Locator, TDD o Integración Continua.

Planteamos dos modelos:

  1. Usar un servicio WCF instalado dentro de SharePoint con Microsoft.SharePoint.Client.Services y que este sea nuestro punto de entrada REST para las peticiones, lo que nos obliga a buscar algún modo de meter un contenedor de dependencias dentro del proceso de SharePoint.
  2. Usar Web Api en una aplicación web externa a SharePoint (los intentos de modificar las tablas de enrutamiento y poner Web Api dentro del ciclo de vida de las llamadas de SharePoint no obtuvieron buenos resultados) que nos permita trabajar independientemente de nuestra capa de servicio, que para la mayoría de los casos será SharePoint, y en la que sería muy sencillo implementar las buenas prácticas que esperamos en nuestros desarrollos, similar al concepto Provider-Hosted que tenemos en Aplicaciones.

¿Qué problemas nos encontramos?

  • En el servicio WCF no sería sencillo ser independientes de SharePoint e implementar un contenedor de dependencias nos obliga a tener un HttpModule recibiendo todas las peticiones de SharePoint y gestionando el ciclo de vida de este contenedor.
  • ¿Qué pasaría si necesitamos tener una capa de servicio que obtenga información de SharePoint y de un repositorio externo, por ejemplo, un servicio en Azure o una base de datos? ¿Tenemos claro que vamos a meter esas llamadas dentro del proceso de ejecución de SharePoint? Es posible, pero nunca me ha gustado hacer esas cosas dentro del código que se ejecuta en SharePoint.
  • Si usamos Web Api, ¿qué hacemos con la autenticación? ¿cómo garantizamos la seguridad de acceso al servicio y que las llamadas a SharePoint se hagan con el contexto del usuario adecuado? Si implementamos Autenticación Integrada, obligamos a realizar doble autenticación a los usuarios, una en SharePoint y la otra en la Web Api pero ¿y si estamos en un ordenador o Tablet fuera de dominio? Está claro que no podemos acceder a la Web Api sin tener las credenciales ni la autenticación del usuario frente a SharePoint.

Posibles soluciones

Para el caso del WCF, tenemos varios ejemplos que nos permiten gestionar (siempre mediante un HttpModule) estos contenedores con Ninject o Autofac, y el problema de hacer llamadas a servicios externos es más algo personal que una limitación técnica.

La solución para la Web Api no es tan simple. Pensemos en el modelo que intentamos replicar, el Provider-Hosted (de ahí el título de este post). Cuando SharePoint hace una llamada a una Aplicación siempre le pasa la información del contexto actual y un Token que permite abrir un contexto de cliente sin necesidad de tener las credenciales del usuario. Tenemos disponible una clase, TokenHelper, que tiene los métodos para leer los Token y abrir un ClientContext, pero nosotros necesitamos un contexto de servidor y no de cliente. Si conseguimos salvar este problema y recibir algún tipo de Token que permita abrir un contexto de servidor, espera, ¿no podemos abrir un SPSite usando la URL del Site y un objeto SPUserToken? Pues va a ser que sí, ahora toca obtener ese Token desde las distintas interfaces de usuario de nuestra Aplicación y dárselo a la Web Api para que pueda hacer peticiones a SharePoint en nombre del usuario.

Estaba claro que obtener el Token tampoco iba a ser sencillo y que no lo íbamos a tener directamente en el contexto de JavaScript de SharePoint pero si en el contexto de servidor: SPContext.Current.Web.CurrentUser.UserToken. Tenemos que ser capaces de enviar ese Token a cualquier llamada a la Web Api para que instancia un contexto de servidor con el usuario actual de SharePoint, pero ¿cómo? Si lo que queremos es que, al igual que el modelo de aplicaciones, en SharePoint no tengamos código de servidor o tengamos lo mínimo indispensable.

WCF al rescate! Bajo la seguridad de SharePoint, desplegamos un servicio WCF que devuelve única y exclusivamente el Token del usuario actual, que usaremos para hacer las llamadas a la Web Api. Algo tal como lo pintamos en el siguiente esquema:

 

  1. Nuestra Aplicación, que puede estar en SharePoint o no, necesita hacer primero una petición al servicio de WCF que le devuelva el Token del usuario actual. Para el caso de que no estemos en el contexto de SharePoint, esa llamada conlleva un proceso previo de autenticación de usuario en SharePoint.
  2. El servicio WCF obtienen el SPUserToken del usuario actual y se lo devuelve a la Aplicación.
  3. Hacemos la llamada a la Web Api, enviando correctamente serializado el SPUserToken para que este pueda abrir un contexto de servidor con las credenciales del usuario actual.

Al final, nos hemos encontrado con un proceso muy similar al que se ha implementado en las Aplicaciones de SharePoint y hemos construido una No-Provider-Hosted adecuada al paradigma de desarrollo que queremos implementar y necesario para nuestro SharePoint Everyware.

 

Saludos a todos…

Un comentario sobre “SharePoint 2013. Una Provider-Hosted que no es una Provider-Hosted”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *