Andres Aguiar's Weblog

Just My Code

April 2004 - Posts

Role based security, permissions and the Authorization and Profile Authorization Block

The .NET Framework provides good support for role-based security. Once the user is authenticated, I can ask for IsInRole("Administrator") and do whatever I need to do.

The problem with this approach is that the way one assigns permissions to roles is usually dynamic, and hard-coding that in the application logic is not a good idea. For example, if I want to add a new role to my application, I need to go to every place and add logic to enable the role for the specific actions.

The solution to this problem is to define 'permissions', and then assign permissions to roles. Then you ask for the permission:

if (user.IsAuthorizedTo("AddCustomer"))

...

As far as I know there isn't a standard way to solve this with the .NET Framework. You need to roll your own solution.

When I saw the Authorization and Profile and Application Block, I assumed that one of the holes it will fill was this one, when I did a quick-read on the documentation it looks like it did. But it seems I was wrong.
 
In addition of providing roles, you have an 'scope' with 'operations' that you can give permissions to. Below is an example of one of the ways to define the permissions in an .xml file:

<user name="testuser">
  <roles>
    <role name="developer" />
    <role name="approver" />
  </roles>
  <scope name="http://localhost/AzManTestWebService/Math.asmx">
    <operation name="Add" hasAccess="true" />
    <operation name="Subtract" hasAccess="false" />
    <operation name="Multiply" hasAccess="false" />
    <operation name="Divide" hasAccess="true" />
  </scope>
</user>

Each user has roles, and it also has permissions to perform operations in a scope. Now you can do two things for checking for authorization. I can hard-code an IsInRole for the roles, as usual, or I ask is the user is authorized for one operation. But the operations permissions are assigned _per user_, not _per role_!. I don't see the reason to do it this way....

I would really prefer to use the following structure:

<?xml version="1.0" encoding="utf-8" ?>
<authorizationInformation>
  <roles>
    <role name="developer">
 <scope name="http://localhost/AzManTestWebService/Math.asmx">
           <operation name="Add" hasAccess="true" />
           <operation name="Subtract" hasAccess="false" />
           <operation name="Multiply" hasAccess="false" />
           <operation name="Divide" hasAccess="true" />
        </scope>
    </role>
  </roles>
  <users>
    <user name="testuser">
      <roles>
         <role name="developer" />
      </roles>
    </user>
  </users>
</authorizationInformation>

In this case the role has a set of permissions, and then I can ask for the permission in my code, add new roles and assign different permissions for this role.

Am I missing something? Is there any way to do this with the Authorization and Profile Authorization Block? A better way of doing it with the .NET BCL?

 

DataSets syntax

There is a good discussion about using DataSets and Customer entities here.

Even if I think DataSets is the way to go to represent database-bound data structures in .NET, there is one 'structural' thing that I don't like about DataSets (I also don't like some performance issues that will be addressed in Whidbey but that is an implementation issue and not an structural one).

When you use them for holding one instance of an entity (for example, one Customer), it's feels awkward to write:

dataSet.Customer[0].CustomerId

You don't always need to write this kind of code, because in a lot of cases you just need to bind the DataSet and let the data-binding infrastructure do its work (this is usually the case in Windows Forms), but sometimes you need to write it.

What we ended up doing in DeKlarit 3.0 is to provide the option of generating a wrapper layer on top of the DataSets that give you a better syntax, that does basically the following:

public Customer(CustomerDataSet.CustomerRow dataRow)
{
 m_DataRow = dataRow;
 m_DataSet = (CustomerDataSet) dataRow.Table.DataSet;
}

public Customer()
{
 m_DataSet = new CustomerDataSet();
 m_DataRow = m_DataSet.Customer.NewCustomerRow();   
}

public System.Int32 CustomerId
{
 get
 {
  return m_DataRow.CustomerId;
 }
 set
 {
  m_DataRow.CustomerId = value;
 }
}

We also added methods to perform persistence operation in these wrappers. For example, the 'Fill by primary key' method looks like:

public void Fill(System.Int32 customerId)
{
 DataAdapterFactory.GetCustomerDataAdapter().Fill(m_DataSet, customerId);
 m_DataRow = m_DataSet.Customer[0];
}

This means you can write:

Customer customer = new Customer();
customer.CustomerId = 1;
customer.Name = "Peter";
customer.Update();

And of course there is a 'DataSet' property that lets you access it in case you want to use it directly or bind to it.

We are also generating a 'CustomerCollection' that feels like a 'Customer' collection by wrapping a DataTable. This is the code for the indexer:

public Customer this[int index]
{
 get
 {
  return new Customer(m_DataTable[index]);
 }
 set
 {
  m_DataTable[index].ItemArray = ((Customer) value).CustomerRow.ItemArray;
 }
}

As you can see this is slighty more expensive because we copy the ItemArray when setting the row.

The CustomerCollection class has additional 'Fill' methods that load the DataTable in different ways (all the records, filtered by indexed fields, one page, etc).

Another interesting scenario is when you have a hierarchical DataSet (i.e., Order and OrderDetail). In this case we create a Order.OrderDetail class in addition to the Order class, and a Order.OrderDetailCollection class. Then you can write:

Order order = new Order();
order.Fill(100);

foreach (Order.OrderDetail detail in order.OrderDetailCollection)
{
     detail.Price = detail.Price * 1.2;
}

order.Update();


It should be easy to write a CodeSmith template that generates this code for any DataSet that has a 'tree' structure, so you can use this approach in your own DataSet-based applications.

Microsoft Business Framework

Here is the 'official' website for the MBF http://www.businessframework.com.

Sometime ago we bought the 'businessframeworkS.com' domain, I hope we don't get into trouble ;).

By the way, I've attended to an ISV event organized in the local MS office, and they keep saying it will be probably free.

As MS is a very big company with a lot of lawyers I don't think they'd say that and then charge for it, so I guess we can take that for granted.

It seems like a very powerful platform. The challenge will be to make it easy enough to use.

More Posts