.netTiers and SAP Authorization Rule Provider
One of the main benefits developers use Microsoft Enterprise Library Application Blocks for is handling application security aspects. Authorizing users against some tasks is always an essential requirement in any application. I am using .netTiers and I am more than pleased in the way it utilizes Enterprise Library different application blocks and as the .netTiers says its base architecture is built upon the Microsoft Enterprise Library Application Blocks. Anyway using entlib different blocks will save time, efforts and give you a standardized way to achieve common software requirements.
But this will not fit every time. Their is some certain scenarios where you need to do things by your self where the entlib will not be there or you need to handle some customized situations. At general entlib is very open, flexible and extendable. By utilizing available interfaces and abstract class's you almost could customize and extend application blocks.
As I said before .netTiers utilizing application blocks and one of those blocks being used is Security Application Block through the component layer. The component represents the business logic layer and you can choose from two options to do this in .netTiers by using Service layer-Manager Pattern- or Domain Model layer.
Security Application Block introduces two ways to read security rules:
- It provides the AzMan -Authorization Manager- which is a general purpose role-based security architecture for windows and we will not discuss AzMan here.
- SAP AuthorizationRuleProvider which located at Microsoft.Practices.EnterpriseLibrary.Security namespace.
- You can build your own and provider.
If we take a close look how .netTiers uses the provider in the default case -AuthorizationRuleProvider - we will find there is central place where all methods will go and check authorization this place called security context and it contains the authorization check method.
If we configured our data provider to enable method level authorization we will let each call to our data provider pass through security check. As we can see here using Provider Pattern -introduced by Microsoft -is a very powerful solution to develop configurable applications.
Before calling the data provider method this authorization check will decide if the current user identity is authorized to do or call this method. Here is where SAP is involved.
If the user is not authorized its throws an exception and don't call the data provider method.
The Problem?
If we enabled method level authorization it assumed that each method has it's own security rule. And this is not the real scenario because no developer loves to write authorization rules for all methods wrote to access his data provider. The .netTiers contains hundreds neither thousands of methods available and generated for you to start using. And the result is to have Authorization Rule Not Found exception ... see image below.
What do you say: no rule == free to go!
Yes, I think if we looked around ourselves in our daily life there is a general idea which if their is no rule to organize something then every body will treat as he well. If their is no rule to forbid you from access some resource so why not access? -of course ethical and convention took's place-
Anyway, as the rule provider contains a dictionary of rules. Simply, to walk around this problem we need to check if the rule exist firstly. If the rule exist then try to authorize the user against it. Else, allow user to access this method.
As the rules dictionary is private and we can't access then simplest way to implement this is to to modify the SAP source code and add a public method to do this check. And use this method to determine that we need to authorize user identity against this method or not.
/// Check if the scurity rule exist or not
/// </summary>
/// <param name="ruleName"></param>
/// <returns></returns>
public bool IsRuleExist(string ruleName)
{
if (authorizationRules[ruleName] == null)
return false;
else
return true;
}
Or we can modify the original Authorize to make this internal check
{
if (IsRuleExist(ruleName))
return true;
if (principal == null) throw new ArgumentNullException("principal");
if (ruleName == null || ruleName.Length == 0) throw new ArgumentNullException("ruleName");
InstrumentationProvider.FireAuthorizationCheckPerformed(principal.Identity.Name, ruleName);
BooleanExpression booleanExpression = GetParsedExpression(ruleName);
if (booleanExpression == null)
{
throw new InvalidOperationException(string.Format(Properties.Resources.AuthorizationRuleNotFoundMsg, ruleName));
}
bool result = booleanExpression.Evaluate(principal);
if (result == false)
{
InstrumentationProvider.FireAuthorizationCheckFailed(principal.Identity.Name, ruleName);
}
return result;
}