October 2012

Volume 27 Number 10

OData - OData, the Entity Framework and Micrsosoft Azure Access Control

By Sean Iannuzzi | October 2012

In this article I’ll show how to implement the Open Data Protocol (OData) with the Entity Framework exposed with Windows Communication Foundation (WCF) RESTful services and secured with the Azure Access Control Service (ACS).

Like most developers, I often find myself trying to leverage a combination of technologies in new and various ways to complete my project as efficiently as possible while also providing a flexible, easy-to-maintain solution. This can be difficult, particularly when the project requires data to be exposed quickly and securely.

Recently I was asked to create a secure Web service for an existing database and Web application. I really didn’t want to implement all of the create, read, update and delete (CRUD) code. It was tempting to just create custom service contracts, operation contracts and data contracts that would drive exactly how the data could be exposed and how someone else could potentially consume this data via services. But I knew there had to be a more advantageous route to take. I started researching various ways that this could be accomplished and saw potential with OData (or “Ohhhh Data,” as I like to call it). The problem was that OData by itself was not secured in a way that I felt was acceptable, and I needed to add an additional layer of security on top of the OData service in order to feel confident it would be secured properly. As I started to piece this together, I found ACS, which is great for implementing a cloud-based federated authentication and authorization service—exactly what I needed. Then I had my “aha!” moment. I realized that if I wired up ACS with OData, I’d have my solution.

Now, I did consider implementing custom service contracts, and there is a place for this approach, especially where a layer of abstrac­tion is needed in front of a data model and where it’s required to protect the database entities from being directly exposed to consumers of a service. However, given how time-consuming this is—creating the appropriate document regarding how to consume the service, and adding in the additional effort required to set up the security (“MessageCredential” and “TransportWithMessageCredentials”)—the project could quickly spiral of control. I was also concerned that additional methods would be needed or requested for one reason or another to support how the services were being consumed, which, again, would add more time, maintenance and customization. Even if my implementation of the service used the Entity Framework versus ADO.NET directly, creating all of the CRUD code might still be required to keep the data layer in sync. Assuming there are a few dozen tables, this effort could be extremely tedious. Plus, creating and maintaining any additional documentation and implementation details required for end users to consume my service made this a much more complicated proposition to manage.

An Easier Way

Once I had identified the primary technologies, I looked for others to fill gaps and help build a cohesive solution. The goal was to limit the amount of code that needed to be written or maintained while securely exposing my OData WCF RESTful services. The technologies I linked together are: ACS, OData, Entity Data Models, WCF Data Services with Entity permissions and a custom Azure security implementation. Each of these technologies already provides significant value on its own, but when combined, their value increases exponentially. Figure 1 demonstrates a high-level overview of how some of these technologies will work when implemented.

High-Level Overview of ACS with a Security Intercept
Figure 1 High-Level Overview of ACS with a Security Intercept

Before I tried to combine all of these technologies, I had to take a step back and really understand each one and how they could impact this project. I then gained a good perspective on how to combine them all and what would be required from someone else using other technologies to consume my services.

What Is ACS?

ACS is provided as a component of the Azure platform. ACS allows me to set up my own cloud-based federated authentication and authorization provider that I use to secure my OData WCF services, but ACS can also be used for securing any app. ACS is a cloud-based service that helps bridge the security gap when there’s a need to implement single sign-on (SSO) in multiple applications, services or products—either cross-platform or cross-domain—supporting various SSO implementations. an Azure account provides access to much more information. You can sign up for a free trial at windowsazure.com. To read more about ACS, see bit.ly/zLpIbw.

What Is OData and Why Would I Use It?

OData is a Web-based protocol for querying and updating data, and exposing the data using a standardized syntax. OData leverages technologies such as HTTP, XML, JSON and the Atom Publishing Protocol to provide access to data differently. Implementing OData with the Entity Framework and WCF Data Services provides many great benefits.

