Compartir a través de


OData

OData, Entity Framework y Access Control en Windows Azure

Sean Iannuzzi

Descargar el ejemplo de código

En este artículo le mostraré cómo implementar Open Data Protocol (OData) con Entity Framework expuesto con los servicios compatibles con REST de Windows Communication Foundation (WCF) y protegidos con Access Control Service de Windows Azure (ACS).

Como ocurre con muchos desarrolladores, frecuentemente intento sacar partido de tecnologías en formas nuevas y diferentes para completar mi proyecto de la manera más eficiente posible, mientras que al mismo tiempo proporciono una solución flexible y fácil de mantener. Esto puede ser difícil, especialmente cuando el proyecto exige que los datos se expongan en forma rápida y segura.

Recientemente me pidieron que creara un servicio Web seguro para una base de datos y aplicación web existente. No tenía ningún deseo de implementar todo el código de creación, lectura, actualización y eliminación (CRUD). Estuve tentado de crear simplemente unos contratos de servicio, de operación y de datos personalizados que condujeran con exactitud la forma en que los datos se exponen y cómo los demás podrían consumir estos datos a través de los servicios. Pero sabía que debía existir alguna ruta más útil. Comencé a buscar varias formas de lograrlo y vi que había potencial en OData (o, como me gusta llamarle, “¡Oh, Datos!”). El problema es que OData por sí mismo no contaba con la seguridad que me parecía necesaria y que debía agregar una capa de seguridad adicional sobre el servicio OData para tener la confianza de que tendría la seguridad apropiada. A medida que comencé a juntar las partes, me topé con ACS, que es fantástico para implementar servicios de autenticación y autorización federada basados en la nube. Exactamente lo que necesitaba. Entonces tuve un momento de “¡eureka!”. Me di cuenta que si conectaba ACS con OData, tendría la solución que andaba buscando.

También pensé en implementar contratos de servicio personalizados; este enfoque tiene sus aplicaciones, específicamente cuando se necesita una capa de abstracción en frente de un modelo de datos y cuando es necesario para proteger las entidades de la base de datos frente a una exposición directa a los clientes de un servicio. Pero como todo esto exige mucho tiempo —crear el documento apropiado sobre cómo consumir el servicio y el trabajo adicional necesario para configurar la seguridad (“MessageCredential“ y “TransportWithMessageCredentials“)—, el proyecto se me podría escapar fácilmente de las manos. También me preocupaba que por una u otra razón podría ser necesario agregar métodos adicionales para el consumo de estos servicios, lo que nuevamente demandaría más tiempo, mantenimiento y personalización. Incluso si mi implementación del servicio usaba Entity Framework en forma directa frente a ADO.NET, podría ser necesario crear todo el código CRUD para mantener sincronizada la capa de datos. Si suponemos que hay varias docenas de tablas, esto podría ser un trabajo extremadamente tedioso. Además, la creación y el mantenimiento de toda la documentación y los detalles de implementación adicionales que pudieran ser necesarios para los usuarios finales complicarían aún más esta propuesta.

Un camino más fácil

Una vez que identifiqué las tecnologías primarias, busqué otras que rellenaran los huecos y que me permitieran construir una solución integral. La meta era limitar la cantidad de código que debía escribir y mantener, mientras que exponía en forma segura los servicios WCF de OData compatibles con REST. Finalmente enlacé las siguientes tecnologías: ACS, OData, Entity Data Models, servicios de datos de WCF con permisos de Entity y una implementación de seguridad personalizada de Windows Azure. Cada una de esas tecnologías ya es bastante valiosa por sí sola pero, al combinarlas, su valor aumenta en forma exponencial. En la Ilustración 1 se muestra una descripción general de cómo funcionarán algunas de esas tecnologías al implementarlas.

High-Level Overview of ACS with a Security InterceptIlustración 1 Descripción general de ACS con una intercepción de seguridad

Antes de intentar de combinar todas estas tecnologías, debí pararme a pensar y entender a cabalidad cada una de ellas y el impacto que podrían tener en este proyecto. Así obtuve una noción clara sobre cómo podría combinarlas y qué es lo que haría falta para que alguien más usara otras tecnologías para consumir mis servicios.

¿Qué es ACS?

ACS se entrega como un componente de la plataforma Windows Azure. ACS me permite configurar una autenticación federada propia basada en la nube y el proveedor de autorización que empleo para proteger los servicios WCF de OData, pero ACS también sirve para proteger cualquier otra aplicación. ACS es un servicio basado en nube que ayuda a cerrar la brecha de seguridad cuando hay que implementar un inicio de sesión único (SSO) en varias aplicaciones, servicios o productos (ya sea para varias plataformas o para varios dominios) que implementen SSO. Una cuenta de Windows Azure proporciona acceso a mucha más información. Puede inscribirse para una evaluación gratuita en windowsazure.com. Para leer más acerca de ACS, consulte bit.ly/zLpIbw.

¿Qué es OData y por qué debería usarlo?

OData es un protocolo basado en web que permite consultar y actualizar datos, y exponer los datos mediante una sintaxis estandarizada. OData saca partido de las tecnologías como HTTP, XML, JSON y el protocolo de publicación Atom para proporcionar acceso de distintas formas a los datos. La implementación de OData con Entity Framework y WCF Data Services proporciona muchos y grandes beneficios.

Empecé a preguntarme por qué usaría esto en lugar de los contratos WCF personalizados. La respuesta saltaba a la vista. La razón más práctica era aprovechar la documentación del servicio que ya estaba disponible y usar una sintaxis estandarizada para obtener acceso a los datos desde mi servicio. Al haber escrito docenas de servicios, parece ser que siempre tengo que agregar un método adicional para poder proporcionar servicios personalizados. Además, los consumidores de los servicios personalizados tienden a pedir más y más características.

 Para obtener más información sobre las convenciones de OData y URI de OData, visite los siguientes sitios:

OData con Entity Framework y servicios de datos de WCF

Al usar OData con los servicios de datos de WCF y Entity Framework, se expone una funcionalidad estándar que permite recuperar y guardar los datos de una manera que ya está documentada y que exige muy poco código de implementación. Cuando comencé a crear mi Entity Data Model para el formato de empaquetamiento de servicios de datos (EDMX) y lo vinculé al servicio WCF mediante los servicios de datos, tenía mis serias dudas. Pero todo funcionó a la perfección. Todas las entidades que incluí en el EDMX se incluyeron y expusieron automáticamente en el servicio WCF en una implementación compatible con REST. En la Ilustración 2 podemos apreciar parte del código de ejemplo.

Ilustración 2 Implementación de los servicios de datos de WCF de OData

using System.Data.Services;
using System.Data.Services.Common;
namespace WCFDataServiceExample
{
  public class NorthwindService : DataService<NorthwindEntities>
  {
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(DataServiceConfiguration config)
    {
      // Give full access to all of the entities.
      config.SetEntitySetAccessRule("*", EntitySetRights.All);
      // Page size will change the max number of rows returned.
      config.SetEntitySetPageSize("*", 25);
      config.DataServiceBehavior.MaxProtocolVersion =
        DataServiceProtocolVersion.V2;
    }
  }
}

Creé un EDMX y lo vinculé a algunas de las tablas de mi base de datos (base de datos de ejemplo Northwind). Luego, vinculé las entidades de base de datos al servicio de datos de WCF y expuse todas las entidades con el método “SetEntitySetAccessRule” con el atributo comodín “*” para todas las entidades. Esto me permitió configurar varios permisos de las entidades, para el acceso de lectura, escritura y consultas, además de configurar el tamaño de página, tal como se aprecia en la Ilustración 2. El código corresponde a la implementación completa de los servicios de datos de WCF de OData.

Los contratos de servicios, de operaciones y de datos se controlan principalmente por medio de la configuración en la inicialización de los servicios proporcionados. En el método de inicialización, tengo la posibilidad de configurar varios permisos asociados a la forma en la que quiero exponer mis entidades y al nivel de acceso que quiero proporcionar a los consumidores de los servicios. Incluso podría emplear plantillas T4 para crear una capa abstracta o capa de plantilla sobre las entidades con nombres de entidades personalizados. Esto agregaría un nivel adicional de claridad para el consumidor de los servicios. Incluso podría configurar el permiso de una tabla puntual o podría establecer el nombre de la tabla junto con la configuración de seguridad apropiada para obtener una protección aún más pormenorizada. En este ejemplo se entrega acceso de lectura a la tabla Customer:

config.SetEntitySetAccessRule("Customer",
  EntitySetRights.AllRead);

OData y los servicios de datos de WCF permiten realizar muchas implementaciones de seguridad diferentes, pero por ahora solo me preocupa cómo proteger los servicios WCF con ACS en combinación con las reglas de acceso del servicio de datos.

En la Ilustración 3 aparece un listado breve de las tecnologías que se emplean, junto con algunas de las razones por las cuales esas tecnologías se podrían usar.

Ilustración 3 Tecnologías usadas junto con las razones

Tecnología Por qué usarla
ACS Proporciona una manera de proteger los servicios mediante un módulo de seguridad federada basado en la nube para la autenticación y autorización
OData Proporciona una sintaxis estándar para realizar consultas y actualizar datos, al aprovechar tecnologías comunes como HTTP, JSON, XML y el protocolo de publicación Atom
Entity Data Model Proporciona una manera rápida de crear un acceso de datos común para un nivel de base de datos y al mismo tiempo proporciona contratos de datos serializables de las tablas de una base de datos
Servicios de datos WCF con permisos de Entity Expone el contrato de datos de Entity Framework con el nivel apropiado de permisos de CRUD como un servicio WCF compatible con REST
Implementación de seguridad personalizada de Windows Azure Protege los servicios (en este caso, los servicios de OData) de que se consuman sin aplicar el nivel de seguridad apropiado como, por ejemplo, un token o certificado

Con cada una de estas tecnologías, siempre se deben realizar concesiones en el proyecto, pero descubrí que al combinarlas se podía ahorrar tiempo preoperativo y se reducía el trabajo de mantenimiento y, al mismo tiempo, se requería menos código y se obtenían ganancias enormes, especialmente cuando tenía que exponer mis datos en forma segura y proporcionar métodos de acceso a datos comunes con una sintaxis estandarizada.

En resumen

Con una buena comprensión del uso combinado de OData, Entity Framework y WCF Data Services, podría aplicar características de seguridad adicionales a esta tecnología, al emplear ACS. Existían varias opciones para restringir el acceso a mi servicio; por ejemplo, la configuración de varios permisos en las entidades o la adición de interceptores de consulta para evitar el consumo del servicio o para controlar la forma en que este se consume.

Sin embargo, la implementación de los interceptores de consulta y la configuración de sus permisos resultaría tedioso; sería preferible agregar una capa de seguridad sobre mi servicio para evitar que se consuma en vez de escribir código adicional. Lo ideal sería implementar un mecanismo de seguridad común que permita otorgar acceso a las partes de confianza o las empresas externas. A su vez, podría usar una combinación de esta seguridad junto con la protección de las entidades para brindarle a mis servicios la implementación más segura con la mayor flexibilidad posible.

Al usar este sistema, cualquier consumidor del servicio debe autenticarse primero a través de ACS y obtener un token de acceso válido. Sin este token de acceso, los servicios se restringirían. El encabezado de la solicitud debería tener los tokens de acceso válidos, antes de otorgar acceso a cualquier usuario del servicio. Una vez que se autorizara al consumidor del servicio, aplicaría una seguridad muy específica en las entidades para garantizar que solo se otorgue un acceso autorizado a los datos y las entidades.

Configuración de ACS

Para implementar ACS, hay que realizar trabajo de configuración adicional. En la Ilustración 4 se entrega un listado de los elementos que establecí para este ejemplo.

Ilustración 4 Configuración de ACS

Configuración Valores
Espacio de nombres de ACS WCFoDataACS
Aplicación de la parte que responde

Nombre: wcfodataacsexampleDevelopment

Modo: dejar valores predeterminados (escribir configuración manualmente)

Dominio: http://localhost/WCFDataServiceExample/<nombredeservicio>.svc

URL de devolución: dejar valor predeterminado (en blanco)

URL de error: dejar valor predeterminado (en blanco)

Formato de token: SWT

Directiva de cifrado de token: dejar valor predeterminado (ninguna)

Duración de token: dejar valor predeterminado (600)

Configuración de autenticación

Proveedores de identidad: desactivar Windows Live ID

Grupo de reglas: activar Crear nuevo grupo de reglas

Nota: Creé distintas configuraciones para desarrollo, pruebas y producción.

Configuración de firma de tokens

Haga clic en el botón Generar

Fecha de entrada en vigencia: dejar valores predeterminados

Fecha de expiración: dejar valores predeterminados

Grupo de reglas Nota: a partir de mi configuración, el grupo de reglas se creará en forma automática, pero igual debo agregar la configuración de reclamación.
Configuración de reclamación

Sección If:

Sistema de control de acceso: seleccionado

Tipo de reclamación de entrada: dejar valor predeterminado (cualquiera)

Valor de reclamación de entrada: dejar valor predeterminado (cualquiera)

Sección Then:

Tipo de reclamación de salida: dejar valor predeterminado (pasar a través de tipo de reclamación de entrada)

Valor de reclamación de salida: dejar valor predeterminado (pasar a través de valor de reclamación de entrada)

Información de regla:

Descripción: dejar valor predeterminado o escribir descripción

Identidad del servicio en Windows

Nombre: el nombre de usuario que se proporcionará a otros (en este ejemplo usé wcfodataacsDevUser)

Descripción: dejar valor predeterminado (o escribir descripción del usuario)

Dominio: http://localhost/WCFDataServiceExample/<nombredeservicio>.svc

Configuración de credencial:

Tipo: seleccionar contraseña

Contraseña: escriba la contraseña deseada

Fecha de entrada en vigencia: dejar valores predeterminados

Fecha de expiración: dejar valores predeterminados

Nota: Existen varias opciones para autenticar un usuario en los servicios creados pero, para simplificar las cosas, usé la escritura de una contraseña como el tipo de credencial. Existen otras opciones, como usar un certificado x509 o una clave simétrica, que pueden proporcionar un nivel mayor de seguridad, pero para este ejemplo opté por la solución más básica.

Después de completar la configuración de ACS, pude proteger los servicios WCF de OData compatibles con REST. Antes de poder protegerlos, tuve que implementar un módulo de seguridad personalizado que pudiera interceptar las solicitudes y validar la seguridad para evitar el acceso no autorizado.

Implementación de seguridad de ACS

Como ejemplo, implementé la seguridad con un módulo HTTP personalizado. Este intercepta cualquier solicitud que se envía a mi servicio y valida si se generó la autenticación y autorización adecuada. Sin este módulo HTTP, los servicios solo estarían seguros en el nivel de las entidades, según la configuración de servicio de datos.

En este caso, protegí estos servicios con ACS; por lo tanto, las consultas se interceptaron y se controló el nivel adecuado de seguridad para tener la certeza de que el consumidor del servicio recibió el nivel de autorización adecuado. Tal como indiqué antes, también se puede implementar una seguridad pormenorizada en el nivel de las entidades después de autorizar el acceso para el consumidor del servicio.

Al implementar la interfaz IHTTPModule, opté por agregar algunas características adicionales, así que expuse algunos de los metadatos del servicio para permitir que los consumidores del servicio generaran clases en forma automática (parecido al comportamiento de agregar cualquier otro servicio web). Agregué estas secciones de código como atributos configurables que se pueden habilitar o deshabilitar para una mayor seguridad y mejorar las pruebas, y para facilitar el trabajo de integración.

En la Ilustración 5 se muestra el código que intercepta las solicitudes y realiza la validación de seguridad propiamente tal.

Ilustración 5 Validación de la seguridad

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Web;
using Microsoft.AccessControl2.SDK;
namespace Azure.oAuth.SecurityModule
{
  internal class SWTModule : IHttpModule
  {
    // Service namespace setup in Windows Azure
    string _serviceNamespace = 
      ConfigurationManager.AppSettings["serviceNamespace"];
    // ACS name
    string _acsHostName = ConfigurationManager.AppSettings["acsHostname"];
    // The key for which the service was signed
    string _trustedSigningKey =
      ConfigurationManager.AppSettings["trustedSigningKey"];
    // The URL that was setup in the rely party in Windows Azure
    string _trustedAudience = 
      ConfigurationManager.AppSettings["trustedAudience"];
    // Setting to allow the metadata to be shown
    bool _enableMetaData =  
       Convert.ToBoolean(ConfigurationManager.AppSettings["enableMetadata"]);
    // Setting to disable or enable the security module
    bool _disableSecurity =
      Convert.ToBoolean(ConfigurationManager.AppSettings["disableSecurity"]);
    const string _metaData = "$metadata";
    private void context_BeginRequest(object sender, EventArgs e)
    {
      if (!_disableSecurity)
      {
        string tempAcceptableURLs = String.Empty;
        // Check if the audiencename has trailing slash
        tempAcceptableURLs = _trustedAudience.ToLower();
        if (tempAcceptableURLs.Substring(_trustedAudience.Length - 1, 1) == "/")
        {
          tempAcceptableURLs =
            tempAcceptableURLs.Substring(0, _trustedAudience.Length - 1);
        }
        // First check if the person is requesting the WSDL or .svc
        if (_enableMetaData != false
          && HttpContext.Current.Request.Url.AbsoluteUri.ToLower() !=
          tempAcceptableURLs
          && HttpContext.Current.Request.Url.AbsoluteUri.ToLower() !=
          tempAcceptableURLs + _metaData
          && HttpContext.Current.Request.Url.AbsoluteUri.ToLower() !=
          tempAcceptableURLs + "/"
          && HttpContext.Current.Request.Url.AbsoluteUri.ToLower() !=
          tempAcceptableURLs + "/" + _metaData)
        {
          // SWT Validation...
          // Get the authorization header
          string headerValue =
            ttpContext.Current.Request.Headers.Get("Authorization");
          // Check that a value is there
          if (string.IsNullOrEmpty(headerValue))
          {
            throw new ApplicationException("unauthorized-1.1");
          }
          // Check that it starts with 'WRAP'
          if (!headerValue.StartsWith("WRAP "))
          {
            throw new ApplicationException("unauthorized-1.2");
          }
          // ... <code truncated> ...
        }
      }
    }
  }
}

Windows Azure SDK

Extraje una clase del SDK de Windows Azure para realizar la validación de los tokens para esta implementación. El proyecto se puede encontrar en bit.ly/utQd3S. Después de instalar el SDK, copié el archivo llamado “tokenvalidators.cs” en un proyecto nuevo. En esta clase puntual, llamé el método de validación para determinar si el usuario está autorizado mediante la información configurada en ACS. Para simplificar esta implementación, creé un DLL personalizado que solo contiene los mecanismos de seguridad necesarios. Después de crear el ensamblado, solo tenía que hacer referencia al DLL de seguridad con mi servicio WCF de OData. El resultado: una implementación protegida y segura.

Implementación del servicio OData seguro

Una vez que estaban implementadas las mejoras de seguridad adicionales, resultó fácil proteger el servicio WCF de OData. Todo lo que quedaba por hacer era hacer una referencia al ensamblado “Azure.AccessControl.SecurityModule” y agregar la configuración adicional. Luego se habilitan las características de seguridad. En la Ilustración 6 aparece la configuración de seguridad.

Ilustración 6 Configuración de seguridad

<appSettings>
  <add key="acsHostName" value="accesscontrol.windows.net" />
  <add key="serviceNamespace" value="Service Namespace" />
  <add key="trustedAudience"
    value="http://localhost/WCFDataServiceExample/NorthwindService.svc/" />
  <add key="trustedSigningKey" value="Trusted Signing Key" />
  <add key="enableMetadata" value="true" />
  <add key="disableSecurity" value="false"/>
</appSettings>
<system.webServer>
  <validation validateIntegratedModeConfiguration="false" />
  <modules runAllManagedModulesForAllRequests="true">
    <add name="SWTModule" type="Azure.AccessControl.SecurityModule.SWTModule,
      Azure.AccessControl.SecurityModule" preCondition="managedHandler" />
  </modules>
</system.webServer>

Según la configuración de seguridad, los consumidores del servicio se pueden restringir de forma tal que solo puedan ver los metadatos. Esto es extremadamente útil, ya que permite que los usuarios sigan haciendo referencia a los objetos y a las propiedades de la entidad en el código, lo que simplifica la implementación. Para deshabilitar los metadatos, establezco el atributo “enableMetadata” en falso, y los consumidores del servicio dejan de tener acceso a los metadatos. En el caso que los consumidores del servicio solo realizan acceso mediante código del lado cliente, no habilitaría los metadatos, pues no serían necesarios. Cuando se habilitan los metadatos, el servicio aparece igual que un servicio web normal, pero sin la posibilidad de consumirlo sin autenticación y autorización adecuada, como se aprecia en la Ilustración 7.

