News, examples, tips, ideas and plans.
Thoughts around ORM, .NET and SQL databases.

Wednesday, April 27, 2011

DataObjects.Net Contribution Program Rocks!

Hello All!

Today I'm proudly presenting one more participant of the program — Mr. Alexander Ovchinnikov! Alexander is the one who created DataObjects.Net Driver for LINQPad tool. Loud ovation!

Let's find out how the power of LINQPad & DataObjects.Net can be utilized:

First of all, download LINQPad and install it. Secondly, download the driver. It is named "LINQPadDriver.lpx" and is located in Bin\Latest directory of "Binaries for .NET 4.0" package, build 7475 or later.

Next, launch LINQPad application. Click "Add connection" link. In the opened window click "View more drivers..." button.



In the next window click "Browse..."


Locate LINQPadDriver.lpx and open it.


After that LINQPad will show a message box that the driver is loaded. Select "DataObjects.Net" from the list of available drivers and hit "Next"


Connection configuration window will be shown. Here you should set connection name, domain connection url and add all required assemblies with persistent types to the list. I added the one from the upcoming security sample which in turn is based on Northwind model.


After several endless seconds, the domain is built and the domain model is populated to the left pane.


That's it. Now you can write LINQ queries and execute them. Note that you should start a query with Query.All<Entity> as you usually do in DataObjects.Net-based projects.
BTW, look how structures are displayd. Beautiful!


