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.