OData WCF Service with Metadata Exposed
Ilustración 7 Servicio WCF de OData con metadatos expuestos

Esto funciona casi igual que al usar Entity Framework directamente para el código de implementación, con unas pocas diferencias menores. El segmento de código clave que se debe agregar es el token obligatorio en el encabezado de la solicitud al enviar datos al servicio WCF de OData. Explicaré como funciona básicamente el mecanismo de seguridad. Primero revisa si el encabezado contiene un token válido y confirma que todos los componentes estén en regla; por ejemplo la audiencia de destino y la expiración y el valor del token. A continuación, se autoriza la solicitud y se genera la llamada al servicio. Al interceptar esta solicitud antes de devolver cualquier tipo de datos al consumidor del servicio, se garantiza que el autor de la llamada al servicio tuviera que obtener un token válido antes de recibir el acceso a los datos.

Hasta este punto (dependiendo del nivel de seguridad requerido por los objetos de la entidad) el consumidor del servicio puede realizar cualquier funcionalidad expuesta por el servicio, según el conjunto de configuraciones de seguridad. Cuando la seguridad no está habilitada, el consumidor del servicio recibe una excepción que indica que la acción realizada no está permitida.

A diferencia del código tradicional de Entity Framework, se debe implementar más lógica antes de llamar el servicio de OData protegido por Windows Azure. Con el módulo HTTP, que protege al servicio, debo asegurarme de realizar primero la autenticación con Windows Azure y recibir un token de acceso válido antes de llamar al servicio de OData. El token recibido de ACS se pasará a través del encabezado de la solicitud en cada solicitud hecha al servicio de OData seguro. En la Ilustración 8 podemos apreciar un ejemplo de solicitud.

Ilustración 8 Ejemplo de token de solicitud

// Request a token from ACS
using (WebClient client = new WebClient())
{
  client.BaseAddress = string.Format("https://{0}.{1}",
    _accessControlNamespace, _accessControlHostName);
  NameValueCollection values = new NameValueCollection();
  values.Add("wrap_name", wrapUsername);
  values.Add("wrap_password", wrapPassword);
  values.Add("wrap_scope", scope);
  byte[] responseBytes =
    client.UploadValues("WRAPv0.9/", "POST", values);
  response = Encoding.UTF8.GetString(responseBytes);
  Console.WriteLine("\nreceived token from ACS: {0}\n", response);
}

Una vez que se recibe de vuelta el token de Windows Azure y el usuario se autentica y autoriza correctamente, se devuelve un token de ACS para usarlo en todas las solicitudes futuras, hasta que el token expire. Llegados a este punto, la implementación de Entity Framework es casi igual que si estuviera conectado a una base de datos local o a una base de datos en mi red. En la Ilustración 9 se aprecia el consumo del servicio de OData con un token de acceso.

Ilustración 9 Consumo del servicio seguro de OData con un token de acceso de Windows Azure

// First things first: I obtain a token from Windows Azure
_token = GetTokenFromACS(_rootURL + "NorthwindService.svc");
// Now that I have a valid token, I can call the service as needed
Uri uri = new Uri(_rootURL + "NorthwindService.svc/");
try
{
  var northwindEntities = new ODataServiceClient.NorthwindEntities(uri);
  // Add the event handler to send the token in my request header
  northwindEntities.SendingRequest += new
    EventHandler<SendingRequestEventArgs>(OnSendingRequest);
  // Sample selecting data out ...
  var customersFound = from customers in northwindEntities.Customers
    select customers;
  foreach (var customer in customersFound)
  {
    // custom process ...
    // ... <code truncated> ...
    }
    // Add new data in ...
    var category = oDataServiceClient.Category.CreateCategory(0, "New category");
    northwindEntities.AddToCategories(category);
    northwindEntities.SaveChanges();
}
catch (DataServiceRequestException e)
{
  // Trap any data service exceptions such as a security error
  // In the event that the security does not allow an insert,
  // a forbidden error will be returned
  // ...
}

La implementación del código mediante un script del lado cliente también es tan sencillo como realizar una llamada AJAX al extremo del servicio. En la Ilustración 10 aparece el consumo del servicio OData seguro desde el script de lado cliente.

Ilustración 10 Consumo del servicio OData seguro desde un script del lado cliente

// Parse the entity object into JSON
var jsonEntity = window.JSON.stringify(entityObject);
$.support.cors = true;
// Asynchronous AJAX function to create a Cateogory using OData
$.ajax({
  type: "POST",
  contentType: "application/json; charset=utf-8",
  datatype: "jsonp",
  url: serverUrl + ODATA_ENDPOINT + "/" + odataSetName,
  data: jsonEntity,
  beforeSend: function (XMLHttpRequest) {
  // Specifying this header ensures that the results will be returned as JSON
  XMLHttpRequest.setRequestHeader("Accept", "application/json");
  XMLHttpRequest.setRequestHeader("Authorization", token);
  },
  success: function (data, textStatus, XmlHttpRequest) {
  if (successCallback) {
    successCallback(data.d, textStatus, XmlHttpRequest);
    }
  },
  error: function (XmlHttpRequest, textStatus, errorThrown) {
  if (errorCallback)
    errorCallback(XmlHttpRequest, textStatus, errorThrown);
  else
    errorHandler(XmlHttpRequest, textStatus, errorThrown);
  }
});

Los servicio compatibles con REST brindan una flexibilidad de implementación mayor y se consumen fácilmente mediante Java u otros scripts o API del lado cliente. Siguen siendo necesarios la autenticación y un token para consumir el servicio, pero OData es un estándar que no depende de la plataforma, debido a la sintaxis de consulta. En la Ilustración 11 vemos el consumo del servicio OData seguro con un token de acceso de Windows Azure en Java.

Ilustración 11 Implementación en Java del consumo del servicio OData seguro con un token de acceso de Windows Azure.

String serviceMethodUrl =  
  "http://localhost/WCFDataServiceExample/NorthwindService.svc/Categories?";
GetMethod method = new GetMethod(serviceMethodUrl + "$top=1");
method.addRequestHeader("Authorization", 
  "WRAP access_token=\"" + authToken + "\"");
try
{
  int returnCode = client.executeMethod(method);
  // ... <code truncated> ...
  br = new BufferedReader(new 
    InputStreamReader(method.getResponseBodyAsStream()));
  String readLine;
  while(((readLine = br.readLine()) != null))
  {
    //System.err.println(readLine);
    result += readLine;
  }
}

Para resumir; frecuentemente me topo con la necesidad de exponer datos de manera que requeriría cierto nivel de seguridad para evitar el acceso no autorizado. El uso de ACS me ayuda en este caso, al implementar un servicio federado basado en la nube para proteger no solo los servicios de datos de WCF de OData, sino que también muchas otras aplicaciones.

Dicho esto, al usar los servicios de datos WCF por sí solos debería implementar contratos de datos individuales e interceptores de consultas para exponer los datos. El uso de Entity Framework en combinación con los servicios de datos de WCF permite sacar provecho de las entidades de base de datos como los contratos de datos, y esos contratos se proporcionan en un formato que ya está establecido (objetos serializables a los que se puede acceder mediante OData). La última pieza de este rompecabezas es asegurarse de que los servicios WCF de OData compatibles con REST estén protegidos frente al acceso no autorizado. El uso de ACS, OData y Entity Framework, encapsulados en los servicios WCF compatibles con REST, proporciona una forma rápida de exponer los datos, con una sintaxis de consulta estándar y una capa de seguridad adicional.

Sean Iannuzzi es arquitecto de soluciones para The Agency Inside Harte-Hanks, donde implementa los procedimientos recomendados para las soluciones de empresas, sistemas y software. Le encanta aprender nuevas tecnologías y encontrar maneras de aprovecharlas para ayudarle a solucionar problemas a las a empresas y los desarrolladores. Tiene un blog en weblogs.asp.net/seaniannuzzi y lo puede seguir en Twitter en twitter.com/seaniannuzzi.

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Danilo Diaz