SQL tab also works. Don't know why it doesn't provide word wrapping, though =(.


Alexander has received DataObjects.Net Ultimate edition as a reward and additionally promised to continue the driver support/maintenance. The driver itself will be included into DataObjects.Net 4.5 and is already available today as a part of DataObjects.Net alpha 2.

Developers!
Wanna get the license for free? Choose a feature (or more) from the feature list and join da game! The reward is guaranteed.

Monday, April 25, 2011

DataObjects.Net stable versions are updated

Hello All,

On Friday, April 22, both stable versions of DataObjects.Net (v.4.3 & v.4.4) were updated to the latest revision. A couple of bugs are fixed:

- Persistent interface with paired EntitySet field bug
- Alias generator for computed columns was generating not so smart aliases
- Upgrade from 4.3 to 4.4 version threw an exception ("No upgrade handler is found for assembly 'Xtensive.Storage', version '1.0.0.0'.").

The updated installers as well as binaries can be downloaded from the official website: dataobjects.net

Friday, April 15, 2011

On security system, part 4

This is the forth part in a series of posts that is dedicated to security system concept in DataObjects.Net. In the previous part I described Role & Permission types and their relationships in context of entity access based on entity type. This part of the concept answers the question whether a user has access to entities of a persistent type or not and what kind of access if yes (read, write, approve, you name it).

In the part where the requirements were listed there was another set that defines some business rules applied to the set of entities that are accessible to a user. Remember, Sales Representatives can edit only their own Order instances, while Sales Managers can edit both their own orders as well as orders of stuff from their Sales Department and so on.

Let me recall the matrix:


So, we should have an option to restrict the set of Customers and Orders visible for Sales Representative & Sales Manager roles. These requirements are more like full-fledged business rules applied to the entire set of Customers & Orders than just a security issue, thus they rarely can be implemented in terms of ACL model.

Having Permission<T> class we can add there a property that will hold an IQueryable<T> object that will be used to describe the entire set of entities of type T that is accessible to a role that contains the permission.

Here is the definition of the Permission<T> class:

public class Permission<T> : Permission where T : class, IEntity
{
  public Func<SecurityContext, IQueryable<T>> Query { get; protected set; }
  ...
  public Permission(bool canWrite)
    : base(typeof(T), canWrite)
  {
    // If not set explicitly, all entities are accessible by default
    Query = context => context.Session.Query.All<T>();
  }

  public Permission(bool canWrite, Func<SecurityContext, IQueryable<T>> query)
    : base(typeof(T), canWrite)
  {
    Query = query;
  }
}

Having such an option, we can use it to explicitly define the accessibility-related business rules. Let's start with Sale Representative. This role restricts access to Order entities to those that are created by particular sales representative. So we have to define a rule that will build an IQueryable<Order> and register it properly. Here is how:

public class SalesRepresentativeRole : EmployeeRole
{
  private static IQueryable<Order> GetOrdersQuery(SecurityContext context)
  {
    // Sales representative role has access to its own orders only
    return context.Session.Query.All<Order>()
      .Where(o => o.Employee == context.User);
  }

  public SalesRepresentativeRole()
  {
    RegisterPermission(new OrderPermission(canWrite:true, canApprove:false, GetOrdersQuery));
  }
}

I won't focus on SecurityContext for now, The only thing that we should know about it is that it contains a Session and a User.

Note that we use Func<SecurityContext, IQueryable<T>> because we need to dynamically resolve the IQueryable<T> depending on the security context, currently active session, etc.

Using the same technique we can define restrictions for Sales Manager role:

  public class SalesManagerRole : SalesRepresentativeRole
  {
    private static IQueryable<Order> GetOrdersQuery(SecurityContext context)
    {
      // Sales manager role has access to its own orders as well as to orders of his department
      return context.Session.Query.All<Order>()
        .Where(
          o =>
          o.Employee == context.User ||
          o.Employee.In(
            context.Session.Query.All<Employee>().Where(e => e.ReportsTo == context.User)));
    }

    public SalesManagerRole()
    {
      // Sales manager can do sale orders approval, in addition
      RegisterPermission(new OrderPermission(canWrite:true, canApprove:true, GetOrdersQuery));
    }
  }

Note that actually we don't need ACLs or something artificial for defining the restrictions. Imagine a database with thousands and billions of entities and every single one must have one or more records that store entity's owner & all users that should have access to it. That's not an option. Pure business objects from the domain model and their relationships are enough for business rules of almost arbitrary complexity.

Now let's define business rules for Sales Representative & Sales Manager roles for accessing Customer objects. There is a rule that says that both of them should deal only with those customers that are from their local region. In this sample there are 2 sales departments, one is located in London, another is in Seattle. Thus, I split all customers into 2 groups: customers from the Old World & customers from the New World. The first group is served by the London sales department, the second one is by the Seattle one.

To simplify things I added a helper class that contains 2 groups of countries:

public static class WellKnown
{
  public static IList<string> NewWorldCountries;
  public static IList<string> OldWorldCountries;

  static WellKnown()
  {
    NewWorldCountries = new List<string>()
                          {
                            "Argentina", "Australia", "Brazil", "Canada",
                            "Mexico", "USA", "Venezuela"
                          };
    OldWorldCountries = new List<string>()
                          {
                            "Austria", "Belgium", "Denmark", "Finland",
                            "France", "Germany", "Ireland", "Italy",
                            "Japan", "Netherlands", "Norway", "Poland",
                            "Portugal", "Singapore", "Spain", "Sweden",
                            "Switzerland", "UK"
                          };
  }
}

Having that done, I can describe the customers-related business rule as follow:

public class SalesRepresentativeRole : EmployeeRole
{
  private static IQueryable<Customer> GetCustomersQuery(SecurityContext context)
  {
    // Sales representative role has access to local customers only
    var employee = (Employee)context.User;
    if (employee.Address.Country.In(WellKnown.NewWorldCountries))
      return context.Session.Query.All<Customer>()
        .Where(c => c.Address.Country.In(WellKnown.NewWorldCountries));
    else
      return context.Session.Query.All<Customer>()
        .Where(c => c.Address.Country.In(WellKnown.OldWorldCountries));
  }

  public SalesRepresentativeRole()
  {
    // Sales representative can see and edit customers
    RegisterPermission(new Permission<Customer>(canWrite:true, GetCustomersQuery));
  }
}

Is't that good? As the role structure is hierarchical, this business rule is automatically inherited by all descendants of Sale Representative role, if not overridden. This means that there is no need to duplicate it in Sales Manager role. However, as Sales President role shouldn't have such a restriction we properly override that permission:

public class SalesPresidentRole : SalesManagerRole
{
  public SalesPresidentRole()
  {
    // Overriding the inherited permission with restriction, so this role will have access to all customers
    RegisterPermission(new Permission<Customer>());
    ...
  }
}

That's all for today. In the next part I'll describe the SecurityContext class and related stuff in details.

Big note for all:
The security concept I'm talking about is a prototype. Its purpose is to find out the better way to implement the security in DataObjects.Net. The only way I can see this can be done right is to criticize & discuss the thing before it is implemented and released. I know that the most of DataObjects.Net users are mature and experienced developers that have numerous properly built applications that have their own security systems. Therefore, I'm hoping that it will be better to join our efforts and make the security system that will perfectly fit our needs.

For now, I would like to specially thank Vlad Klekovkin for his critics of the prototype. Vlad also shared a concept of his own security system built on top of DataObjects.Net.
Thanks a lot, Vlad!

Wednesday, April 13, 2011

DataObjects.Net 4.5 Alpha 1

We are pleased to announce the availability of DataObjects.Net 4.5 Alpha 1. This build includes all the fixes that are made to stable 4.4 version as well as two brand new data providers: Firebird 2.x & MySql 5.x, thanks to Csaba Beer & Malisa Ncube (thunderous applause here!).

As it is alpha, there are some limitations, such as:
- Upgrade doesn't work yet in most scenarios for both Firebird & MySql. Hence, use 'Recreate' to update the database schema.

Examples of ConnectionUrls/ConnectionStrings for these 2 providers are like the following:

// MySql
var connectionUrl = @"mysql://user:password@myserver:3306/database";

// Firebird
var provider = "firebird";
var connectionString = @"User=user;Password=password;Database=C:\Program Files\Firebird\Firebird_2_5\database.fdb;DataSource=myserver; Port=3050;Dialect=3; Charset=NONE;Role=;Connection lifetime=15;Pooling=true; MinPoolSize=0;MaxPoolSize=50;Packet Size=8192;ServerType=0;";
// or
var connectionUrl = @"firebird://user:password@myserver/C:\Program Files\Firebird\Firebird_2_5\database.fdb?Port=3050&Dialect=3&Charset=NONE&Role=&Connection lifetime=15&Pooling=true&MinPoolSize=0&MaxPoolSize=50&Packet Size=8192&ServerType=0";

The binaries are available at the corresponding section of Downloads page.

Feedback of any kind is highly appreciated.

Note: this is alpha version, it is not intended to be used in production.

Tuesday, April 12, 2011

On security system, part 3

This is the third part in a series of posts that are dedicated to security system concept in DataObjects.Net. The first part contained common considerations and bits of theory, the second one was about the approach in development and the requirements to security system.

In this part I'll describe main blocks of security system architecture, i.e. roles & permissions.

First of all, let's start with roles. As you might remember, there is a list of positions in our imaginary sales organization:
  • Stock manager 
  • Sales representative 
  • Sales manager 
  • Sales president
I won't list their particular duties and access permissions again as this information can be found in the previous post. The thing that must be mentioned here is that each position executes one or more roles within the company, for example, Stock manager is also an employee, so Stock manager position includes some basic duties as well as duties specific to stock manager. The same goes for Sales manager, he not only have to approve orders but also acts like a sale representative as well as a common employee. Therefore, these positions can be arranged into accurate hierarchical structure according to the rule of inheritance. Luckily, RBAC level 2 declares support for roles hierarchies, and so does our security model.

Role hierarchy for the imaginary sales company:

Note, that each role is defined as a separate class. This approach as any other one has advantages and well as drawbacks. It is less dynamic, but provides natural inheritance, doesn't require persistence and is more intuitive, visual and understandable. Moreover, as roles in a company are mostly static, I've found the approach highly advantageous.

Look, EmployeeRole inherits a Role class. This is the base role class, it provides inheritors with necessary infrastructure: a set of Permissions for a role, name of a role and a method for permission registration.

To continue with roles hierarchy configuration we should define a permission first. According to the access matrix in the previous post, there are 2 common permissions that are actual for all kind of entities: Read permission & Write permission. In addition to these basic ones, there might be extended permissions as well, like Approve permission defined for Order entity type. Thus, we've defined a base Permission type and OrderPermission inheritor that provides requested functionality:

Let's see how these roles and permission are intended to be used. Let's start with the EmployeeRole first.  As it is mentioned above, all company positions have at least read-only access to employees & products, we can define the base Role node for this organization and call it EmployeeRole. Let this role is given to any employee in the company.

Here is how EmployeeRole is declared:

public class EmployeeRole : Role
{
  public EmployeeRole()
  {
    // This is base role for every employee

    // All employees can read products
    RegisterPermission(new Permission<Product>());
    // All employees can read employees
    RegisterPermission(new Permission<Employee>());
  }
}

That's it. Now all employees have a permission to read Products & Employees.

What about the Stock manager role? Stock manager should inherit the base EmployeeRole and add permission for editing products.

public class StockManagerRole : EmployeeRole
{
  public StockManagerRole()
  {
    // Stock manager inherits Employee permissions

    // Stock managers can read and edit products
    RegisterPermission(new Permission<Product>(canWrite:true));
  }
}

As I've already mentioned, the advantage of the class-based approach in role hierarchy definition is in its essential inheritance support. Derived role can inherit all permissions and other options of the base class and override something if is necessary. This is achievable in the most natural way for developers: make an inheritor & override all you need.

On the other branch of roles hierarchy, Sales representative role also inherits the base EmployeeRole and should add permissions to edit customers and orders. In order to add Order permission we should define OrderPermission first, where a property CanApprove should be included. Here it is:

public class OrderPermission : Permission<Order>
{
  public bool CanApprove { get; private set; }

  public OrderPermission(bool canWrite, bool canApprove)
    : base(canWrite)
  {
    CanApprove = canApprove;
  }
}

Having declared the OrderPermission, we can proceed with SaleRepresentativeRole class:

public class SalesRepresentativeRole : EmployeeRole
{
  public SalesRepresentativeRole()
  {
    // Sales representative inherits Employee permissions

    // Sales representative can read and edit customers
    RegisterPermission(new Permission<Customer>(canWrite:true));
    // Sales representative can read and edit sale orders but not approve
    RegisterPermission(new OrderPermission(canWrite:true, canApprove:false));
  }
}

As for Sales manager role, it inherits Sales representative role and adds permission to approve orders. Here is how:

public class SalesManagerRole : SalesRepresentativeRole
{
  public SalesManagerRole()
  {
    // Sales manager inherits Sales representative permissions

    // Sales manager can do sale orders approval, in addition
    RegisterPermission(new OrderPermission(canWrite:true, canApprove:true));
  }
}

The last one is Sales president role. It in turn has access to all entities in read-only mode plus write permission to Employees, so we have to override permissions declared in its ansector (SalesManagerRole):

public class SalesPresidentRole : SalesManagerRole
{
  public SalesPresidentRole()
  {
    // Sales president inherits Sales manager permissions

    // Sales President can read all, but can't alter any details, except employees. They usually need read-only aggregated reports, actually
    RegisterPermission(new Permission<Customer>());
    RegisterPermission(new Permission<Order>());
    RegisterPermission(new Permission<Product>());
    RegisterPermission(new Permission<Employee>(canWrite:true));
  }
}

Note the clarity and the ease of permissions overriding.

That's all for today. For now we have permissions and roles defined. Hence, we've got a mechanism that can be used to describe the access matrix from the previous post in full manner:

Tuesday, April 05, 2011

On security system, part 2

This is the second part in a series of posts that are dedicated to security system concept in DataObjects.Net. The first part contained common considerations and bits of theory.

In this part I'll tell you about the development approach we chose.

To avoid the situation when a framework is being built according to some pure theoretical ideas and as a result it is hard to use it in real world scenarios we had decided to start from the other side: try implementing an application that seems to be more or less real, put into practice our security concepts and thus develop the security system.

We chose Northwind database model as a playground and slightly modified it to add some complexity in company staff relationships.

Here is the updated organization chart for our Northwind company.

There are 2 sales departments: first is located in Seattle and second is in London. Both of them are managed by a sales manager, each of them has 2 sales representatives and 1 stock manager. Sales representatives report to sales manager, both sales managers report to sales president.

In this application model we defined the following main types of entities to secure:
  • Customer
  • Order
  • Product
  • Employee
There could be much more types to secure but there is no necessity as those four is enough to build more or less authentic model.

Next we have to define which company staff will have access to these secured entities, and which won't. Moreover, there might be several levels of access, for example, read, write and any other more specific ones.

According to the organization chart, we define 4 main roles:
  • Stock manager
  • Sales representative
  • Sales manager
  • Sales president
Each of them has its own set of duties, responsibilities, permissions and limitations. In our model there is the following distribution of all that stuff:
  • All staff has read-only access to employees data.
  • Stock managers manage products. They doesn't have access to customers and orders.
  • Sales representatives have read-only access to products, have full access to customers of their sales department and their own orders. They don't have access to order approval.
  • Sales managers also have full access to customers of the sales department, to their own orders and well as to orders of sales representatives in their sales department. Moreover, sales managers have access to the order approval operation.
  • Sales president has access to all kind of information without limitation, but in read-only mode. In addition, he can manage employees (hire, dismiss, so he also has write access).
Here is the graphical matrix that shows access rights to entity types:


This matrix that demonstrates the additional limitations that must be met as well.


So, here is the deal: we need to provide a flexible and efficient security framework that can be used in domain models like this one with all above-mentioned permissions and limitations. In the next post I'll show you whether we managed to achieve the goal and how we did it.