An important concept to discuss is not a WCF Data Service feature. However, because a service is exposed as an ASP.NET application, every rule that applies to ASP.NET pages and services can be applied to a data service. For example, you can use Windows authentication for services exposed on the intranet, or whenever you have a domain that contains users and groups. In this scenario, you can also use digital certificates in the same way you would any other ASP.NET application.
If you want to expose your service on the Internet and protect it with credentials, you can leverage the .NET Security Principal in the way you prefer. For example, you can use the membership and role manager standard ASP.NET provider if you have a simple service, or you can create a custom provider to use your own storage technique. In case you decide to use the membership and role manager, it is important to disable (or, at least, to not use) the Forms Authentication mechanism because it redirects the request to a login page that is useless in a service request. The client must provide the credential in every request.
If you do not want to use the membership and role manager provider because they are not suitable for your scenario, you can leverage the underlying GenericPrincipal or create a custom principal to adhere to the .NET Framework security pillars. You can also integrate your solution with other trusted identity providers by using custom code or frameworks such as Windows Identity Foundation.
These scenarios are possible because a WCF Data Service can be hosted in an on-premises ASP.NET application or can be moved to the cloud. If you resolve to maintain your solution in an on-premises infrastructure, you can use the Internet Information Services (IIS) Windows Activated Service (WAS) to automate the activation of the engine or, even better, you can leverage the Windows Server AppFabric to simplify the management operations.
A WCF Data Service has two other ways to protect access to an entire entity set or to a single entity or a subset. In the examples at the beginning of this chapter, you saw the InitializeService static method, and you uncommented the first line to open your entity data model to every request that could reach the service. This internal mechanism can be used to specify access criteria for a single entity set. For example, you can make the salesmen entity readable, make the estates entity set updatable, and completely hide the other entity sets.
The enum EntitySetRights listed in Table 8-1 shows the various permissions of a single entity set.
| Entity Right | Description |
| All | Read operations are permitted. |
| AllRead | Read operations are permitted. |
| AllWrite | Read and write operations are permitted. |
| None | Denies all rights to access data. |
| ReadMultiple | Permission to read multiple data as in queries for different entities. |
| ReadSingle | Only access to single entity is permitted. The request for the entity set will be denied. |
| WriteAppend | Authorization to create a new entity in the entity set. |
| WriteDelete | Authorization to delete an entity. |
| WriteMerge | Authorization to update the data. Merge is referred to the Http method used to update the data. |
| WriteReplace | Authorization to replace data. |
The keyword * indicates that a right is assigned to every entity set.
When the client requests an operation not permitted by an access rule, the code receives a DataServiceException exception.
Every service exposes only the operations available on the EDM with some restrictions imposed by the client provider. You can also add some methods to your service to extend its functionality and let the client invoke the methods, because the metadata description instructs the proxy generator (DataSvcUtil.exe) to create a client method in the generated class.
The interesting thing about a new service operation is that it can have two kinds of security implications. The first is the simpler of the two, because it implies the definition of a ServiceOperationAccessRule in the same way the EntitySetRights does. For every operation, you can instruct the service how to respond to the client request. You can expose an operation, protect it as you want, and let the code verify the request before executing it. An operation is defined by code, so you can define whatever security logic you need. The complete set of rules for a service operation is listed in Table 8-2.
| Entity Right | Description |
| All | No restriction on service operations. |
| AllRead | Authorization to read single entity and complete entity sets returned by the service operation. |
| None | The service operation is not accessible. |
| ReadSingle | Only access to single entity is permitted by the service operation. |
| ReadMultiple | The service operation does not restrict access to an entity set. |
| OverrideEntitySetRights | The service operation rights override the permission defined by the entity set access rule. |
You can also define a new service operation by adding a method to the class that represents the WCF Data Service and assigning the classic WebGet attribute to it.
Example 8-23 shows two different security mechanisms applied in a newly defined service operation. You can use this code directly in the WCF Data Service you created at the beginning of the chapter.
Example 8-23. Service Operations added to the WCF Data Service.
public class EstatesManagement : DataService<Entities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// Examples:
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("SalesmanAdmin",
ServiceOperationRights.All);
config.DataServicebehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
}
[WebGet]
public IQueryable<Salesman> SalemanAdmin()
{
if (!Thread.CurrentPrincipal.IsInRole("Admin"))
throw new DataServiceException("You cannot access this method");
return this.CurrentDataSource.Salesmen;
}
[WebGet]
public IQueryable<Salesman> SalemanForManager()
{
if (!Thread.CurrentPrincipal.IsInRole("Manager"))
return this.CurrentDataSource.Salesmen.Where(s => s.Estates.Count < 100);
return this.CreateDataSource().Salesmen;
}
}In Example 8-23, the first service operation, named SalesmanAdmin, exposes the complete salesmen entity set only to users in the Admin role. The code is straightforward: it checks the role of the user using the standard .NET Framework technique to raise a DataServiceException (or a Security Exception, if you prefer) when the user doesn’t have the correct permission. To access an entity set from a service operation, you have to use the CurrentDataSource property exposed by the base class of your service.
The second operation shown in Example 8-23 illustrates a smart technique to filter data for a particular group of users and can be used for every check you need to perform in a solution. You just check the role and leverage the IQueryable interface of the EntitySet class to apply a filter on the salesmen entity set: for instance, when the user is not a manager, he cannot see any salesman with more than 100 estates assigned.
A similar result can be achieved with another feature of the WCF Data Service base class that is called the query interceptor. When a request comes in, it is up to the service to inspect the code to find a method with the QueryInterceptorAttribute attribute and execute the method before passing the query to the Entity Framework engine. The query interceptor replies to the request, returning an Expression<Func<EntitySet, Boolean>> in which you can express your filter to apply a security algorithm. The returned value is used by the service to enrich the query that will be applied to the EDM.
In Example 8-24, I applied a different security filter to the salesmen entity set, checking whether the user identity contains the string Roberto. The code returns a lambda expression that selects the nonadministrative salesmen.
Example 8-24. QueryInterceptor.
[QueryInterceptor("Salesmen")]
public Expression<Func<Salesman, Boolean>> OnQuerySalemen()
{
if (HttpContext.Current.User.Identity.Name.Contains("Roberto"))
return s => s.SalesmanIsAdmin == false;
else
return s => true;
}You can also define a query interceptor for CUD operations so that you can selectively choose which users and roles can perform a given operation.
Learn more about this topic from Windows Azure™ Step by Step.
Teach yourself how to build and host scalable applications in the cloud using Windows Azure—one step at a time. Ideal for those with basic programming skills, this tutorial provides practical, learn-by-doing exercises for working with the core services and features of the Windows Azure platform.

Help


