lunes, 28 de noviembre de 2011

SharePoint 2010, Servicios REST y Claims

Una de las cosas en las que estoy trabajando actualmente requería disponer de un servicio WCF REST para interactuar con SharePoint 2010. Este servicio se consumía mayoritariamente desde javascript via AJAX y no presentaba mayores problemas y hace un tiempo surgió la necesidad de hacer llamadas al mismo servicio desde diversos webparts y event receivers de manera que el punto de entrada al corazón de la aplicación fuera siempre el mismo. Todo parecía funcionar correctamente hasta que en una de las pruebas de despliegue detectamos un error extraño similar al siguiente:

The remote server returned an error: (400) Bad Request. Exception: System.Net.WebException: The remote server returned an error: (400) Bad Request.     at System.Net.WebClient.UploadDataInternal

Como el error en sí no era demasiado descriptivo metí unas cuantas trazas y utilicé algún que otro Fiddler para determinar la causa real del problema. Así es como di con el siguiente error:

Message: 403 FORBIDDEN

Perfecto, habíamos pasado de un Bad Request (400) a un Forbidden (403). Además tenía todo el sentido del mundo porque el error se daba únicamente en el entorno donde teníamos corriendo el código en una aplicación web con autenticación basada en Claims. Determinado el error y su más que probable causa, encontrar una solución era sólo cuestión de tiempo. Y la solución vino de la mano de Justin Kobel y de este artículo.

Aquí no sólo encontramos el código necesario para realizar las llamadas de manera adecuada, sino que se explica también cómo hacer para distinguir si estamos en una aplicación web clásica o en una basada en notificaciones. Yo tuve que cambiar algo el código para adaptarlo a mis necesidades pero la esencia es la misma y consiste en aprovechar la cabecera Cookie para nuestra llamada, tal y como muestra el siguiente listado.

webClient = new WebClient { Credentials = CredentialCache.DefaultNetworkCredentials };
webClient.Headers[HttpRequestHeader.ContentType] = "application/json";
 
IClaimsPrincipal principal = HttpContext.Current.User as IClaimsPrincipal;
if (principal != null)
{
   NameValueCollection headers = HttpContext.Current.Request.Headers;
   webClient.Headers["Cookie"] = headers["Cookie"];
}
 
var receivedData = webClient.UploadData(url, verb, memoryStream.ToArray());
var response = (T)jsonSerializer.ReadObject(new MemoryStream(receivedData));

Veréis que en un punto del artículo hace el autor se salta la validación de los certificados en el momento de la autenticación. Si queréis información sobre como hacer esto de manera adecuada, os recomiendo este artículo de mi compañero Jordi Ruiz.

0 comentarios: