Automatic End to End Authorization (Part 2)

In my previous post, I talked about the importance of an end to end authorization system. I had an open source project here a while ago for this purpose. I describe the framework with some example here. An old saying says that a piece of code talk more than 1000 words:

Below is a sample class annotated with different authentication attributes.

<pre>
[Grant(Roles = new[] { "Everyone" }, Permission = Permission.View)]
[Grant(Roles = new[] { "QLDAdmin", "NSWAdmin" }, Permission = Permission.View | Permission.Edit | Permission.Create)]
[Grant(Roles = new[] { "Deleter" }, Permission = Permission.Delete)]
[Grant(Roles = new[] { "God" }, Permission = Permission.View | Permission.Own)]
[Deny(Roles = new[] { "NSWAdmin" }, Permission = Permission.Edit)]
[AuthorizationCustom(CustomType = typeof(TestObject), Method = "OnlyQld")]
public class TestObject
{
[Grant(Roles = new[] { "Everyone" }, Permission = Permission.View)]
[Deny(Roles = new[] { "God" }, Permission = Permission.View)]
public int YouCanSeeMe { get; set; }

[Grant(Roles = new[] { "Everyone" }, Permission = Permission.Edit)]
[Deny(Roles = new[] { "God" }, Permission = Permission.Edit | Permission.View)]
public string YouCanEditMe { get; set; }

[Deny(Roles = new[] { "Everyone" }, Permission = Permission.View)]
public string YouCanNotSeeMe { get; set; }

[Deny(Roles = new[] { "Everyone" }, Permission = Permission.Edit)]
public string YouCanSeeMeButNotEditMe { get; set; }

[Grant(Roles = new[] { "*" }, Permission = Permission.View)]
public string EverybodyCanSeeMe { get; set; }

public string[] States { get; set; }

public static Permission OnlyQld( IPrincipal pri, object instance )
{
var user = pri as TestUser;
if (user.Roles.Any(r => r.Contains("QLD"))
&&
(((TestObject)instance).States != null && ((TestObject)instance).States.Contains("QLD"))
)
return Permission.All;
return Permission.None;
}
}

</pre>

Next step is to check the permission for them in different scenarios:

<pre>[TestMethod()]
public void GetObjectLevelPremissionTest()
{
IMetadataClassProvider metadataProvider = new SelfMetadata();
var to = new TestObject();
var everyone = new TestUser() { Roles = new[] { "Everyone" } };
var god = new TestUser() { Roles = new[] { "God" } };
var adminNsw = new TestUser() { Roles = new[] { "NSWAdmin" } };
var adminQld = new TestUser() { Roles = new[] { "QLDAdmin" } };
var userWA = new TestUser() { Roles = new[] { "WAuser" } };
var userQLD = new TestUser() { Roles = new[] { "QLDuser" } };

var actual = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, everyone);
Assert.AreEqual(true, actual.Key.HasFlag(Permission.View));
Assert.AreEqual(false, actual.Key.HasFlag(Permission.Edit));
Assert.AreEqual(false, actual.Key.HasFlag(Permission.Create));

actual = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, god);
Assert.AreEqual(true, actual.Key.HasFlag(Permission.Own));

actual = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, adminNsw);
Assert.AreEqual(false, actual.Key.HasFlag(Permission.Edit));
Assert.AreEqual(true, actual.Key.HasFlag(Permission.View));

actual = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, adminQld);
Assert.AreEqual(true, actual.Key.HasFlag(Permission.Edit));
Assert.AreEqual(true, actual.Key.HasFlag(Permission.View));

to = new TestObject() { States = new[] { "QLD", "NSW" } };
actual = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, userWA);
Assert.AreEqual(false, actual.Key.HasFlag(Permission.View));

actual = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, userQLD);
Assert.AreEqual(true, actual.Key.HasFlag(Permission.View));
Assert.AreEqual(true, actual.Key.HasFlag(Permission.Create));

actual = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, adminQld);
Assert.AreEqual(true, actual.Key.HasFlag(Permission.Delete));
Assert.AreEqual(true, actual.Key.HasFlag(Permission.View));
}</pre>

Above code tests the permissions at the object level. We can get permissions at property level also in an array:

<pre>[TestMethod()]
public void GetPropertyLevelPremissionsTest()
{
IMetadataClassProvider metadataProvider = new SelfMetadata();
var to = new TestObject();
var everyone = new TestUser() { Roles = new[] { "Everyone" } };
var god = new TestUser() { Roles = new[] { "God" } };
var anon = new TestUser() { Roles = new string[0] };

var parent = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, everyone);
var actual = PermissionHelper.GetPropertyLevelPremissions(metadataProvider, parent, typeof(TestObject), to, everyone);
Assert.AreEqual(true, actual["YouCanSeeMe"].Key.HasFlag(Permission.View));
Assert.AreEqual(false, actual["YouCanSeeMe"].Key.HasFlag(Permission.Edit));
Assert.AreEqual(false, actual["YouCanSeeMe"].Key.HasFlag(Permission.Create));
Assert.AreEqual(false, actual["YouCanNotSeeMe"].Key.HasFlag(Permission.View));
Assert.AreEqual(true, actual["YouCanSeeMeButNotEditMe"].Key.HasFlag(Permission.View));
Assert.AreEqual(false, actual["YouCanSeeMeButNotEditMe"].Key.HasFlag(Permission.Edit));

parent = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, god);
actual = PermissionHelper.GetPropertyLevelPremissions(metadataProvider, parent, typeof(TestObject), to, god);
Assert.AreEqual(false, actual["YouCanSeeMe"].Key.HasFlag(Permission.View));
Assert.AreEqual(false, actual["YouCanEditMe"].Key.HasFlag(Permission.View));
Assert.AreEqual(false, actual["YouCanEditMe"].Key.HasFlag(Permission.Edit));
Assert.AreEqual(false, actual.ContainsKey("YouCanNotSeeMe"));

parent = null;
actual = PermissionHelper.GetPropertyLevelPremissions(metadataProvider, parent, typeof(TestObject), to, everyone);
Assert.AreEqual(true, actual["YouCanSeeMe"].Key.HasFlag(Permission.View));

parent = PermissionHelper.GetObjectLevelPremission(metadataProvider, typeof(TestObject), to, anon);
actual = PermissionHelper.GetPropertyLevelPremissions(metadataProvider, parent, typeof(TestObject), to, anon);
Assert.AreEqual(true, actual["EverybodyCanSeeMe"].Key.HasFlag(Permission.View));
}</pre>

Don’t get too excited. So far we haven’t seen much. The real beauty is when we get to automatically filter collections and set the client view visibility using the framework with one line of code.

To be continued…

Advertisements

Automatic End to End Authorization (Part 1)

Authorization is still a dilemma in development of business applications. ASP.Net provides the membership provider which supports user/role membership and domain service also supports it so you can use UserContext in the client side and User.IsInRole() gives you the user’s role memberships.

This looks good, but is certainly not enough. First of all authorization can be quiet complex such that authorization rules should be applied on a record-by-record basis and also the authorization rules can be more complicated than a single IsInRole check. For example a use in certain rolls can access a filed of a record only if the state of the user (e.g. Queensland) is similar to the state of the object (e.g. Pharmacy in Queensland).

Currently, you have to implement authorization on the server-side. Then you have to implement the same thing in your database using SQL techniques and you have to implement all the scraps again in the client side to figure out which filed or views are visible and which are read only!!! This is owe-full, isn’t it?

The way I would like to do all my authorization is as follows:

  1. In the service side I want to be able to assign authorization attributes to the model’s metadata, (similar to authorized attribute in MVC which you can apply to controllers) . I should be able to have custom authorizations.
  2. In the service side for Queries, I want to have a filter athorized method, which get’s an IEnumerable of roles and/or users and filters the records, it should remove the records that user can not have access to, scrap the fileds that user has no access to (if he has access to the record) and attach an access attribute to the whole collection and each individual field (if different from the collection).
  3. In the service side for Commands, I want to have a check authorized method, which get’s an IEnumerable of roles and/or users, and the object which is supposed to be changed and returns a boolean identifying if is allowed or not.
  4. It would be great if in the service side, exists an IsAllowed method which get’s the data context and a list of users and roles and returns if the modifications in the context can be authorized.
  5. In the client side, there should be an attribute attached to each returned object from the service. The attribute contains the fields the accessible fields. For example “Name” is visible and read-only, “DateOfBirth” is visible and editable, etc. This attribute can be used to change the view appearance for visible and read-only fields. For MVVM, the visibility and edit-ability of parts of a view can be bound to these attributes (of course through a method or using a converter).
  6. In the client side, there should be a service that generates a dummy empty object with it’s authorization attributes to be bound o the view for creating a new object.
  7. In the Database side,  a function should be automatically generated, to do the authorization. Although this may look impossible in presence of custom authorization, there are ways to do that: First, to use a provider model and force user to implement the same custom authorization as SQL function. Second, (only for SQL Server) use CLR and create a CLR class that uses the same service side methods for this reason.

Extra benefit of using this approach is that, the authorization rules can be changed without any change to the client side. Full loose coupling!

Note that although this approach provide full end to end authorization by only defining rules at one place (if implemented completely) effectively, it can not be efficient (specially in DB side). User still should use their own personalized queries to query large datasets. However, his job can be simplified by shortlisting the results by more general rules, and fine tune authorization by filtering using the generated authorization functions.

I  try to implement this in my spare time and update implementation details in the blog.

ASP.Net MVVM

MVVM tend to be a very pleasant pattern for rich internet applications. After working with Silverlight for a while I feel this pattern is a great pattern, is much easier to work in compare to MVC but has almost all of the benefits. However, the whole MVVM pattern becomes possible because there are such wonderful binding capabilities in xaml.

I was thinking about developing a website with MVVM pattern, and bringing at least some of the goodness of MVVM to web pages. It might look a bit eccentric at start, but considering all the power that ASP.Net web forms and WCF gives us, it is certainly possible and worth a try. The only real limitation is that the ViewModel code should be in JavaScrip, because it is being run on the client side. I think some real man should someday jump in GWT source code and start a similar project that compiles C# into JavaScript, so that C# developers can keep writing in C# for the client side. However, till that time all the client code should be in JavaScript.

Here is the big picture: Lets have a bunch of WCF services that return JSON objects. Same as when you work with WPF or Silverlight (but services are configured to return JSON instead of binary). On the view end, we have the normal ASP.Net web form which consist of only following controls: A XMLDataSource and a bunch of DataBound controls. All the controls in the web form are bound to the XMLDataSource. We have our View and Model handy, but the missing part of the puzzle is ViewModel and binding it to the View.

The default (and possibly optimum) for the MVVM is that ViewModel should be a flattened representation of the model. Thus, the only work here is to provide a set of JavaScript helpers to simplify following tasks:

1- Loading model from the Service (jQuery does this)

2- Binding the ViewModel JavaScript object to the XMLDataSource through Web Form client side scripts. (*The challenge)

3- Some pattern similar to INotifyPropertyChange for JavaScript. (Not too hard)

4- Some simple JavaScript data context manager to manage changes in the context and provide related update or insert commands (Lower priority)

5- Implement the Command pattern with jQuery.

6- Develop a pattern for binding nested views (Possibly a bootstrapper to load up ascx controls in AJAX placeholders).

By sorting the above problems out, we can have a pretty feasible and powerful MVVM pattern for web forms which is much nicer to implement than MVC and much more sensible than Web Forms. There would be still limitations such as  binding controls together, but we can live without them.

I am not going to start this project anytime soon, but I will be really happy if some of you take this idea and start something.

C# in depth.

I was reading this book last night. It’s a nice one. I suggest you purchase a copy and read it. Following images are from this book which reminds me of how nice and easy it has become to program with C# through the last decade. Click on the images to see bigger images.

How to simulate bag access in Windows azure table storage? (Part 1)

It is nice to hear that Microsoft is providing table storage. Hopefully we can get it for non-azure platforms as well. The idea is fast and scalable access to persisted objects without limitations of tabular world. No doubt that relational databases are amazing and let for super complex queries and transactions to happen. Downside is their complexity of design and usage. It tends to be extremely hard to provide real scalable relational data yet satisfying service level agreements on response time, availability etc.

Efforts on developing non-relational non-schema bound data sets are as old as databases, and in the cloud era, they make so much sense. For example Mnesia is a lovely database designed to work with Erlang with a LINQ-like query language. Enough to say it is developed in 80’s and is easy to scale, and provides 100% uptime (you get a mechanism to do hot patching). I also read about this database (RavenDB) a few days ago which is based on a similar motive.

One important thing to remember when working with non-relational databases, is that they are not relational. Thus, you don’t run SQL scripts against them and there is no join, no views, no foreign keys and primary keys. These terms make sense for tabular data. Databases like table storage are semi-structured data storage. Structured is tabular and relational data storage store them. Semi structure is XML, JSON, or any other form of persisted object. Unstructured is web and free-form text, etc.

Mnesia (as a pioneer of table-storage like databases) stores data in set’s and bags. A set is a table, which each record has a unique key. Fair enough, we are used to work with table with primary key which is the same. But a bag, is a table in which many records can share a key, hence there might be no way to access a single row of a table because it does not have a unique key (You may say now, WTF? what happens to my candidate keys and primary keys – and my answer is wait a minute. We are not in relational world, so non of these terms exist here).

So what is the value of having a row in a table which we can not access it directly? It of course has some value. Bearing in mind again that table storage is not relational, a good design paradigm is to NEVER query anything except the key (and of course partition key for table storage). Any other query (which is not bounded to partition key for table storage) is similar to a full table scan in you SQL Server database and full table (or index) scan is is THE killer. You can never become scalable if you have a single operation with full table scan over your growing data.

to be continued…

A framework for in memory LINQ

I had a blog post about comparing the performance of cache versus database. Unfortunately Linq to object takes a naive staraight forward approach to any query which is the brute-force look everything. This should change sometime and it annoys me alot. Be a man and start fixing this. I will cach up on it someday after I mowed my yard. I am too busy right now and my weeds are close to 2 meters. Here is my whish list: When I write this code


IEnumerable indexedCollection = myMemColl.AddIndex( i => new {i.FName, i.LName}, IndexOptions.CreateStatistics );

indexedCollection.Where(i => i.FName > "c" && i.FName < "d")
.OrderBy( i => i.FName)
.AsIndexedQueryable().Take(10);

I want the the indexed collection smartly utilize my indexes and take the top 10 items for me without scanning the whole collection. Is it really a big request in 21st century??