I started to wonder why I would use this versus custom WCF contracts. The answer was straightforward. The most practical reason was to leverage service documentation that’s already available and use a standardized syntax supporting how to access data from my service. Having written dozens of services, it seems that I always need to add an additional method as a result of providing custom services. And consumers of custom services tend to ask for more and more features.

 For more information on OData and OData URI conventions, visit the following sites:

OData with the Entity Framework and WCF Data Services

Using OData with WCF Data Services and the Entity Framework exposes standard functionality to support the retrieval and saving of data in a way that’s already documented with little implementation code. When I first started creating my Entity Data Model for Data Services Packaging Format (EDMX) and linked it to my WCF service through data services, I was very skeptical. However, it worked perfectly. All of the entities I included in my EDMX were automatically included and exposed in my WCF service in a RESTful implementation. Figure 2shows some example code.

Figure 2 Implementing OData WCF Data Services

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

I created an EDMX and linked that to a few of the tables in my database (Northwind Sample Database). I then linked my database entities to my WCF Data Service, exposing all of the entities by using the “SetEntitySetAccessRule” method with a wildcard attribute of “*” for all entities. This allowed me to set various permissions on my entities for read, write and query access as well as set the page size, as shown in Figure 2. The code shown is the entire implementation of the OData WCF Data Services code.

The service contracts, operation contacts and data contracts are mainly controlled via the configuration in the initialization of the service being provided. In the initialization method I have the ability to set various permissions related to how I’d like to expose my entities and what level of access I’d like to provide to anyone looking to consume my services. I could even leverage T4 templates to create an abstract layer or template layer on top of the entities with custom entity names. This would provide an added level of clarity to the consumer of my services. I could even set the permission for a specific table, or I could set the table name along with the appropriate security settings for even lower-level protection. Here’s an example of giving read access to the Customer table:

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

Many different security implementations can be enabled with OData and WCF Data Services, but for now I’m only concerned with how to protect my WCF services using ACS in combination with the data service’s access rules.

A quick list of the technologies used is shown in Figure 3, along with some of the reasons why these technologies would be used.

Figure 3 Technologies Used and Why

Technology Why Use It
ACS Provides a way to secure services using a cloud-based federated security module for authentication and authorization
OData Provides a standard syntax for querying and updating data while leveraging common technologies such as HTTP, JSON, the Atom Publishing Protocol and XML
Entity Data Models Provide a quick way to create a common data access for a database tier while also providing serializable data contracts of tables in a database
WCF Data Services with Entity Permissions Exposes the Entity Framework data contract with the appropriate level of permissions for CRUD as a WCF RESTful service
Custom Azure Security Implementation Secures services (in this case OData services) from being consumed without the proper level of security being applied, such as a token or certificate

With each of these technologies there are always trade-offs based on the project, but I found that combining them saved up-front setup time and reduced maintenance efforts, while requiring less code and providing huge gains—especially when I needed to expose my data securely and supply common data-access methods with a standardized syntax.

Putting It All Together

With a fairly good understanding of the combined use of OData, the Entity Framework and WCF Data Services, I could apply some additional security features to this technology by leveraging ACS. There were a few options to secure my service from being accessed, including setting various permissions on the entities or adding query interceptors to prevent service consumption or control how my service could be consumed.

However, implementing query interceptors or setting permissions would be tedious, and adding a layer of security on top of my service to protect it from being consumed was preferred rather than writing additional code. Implementing a common security mechanism that allows trusted parties or external companies to access my services would be ideal. In turn, I could use a combination of this security along with the entity protection to give my services the most secure implementation with the most flexibility.

Using this approach would require any consumer of my service to first authenticate through ACS and obtain a valid access token. The services would be restricted without this access token. Valid access tokens would be required in the request header before anyone would be granted access to my service. Once the consumer of my service was authorized, I’d apply fine-grained security on the entities to ensure only authorized access to the data or my entities.

ACS Setup and Configuration

Some setup and configuration is required in order to implement ACS. Figure 4 shows a list of items that I set up for this example.

Figure 4 ACS Setup

Configuration Values
ACS Namespace WCFoDataACS
Replying Party Application

Name: wcfodataacsexampleDevelopment

Mode: Leave defaults (enter settings manually)

Realm: https://localhost/WCFDataServiceExample/<servicename>.svc

Return URL: Leave default (blank)

Error URL: Leave default (blank)

Token Format: SWT

Token Encryption Policy: Leave default (none)

Token Lifetime: Leave default (600)

Authentication Settings

Identity Providers: Uncheck Windows Live ID

Rules Group: Check Create New Rule Group

Note: I created different settings for development, test and production.

Token Signing Settings

Click on the Generate button

Effective Date: Leave defaults

Expiration Date: Leave defaults

Rule Group Note: Based on my settings, the rule group will be created automatically, but I’ll still need to add the claim configuration.
Claim Configuration

If Section:

Access Control System: Selected

Input claim type: Leave default (any)

Input claim value: Leave default (any)

Then Section:

Output claim type: Leave default (pass through input claim type)

Output claim value: Leave default (pass through input claim value)

Rule Information:

Description: Leave default or enter a description

Service Identity Within Windows

Name: the username to provide others (in this example I used wcfodataacsDevUser)

Description: Leave defaults (or enter a description for the user)

Realm: https://localhost/WCFDataServiceExample/<servicename>.svc

Credential Settings:

Type: Select password

Password: Enter the desired password

Effective Date: Leave defaults

Expiration Date: Leave defaults

Note: There are several options for how to authenticate a user into the services created, but for simplicity, I used a password entry as the credential type. There are other options available—such as using a x509 certificate or a symmetric key—that may provide a higher level of security, but for this example I tried to keep it basic.

After completing the setup of ACS, I was able to secure my OData WCF RESTful services. Before I could secure them, I first had to implement a custom security module that could intercept the requests and validate the security to prevent unauthorized access.

ACS Security Implementation

As an example, I implemented the security using a custom HTTP module. This intercepts any request made to my service and validates if the proper authentication and authorization have occurred. Without this HTTP module, my services would be secure only at the entity level, based on the settings in the data service configuration.

In this case, I secured these services with ACS; therefore, requests were intercepted and then checked for the proper level of security to make sure the consumer of the service had been granted the proper level of authorization. As noted earlier, fine-grained security could be implemented at the entity level after the consumer of the service had been authorized access.

When implementing the IHTTPModule interface, I chose to add some additional features, so I exposed parts of the service metadata in order to allow consumers of the service to auto-generate classes (similar to the behavior of adding any other Web service). I added these sections of code as configurable attributes that can be enabled or disabled for added security, testing and to ease the integration effort.

Figure 5 shows code that intercepts the requests and performs the proper security validation.

Figure 5 Security Validation

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

Azure SDK

I pulled a class from the Azure SDK to perform token validations for this implementation. The project can be found at bit.ly/utQd3S. After installing the SDK, I copied the file named “tokenvalidator.cs” into a new project. In this particular class, I called the validation method to determine if the user was authorized via the information configured in ACS. To simplify this implementation, I created a custom DLL with only the security mechanism needed. After creating the assembly, all that was needed was a reference to the security DLL with my OData WCF service. The result: a protected and secure implementation.

Implementation of the Secure OData Service

With the additional security enhancement in place, securing the OData WCF service became easy. All that was needed was a reference to the “Azure.AccessControl.SecurityModule” assembly, and to add in the additional configuration settings. Then the security features would be enabled. Figure 6 shows the security configuration settings.

Figure 6 Security Configuration Settings

<appSettings>
  <add key="acsHostName" value="accesscontrol.windows.net" />
  <add key="serviceNamespace" value="Service Namespace" />
  <add key="trustedAudience"
    value="https://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>

