Showing posts with label wcf. Show all posts
Showing posts with label wcf. Show all posts

Thursday, March 21, 2013

WCF Security - Service Authorization Manager

In the previous posts, we have seen two possible options of authorization / access control including PrincipalPermission and directly using ServiceSecurityContext for authorizing users from the same active directory domains. With PrincipalPermission() we need to provide the security logic on each service operation with an option of using PrinicipalPermissionAttribute. Using ServiceSecurityContext, we included the authorization logic in service operation code which makes it convoluted. What if we need to only authorize certain users for the service i.e. all operations of the service. The feature can be implemented by using the extensibility features in WCF. We can use ServiceAuthorizationManager for the same.

Based on Security Architecture document on MSDN, ServiceAuthorizationManager is used to perform two steps for the incoming message. The first step is Authorization Policies Evaluation Stage, Here It is used to evaluate authorization policies where claims can also be added to the evaluation context. Here external authorization policies can also be used. As the second step [Service Authorization stage], the authorization policies can be used to perform the actual authorization. In the document, the steps are specified as follows in the WCF pipeline:



ServiceAuthorizationManager is provided as follows:



As we can see that there are two overloads of CheckAccess() method. Additionally, there are two virtual methods CheckAccessCore() and GetAuthorizationPolicies(). If we dotPeek the code, we can verify the flow described by the MSDN document. As you can see that it iis first calling GetAuthorizationPolicies() and then after using the authorization policies to create a ServiceSecurityContext, it is using the CheckAccessCore() method. The default implementation of CheckAccessCore() is PERMIT ALL i.e. it returns true, we can override this to perform the required authorization.



In order to understand it further let us add a custom definition of ServiceAuthorizationManager. It is non-sealed so we can directly inherit from it and override the virtual members. Based on the code flow of CheckAccess() described above, we just need to override CheckAccessCore() and GetAuthorizationPolicies() methods. For now, let's just use the logic provided by the base class i.e. ServiceAuthorizationManager.

Now in order for the service to use this, we must add this behavior, let's update the App.Config. As you can see we are still using WindowsGroups as the principal permissions. We would be providing the actual authorization using the same groups.

In order to test that the service authorization manager is actually being used by the service. Add some breakpoints and execute the code, you should see that GetAuthorizationPolicies() is called first followed by CheckAccessCore() method.



Here we have used the same WCF Test Client as we have been using in the previous examples:



Now let us provide the same authorization logic we have provided in the last two examples. We only want subjects from Traders group to have access to our service. Since the same WCF pipeline is used for metadata requests as well, we need to first determine if this is such request. If so we can allow the operation. There is no user specific security information for metadata request including claims and domain groups. For other service operations as well, the header action is set accordingly.

Let's execute the code, as you can see the authorization logic is correctly being used.



Here we have provided the code for service level authorization logic. For more fine grained security based, we can use the request header actions.

Download

Tuesday, March 19, 2013

WCF Role Based Authorization using ServiceSecurityContext

In this post we are going to discuss how we can use ServiceSecurityContext for authorization. Although it is not recommended a lot but I have seen it being used in organizational setups more often than usual. In the last post, we discussed about PrincipalPermission based roles authorization. Here roles are Windows / Domain groups. Since the service is able to validate the users based on these roles, it means that service has access to those groups from the client request. The whole idea is to access these roles and use them for our purpose. One such use is authorization. Actually, this information is part of message through SecurityMessageProperty.



