Authorization and scopes

Authorization and scopes

Old forum URL: forums.lhotka.net/forums/t/3775.aspx


MtyNLMex posted on Wednesday, October 24, 2007

For our project we are required to handle authorizations based on a Role/Data Scope basis. This means a user can be assigned to more than 1 role and reach a different Data Scope for each User/Role combination.

 

For example:

Suppose we have 3 different classes: Orders, Customers and Products

Role 1 has these permissions

Class

View

Add

Update

Delete

Products

Allow

None

None

None

Customers

Allow

None

None

None

Orders

None

None

None

None

 

Role 2 has these permissions

Class

View

Add

Update

Delete

Products

Allow

None

Allow

None

Customers

Allow

None

None

None

Orders

Allow

Allow

Allow

Allow

 

User 1 is assigned to Role 1 with a scope of: Company 1, Company 2 and Company 3

He is also assigned to Role 2 with a scope of: Company 1

 

This means she can view products and customers for the 3 companies but can only update products and create orders for company 1.

 

To handle this, we built a class library that includes a custom principal allowing us to do something like this:

 

Dim _principal As MyCustomPrincipal = Csla.ApplicationContext.User

CanAdd = _principal.BusinessClasses(“Products”).PermissionsForScopes( _

         mCompanyKey).HasPermission(enmPermissionIndex.epmx_Add)

Where mCompanyKey is the key of the company a product belongs to.

Or even handle more than one scope, let’s say company and department:

CanAdd = _principal.BusinessClasses(“Products”).PermissionsForScopes( _

         mCompanyKey, mDepartmentKey).HasPermission(enmPermissionIndex.epmx_Add)

 

The problem is I can’t figure it out how to add this to the Product class authorization rules. Maybe have something like the Shared functions CanAddObject, CanGetObject, etc. But because they’re shared I must refer to instance members.

 

Any help would be greatly appreciated.

 

RockfordLhotka replied on Wednesday, October 24, 2007

I think you can use some decoupling here.

Perhaps an interface like IDataScope that business objects can implement to return their scope (companykey, departmentkey) in a standard manner.

Then you can create a centralized helper method to check the role/company/dept triplets.

Then you can override CanReadProperty() and CanWriteProperty() in a custom base class (which would also implement IDataScope to force subclasses to provide that data!) so the triplet is used to call this helper method.

Finally, your Shared CanXyzObject() methods can accept an IDataScope if appropriate. Though I'm not sure that makes a lot of sense. Remember that the 4 Shared methods exist primarily to allow the UI to enable/disable various menu items or links. If the answer is "maybe" then the UI really must leave the options enabled and so the questions have no value. If they have no value, then don't implement them.

MtyNLMex replied on Thursday, October 25, 2007

Rocky,

 

Following your suggestion, we created the IDataScope interface and implemented it in our business classes.

We also modified our Shared CanXyzObject methods to accept an IDataScope object or an array of Guids as follows:

 

 

Public Shared Function CanAddObject(ByVal ParamArray scopeKeys() As System.Guid) As Boolean

    Dim _principal As MyCustomPrincipal = Csla.ApplicationContext.User

    Return _principal.Identity.IsAuthenticated AndAlso _principal.BusinessClasses(“Product”).PermissionsForScopes(scopeKeys).HasPermission(EnmPermissionIndex.epmx_Add)

End Function

Public Shared Function CanGetObject(ByVal ParamArray scopeKeys() As System.Guid) As Boolean

    Dim _principal As MyCustomPrincipal = Csla.ApplicationContext.User

    Return _principal.Identity.IsAuthenticated AndAlso _principal.BusinessClasses(“Product”).PermissionsForScopes(scopeKeys).HasPermission(EnmPermissionIndex.epmx_View)

End Function

Public Overloads Shared Function CanEditObject(ByVal product as IDataScope) As Boolean

    If IsNothing(employee) Then

       Return False

    Else

       Dim _principal As MyCustomPrincipal = Csla.ApplicationContext.User

       Return _principal.Identity.IsAuthenticated AndAlso _principal.BusinessClasses(“Product”).PermissionsForScopes(product.ScopeKeys).HasPermission(EnmPermissionIndex.epmx_Update)

    End If

End Function

Public Overloads Shared Function CanEditObject(ByVal ParamArray scopeKeys() As System.Guid) As Boolean

    Dim _principal As MyCustomPrincipal = Csla.ApplicationContext.User

    Return _principal.Identity.IsAuthenticated AndAlso _principal.BusinessClasses(“Product”).PermissionsForScopes(scopeKeys).HasPermission(EnmPermissionIndex.epmx_Update)

End Function

Public Shared Function CanDeleteObject(ByVal product as IDataScope) As Boolean

    If IsNothing(employee) Then

       Return False

    Else

       Dim _principal As MyCustomPrincipal = Csla.ApplicationContext.User

       Return _principal.Identity.IsAuthenticated AndAlso _principal.BusinessClasses(anObject).PermissionsForScopes(product.ScopeKeys).HasPermission(EnmPermissionIndex.epmx_Delete)

    End If

End Function

 

Maybe we should use reflection and instead of specifying the name of the object we could do something like

 

Public Shared Function CanDeleteObject(ByVal anObject as object) As Boolean

    If IsNothing(employee) Then

       Return False

    Else

       Dim _principal As MyCustomPrincipal = Csla.ApplicationContext.User

       Return _principal.Identity.IsAuthenticated AndAlso _principal.BusinessClasses(anObject.GetType.Name).PermissionsForScopes(product.ScopeKeys).HasPermission(EnmPermissionIndex.epmx_Delete)

    End If

End Function

 

I don’t know if it’s possible to get the type for the functions that don’t receive an instance as parameter.

 

We’ll need to do some research before trying overriding CanReadProperty and CanWriteProperty in a new base class, but we can live with the above approach for now.

 

Thanks a lot for your help!

Copyright (c) Marimer LLC