Depending on the security settings, consumers of my service can be restricted to see only the metadata. This is extremely beneficial because users can still reference the entity objects and properties in code, simplifying the implementation. To disable the metadata, I set the attribute “enableMetadata” to false, so consumers of my service would no longer be able to access the metadata. If consumers of my service were only accessing it via client-side code, I wouldn’t enable the metadata because it wouldn’t be necessary. The service does appear the same as a normal Web service when the metadata is enabled, but without the ability to consume it without proper authentication and authorization, as shown in Figure 7.

OData WCF Service with Metadata Exposed
Figure 7 OData WCF Service with Metadata Exposed

This works almost the same as using the Entity Framework directly for the implementation code, with a few minor differences. The key code segment to add is the required token in the request header when sending data to the OData WCF service. I’ll explain how the security mechanism works, in essence. First, it checks the header for a valid token and checks if all its components are OK, such as the target audience, token expiration and token value. Next, the request is authorized and the call to the service succeeds. Intercepting this request prior to returning any data to the consumer of the service ensures that the caller of the service had to obtain a valid token prior to being granted access to any data.

At this point—depending on the level of security required on the entity objects—the consumer of the service is able to perform any functionality exposed by the service based on the security settings set. Where the security isn’t enabled, the consumer of the service receives an exception that indicates that the action performed isn’t allowed.

Unlike traditional Entity Framework code, more logic needs to be implemented prior to calling the Azure-secured OData service. With the HTTP module protecting the service, I need to make sure that I first authenticate to Azure and receive a valid access token prior to calling the OData service. The token received from ACS will be passed through in the request header for every request made to the secure OData service. An example request is shown in Figure 8.

Figure 8 Example Token Request

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

Once the token is received back from Azure and the user is successfully authenticated and authorized, a token will be returned back from ACS to use for all future requests until the token expires. At this point, implementing the Entity Framework is almost the same as if I were connected to a local database or a database in my network. Figure 9 shows the consumption of the OData service with an access token.

Figure 9 Consuming the OData Secure Service with an Azure Access Token

// First things first: I obtain a token from 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
  // ...
}

Implementing the code via client-side script is also just as easy as making an AJAX call to my service endpoint. Figure 10 shows consuming the OData secure service from client-side script.

Figure 10 Consuming the OData Secure Service from Client-Side Script

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

A RESTful service provides greater implementation flexibility and is easily consumed via Java or other client-side scripts or APIs. Authentication and a token are still required in order to consume the service, but OData is standard regardless of the platform due to the query syntax. Figure 11 shows consuming the OData secure service with an Azure access token in Java.

Figure 11 Java Implementation of Consuming the OData Secure Service with an Azure Access Token

String serviceMethodUrl =  
  "https://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;
  }
}

To summarize, I often find the need to expose data in a manner that would require some level of security to prevent unauthorized access. Using ACS supports this need by leveraging a cloud-based federated service to protect not only my OData WCF Data Services, but many other applications as well.

With that said, using WCF Data Services alone would require the implementation of individual data contracts and query interceptors for the data to be exposed. Using the Entity Framework in combination with WCF Data Services provides the ability to leverage database entities as data contracts—and these contracts are provided in a format that’s already set up (serializable objects that are accessible via OData). The final piece of the puzzle is to make sure that my OData WCF RESTful services are protected from unauthorized access. Using ACS, OData and the Entity Framework wrapped by WCF RESTful services provides a quick way to expose my data while using standard query syntax with an additional layer of security.


Sean Iannuzzi is a solutions architect for The Agency Inside Harte-Hanks, leveraging best practices for enterprise, system and software solutions. He enjoys learning new technologies and finding ways to leverage technology to help businesses and developers solve problems. He blogs at weblogs.asp.net/seaniannuzzi and you can follow him on Twitter at twitter.com/seaniannuzzi.

Thanks to the following technical expert for reviewing this article: Danilo Diaz