We will be building on the previous example so you might want to get that code first [http://www.shujaat.net/2013/03/wcf-role-based-authorization-using.html]. Let's assume that we have the same security requirement as the previous example and we want that only those requesters which belong to the Traders group should be able to execute Trades. Let's update the service implementation as follows:

The above code is practically doing the same thing as in the previous post i.e. only allow Traders to execute the trades. I would specially emphasis to look at the definition of newly added AuthorizeUser() method. I have refactored it into a separate method just in case other service operations from the same service might require the same authorization then the would provide reusability. We can also define the authorize user in a configuration file or just read it from database and use it here for authorization. This would allow us to change it without requiring to recompile the code.

The first problem is to get our hands on the requester's roles. As discussed above, ServiceSecurityContext allows us to get the list of the groups from the request. It provides us the SIDs for the groups which can be translated into their names. Then we just need to check if the groups' collection has our authorized group. If so, then just allow the request to continue, otherwise, throw an exception.

The above is very simple implementation of the trade execution authorization. This example can be extended into allowing certain users to execute a certain kind of trade. In that case, we can create domain groups for each role and check if the requester belongs to such role before having allowing him to continue. In the following example, the requester must belong to MSFTTraders group in addition to being a trader in order to execute MSFT instrument trading.

Based on the above code, if I request the trade execution as follows then it should flow through fine. This is because, we have added the current user to Traders group. Since we are trading GOOG, it doesn't require any further authorization.



On the other hand, if we were trading MSFT, we should get the unauthorized access, as the current user doesn't belong to MSFTTraders group.



We get the following exception for the current user.



These roles can also be used to define the role specific service workflows. We can require requester, belonging to a certain groups, to get authorized or send an email to a control group watching the activities of traders which are fed to some regulatory authorities interested in such information. But I would leave that to work on that.

Download


Monday, March 18, 2013

WCF Role Based Authorization using Principal Permissions for Windows Groups

In the last few post we have been trying to set the stage to start discussing about creating Identity aware application architecture using Windows Identity Foundation [WIF]. We have been going through these posts to ease ourselves into the technology. This post is also to set one step towards that direction. This is to discuss role based security outside the Identity and Claims world. Please remember that this is the most common way we have been implementing security authentication and authorization in our services specially inside the firewall in an intranet organization setup.

Let's consider our organization as a financial type of organization where we have different applications and services to help the employees carrying out their activities. One such users are traders. They execute trades which are then forwarded to any specific exchange for placement. We need to make sure that only traders are allowed to execute trade. One such way is to check at the service level if the requester is a trader and allow the operation only under such case.

In WCF scenarios for a Windows Active Directory based domains, users belong to different domain groups. These groups are used by applications to determine the user privileges before executing the actual operation. The same approach has been traditionally taken to implement security for our services. This is exactly what we would be trying to discuss in this post. For our organization, let us assume that all traders belong to Traders group.

Let's start by creating a WCF Service Library project, TradeExecutionServiceLib.



Now let's update the name of the service contract and the implementation to ITradeExecutor and TradeExecutor respectively. Doing it on the solution explorer level would ensure that the class names are updated inside their respective files. This should also update the service configuration in App.Config file.



Now let us update ITradeExecutor as follows:

Here we have also included a service operation, ExecuteTrade(). This is certainly very simple way on the service side for looking at the trades execution but this should be enough to understand the concept of role based security authorization in WCF, which is the purpose of today's post. This requires the instrument's symbol and quantity to be passed as input parameters. Now we update the service implementation as follows:

The implementation is just writing the details about the symbol and traded quantity on the console. Now let us add authorization code. We need to make sure that only traders belonging to Traders group have access to ExecuteTrade() operation. In WCF and code access security scenarios, this can easily be implemented using PrincipalPermission attribute from System.Security.Permissions namespace in mscorlib assembly. We can also directly use PrincipalPermssion class in a non-declarative way.

Decorating Service Operations with PrincipalPermissionAttribute
One way to authorize user's role is to decorate the operation with PrincipalPermissionAttribute. Here Role would mean the Windows group we are specifically looking for. Now this becomes the responsibility of runtime hosting the service to ensure that the user of the service is a member of the specified group and deny access otherwise.

Now we need to test if the authorization logic is actually working. Since this is a very simple service, we don't need to build a special client just to test the service. Here we can simply use WCF Test Client installed using the framework. We don't even need to host this as Visual Studio would automatically host it to the default WCF Service Host. run this with the default service configuration. Just make sure that you have the service project set as start up project in the solution. Since we have only one project in the solution, this is the default case here. You should see the following toast appear in the system tray when you run the service.



If you double click the icon on the tray, you should see that service is hosted and the status should show as Started.



This should also launch WCF Test Client with the operations listed on the service.



Let us provide the input arguments for ExecuteTrade operation and hit Invoke. Since were debugging it, we should be able to see the following security exception in the visual studio editor:



If you continue the execution then you should see the following on the WCF Test Client side which just shows the client that there is something wrong with the request. When we write our custom clients we should be handling this case more gracefully showing the user the exact cause of the error or how to request permissions if he is a legitimate user of the service.



Since the service operation requires the user to belong to a certain role, it blows up as there is no such membership for the requesting user. Not even such a group exists on the machine [CHEETA]. To keep it simple, let us create a Windows Group using the Computer Management tool as follows:



Let's add the user (requester) to the Traders group now. See the highlighted information requiring the user to login again in order for the changes to take effect.



Now let us update ServiceModel section of the service configuration in App.Config to use Windows security. Here we have updated the binding to net TCP. We have also updated authorization behavior use Windows Accounts.

In order to test that the logic is actually working let us debug the code. Let us insert a break point on the ExecuteTrade operation side and run the service. As described previously the service is hosted and WCF Test Client is launched, we provide the same input arguments as before ("MSFT" and 100) and invoke service operation. since the user has such membership now, the security authorization logic calls the method and hits the break point.



The class hierarchy of PrinicipalPermissionAttribute is as follows:



Non-Declarative Permission Demands
In the above example we provided the required membership requirements by adding PrinicipalPermissionAttribute to the operation contract implementation. The same behavior can be achieved by doing the same thing in the code. The unauthorized access would be determined by WCF Service pipeline and an exception would be generated which would result in a fault for the user. In the below code, we are just updating the code to demand membership using the same Principal Permission, but using code.


The definition of PrincipalPermission is as follows:



If we look at the definition of PrincipalPermissionAttribute, it is using the same IPermission.



Download Code


Thursday, July 26, 2012

DataTable & WCF Service

In this post we will be discussing a minor issue with the serialization of DataTable in WCF. We, then would present its solution. The issue is that we cannot send a DataTable object across the wire for which TableName property is not set. If we do try to send it, it throws exception. The post would just have an example to show the issue and its solution.

There are a lot of material you can find, not recommending DataSet and DataTable on WCF boundaries. But you might run into situations where some architectural design decisions are horribly taken and you cannot change them. This case would be one of them. Or this might be a client requirement which needs data in this format.

Let's create a WCF Library project DataTableWCFApp.Service. We can update the service contract as follows:

We can use the following as the implementation of the ServiceContract interface presented above. This is just creating a untyped DataTable, filling it with a single row and returning it.

We wouldn't be able to test it using WCF Test Client because of non-primitive DataTable type which it cannot deserialize.


So let's create a simple MVVM Light WPF project to test it. Here we are creating a project with name DataTableWCFApp as follows:


After adding the service reference for the DataTable Service, we need to update the view and view model for showing the DataTable returned from the service. Let's update MainWindow as follows:

So the view expects a collection MyData in its DataContext. The collection is expected to be available at the time of loading the view, hence OneTime mode for Binding. Let's update the view model as follows:

Before running it, we need to find a way to host the WCF Service. Luckily Visual Studio makes it easier for us. Just check the following option is checked for your WCF project. This would host the WCF Service when another project in the solution is being debugged. If we set the WCF Service project as the start up project then this would host it in WCF Service Host, additionally, this would launch WCF Test Client for the service.

Now set the WPF Project as the Startup Project and run it. We get the following CommunicationException with no details about what actually happened or how to fix it.

In order to find the actual cause, let's take some help from WCF Service Trace Viewer. We need to add the following configuration in our WCF Service project's app.config file.

Now we can run it again. We would again get the same exception but the traces should be recorded in the location for the trace file as mentioned in the above configuration. Let's try opening the file using Microsoft Service Trace Viewer. We need to install Windows SDK for this tool. It shows the actual cause of the problem.
The error message is descriptive enough. We are just missing to set the TableName of the DataTable. The DataTable cannot be serialized without setting it. Let's update the Service to do the same as follows:

Now we run the project again. Now the service returns the response without any issue. The DataTable is used by the view to display it in a DataGrid. For an untyped DataTable, this would be the most suitable control as this can analyze data and create columns based on the data in the DataTable. Other control, e.g. ListBox would show DataRowView for each entry in the DataTable.


Download

Thursday, March 15, 2012

Visual Studio hosting WCF Services using WCF Service Host

In this post we are going to be creating a simple WCF Service library project. We are going to be hosting this using Visual Studio Service host. We are going to see what various options are available to launch a WCF Service using Visual Studio including how we can test it using WCF Service Client. We are also going to be using Process Explorer to see how these supporting tools are used by Visual Studio.

When we create a WCF class library project, then Visual Studio creates a default WCF service for us with default template. It creates the following in the project.
  1. Adds the relevant assembly reference to the project. This includes System.Runtime.Serialization.dll and System.ServiceModel.dll.
  2. Adds a WCF Service containing a simple method. The class implements a contract added separately. The method (defined as operation contract)
  3. Adds a interface decorated with [ServiceContract] attribute. This also has a method decorated with [operationContract] attribute. This is the same interface implemented by the above class.
  4. Adds a class decorated with [DataContract] attribute. This type is used as a parameter in the operation contract method of above service contract.
  5. Adds app.config to the project. The configuration has the details of the exposed WCF service.

  6. See the properties of a WCF Service library project. There is an additional WCF options tab added.



    There is only one configurable option for the WCF service. When checked, Visual Studio automatically launches WCF Service Host utility hosting the service even when there is another start up project in the solution. This is a Visual Studio supporting tool and gets installed with Visual Studio installation in the following path in your Windows 7 computer.

    C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\

    This is available as follows:


    Let's download Process Explorer to see the details about WCF Service Host process from the following technet link:

    http://technet.microsoft.com/en-us/sysinternals/bb896653

    When launched, WCF Service host is available in system tray as follows:


    The tray icon can be used to launch the tool's interface. The interface has the details about hosted service.


    • If the WCF class library project is the start-up project then the service host is launched with relevant start-up arguments to use WCF Test Client as the client tool for the hosted service. The service host takes care of launching the client tool. We can use Process explorer to see the start-up argument of service host process.

      It is basically launched with the following start-up arguments.
      /service:C:\Users\shujaat\documents\visual studio 2010\Projects\InstituteApp\Institute.Data\bin\Debug\Institute.Data.dll
      /config:C:\Users\shujaat\documents\visual studio 2010\Projects\InstituteApp\Institute.Data\bin\Debug\Institute.Data.dll.config
      /event:dc8e4802-046c-4134-97b3-0d940ab3ee82 
      /client:"WcfTestClient.exe
      
      Specifying the switch for client launches the WCF Test Client after the service is hosted in WCF Service Host tool. The WCF Test Client is launched with the start-up arguments specifying the service details.


    • When the service project is not selected as a start-up project then Visual Studio just launches the WCF Service host with the details of the service being hosted. The start-up arguments to launch WCF Service host are as follows:
      /service:C:\Users\shujaat\documents\visual studio 2010\Projects\InstituteApp\Institute.Data\bin\Debug\Institute.Data.dll
      /config:C:\Users\shujaat\documents\visual studio 2010\Projects\InstituteApp\Institute.Data\bin\Debug\Institute.Data.dll.config
      /event:56023077-b3b8-486d-8e62-ffc2ccf7cad7 
      We can see that all the parameters are same except the client is not expected to be launched so the client switch hasn't been specified.

Basically the additional start-up argument is the default start-up argument of WCF Service library project. It can be seen in the Debug tab of project properties. If we don't want the WCFTestClient to be launched when WCF Service runs as a start-up project then just remove this extra switch.


Download Code: