CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

Syntax for Instance Level Authorization Rule in CSLA 4

rated by 0 users
Not Answered This post has 0 verified answers | 3 Replies | 2 Followers

Top 500 Contributor
16 Posts
Biceman posted on Fri, Aug 13 2010 11:27 PM

Can someone show me the syntax for adding an instance level authorization rule in CSLA 4?  Rocky's overview of the Authorization Rules for CSLA 4 mentions this functionality but there is no example of how to go about adding this type of rule.

All Replies

Top 10 Contributor
9,433 Posts

Where possible (specifically for insert/update/delete operations) the Target property of the context parameter is populated with a reference to the business object instance. So your authorization rule can use the Target property to interact with the object instance.

Obviously in the case of create/fetch there is no instance when the rule runs because the rule is indicating whether it is possible to do the create/fetch before the operation occurs - so Target isn't available in those cases.

Rocky

Top 500 Contributor
16 Posts

So in order to use instance level authorization for read, edit, delete, and add, I need to create a custom "IsInRole" class ... correct?  Your blog write-up didn't mention that explicitly so I was thinking I could use the Rules.CommonRules.IsInRole version. 

Do I need to override the logic in the BusinessBase so that it performs an instance level authorization before a Save or Delete (e.g., Rules.BusinessRules.HasPermission(AuthorizationActions.Delete, _myCustomer) ) or does CSLA already do this for me (check at per-type level and per-instance level)?

 

In the spirit of helping others, I'll explain the solution I came up with:

My application contains various master data tables (e.g., colors).  The Colors table comes pre-populated with some standard entries.  These are flagged in the database as "system entries".  The user is free to add to this list of color(s).  The authorization requirements are as such:

  • No one can delete a system entry
  • Only System Admins can edit a system entry
  • The "User" role allows you to view a system entry
  • The "User" role allows you to add a new color(s) and/or edit/delete any user created color(s)

I created a read-only property named "IsSystemEntry" in my ColorBO.

I created a custom IsInRole class named "SysEntryIsInRole".  I added another cached list of roles (_SysPptyRoles) to the class to store the role(s) which can perform operations on system entries.  The Sub New contains a signature with:

(Action, SysEntryRoles as List(of String), Roles as List(of String))

Since Property level authorizations are already instance based, I did not have to worry about them in my custom class (hence there is no place holder for "element" in the Sub New).

In the Execute method, I check context.target.  If it is Nothing then I do the same look-up processing against the _Roles list that the CommonRules.IsInRole does.  However, if the target contains a reference, then an instance level authorization is being requested.  I cast the target as my ColorBO then reference the IsSystemEntry property.  Only deletion and edit authorization rules are special for system entries so if the authorization action is one of these, I loop over the _SysEntryRoles list just like you normally do for the _Roles list; otherwise I loop over the _Roles list.

Here's the code which might make things clearer:

In my ColorBO:

    Protected Shared Sub AddObjectAuthorizationRules()
        Rules.BusinessRules.AddRule(GetType(ColorBO), New Rules.CommonRules.IsInRole(Rules.AuthorizationActions.GetObject, "User"))
        Rules.BusinessRules.AddRule(GetType(ColorBO), New Rules.CommonRules.IsInRole(Rules.AuthorizationActions.CreateObject, "User"))
        Rules.BusinessRules.AddRule(GetType(ColorBO), New SysEntryIsInRole(Rules.AuthorizationActions.EditObject, "System Admin", "User"))
        Rules.BusinessRules.AddRule(GetType(ColorBO), New SysEntryIsInRole(Rules.AuthorizationActions.DeleteObject, "**NoOne**", "User"))
    End Sub

For the delete rule, I specify the fictitious role "**NoOne**" to indicate no one can perform this task.  I could just as well have passed an empty string.  Again only Edit and Delete require special checking so only those two actions reference my SysEntryIsInRole class.

 

In my SysEntryIsInRole class:

Public Class SysEntryIsInRole
    Inherits Csla.Rules.AuthorizationRule

    Private _Roles As List(Of String)
    Private _SysPptyRoles As List(Of String)

'I actually pass in a single string for the SysPptyRole (System Property Role) because I know I will have at most one entry and it saves me

'from having to pass a list

Public Sub New(ByVal Action As Csla.Rules.AuthorizationActions, ByVal SysPptyRole As String, ByVal ParamArray roles() As String)
        MyBase.New(Action)

        _Roles = New List(Of String)
        For Each item As String In roles
            _Roles.Add(item)
        Next

        _SysPptyRoles = New List(Of String)
        _SysPptyRoles.Add(SysPptyRole)

    End Sub

    Protected Overrides Sub Execute(ByVal context As Csla.Rules.AuthorizationContext)
        If context.Target Is Nothing Then  'Entity level authorization check
            CheckAuthorization(context)
        Else  'Instance level authorization check
            Dim o As ColorBO = CType(context.Target, ColorBO)
            If o.IsSystemEntry AndAlso (Me.Action = Csla.Rules.AuthorizationActions.DeleteObject OrElse Me.Action = Csla.Rules.AuthorizationActions.EditObject) Then
                context.HasPermission = False  'Default is NO
                If _SysPptyRoles IsNot Nothing Then
                    For Each role As String In _SysPptyRoles
                        If Csla.ApplicationContext.User.IsInRole(role) Then
                            context.HasPermission = True
                            Exit For
                        End If
                    Next
                End If
            Else
                CheckAuthorization(context)
            End If
        End If

    End Sub

    Private Sub CheckAuthorization(ByVal context As Csla.Rules.AuthorizationContext)
        If _Roles.Count > 0 Then
            For Each role As String In _Roles
                If Csla.ApplicationContext.User.IsInRole(role) Then
                    context.HasPermission = True
                    Exit For
                End If
            Next
        Else
            context.HasPermission = True 'Default is to authorize unless explicitly stated
        End If
    End Sub

Since I have many master tables that require this same authorization checking, I am going to create in Interface for the IsSystemEntry property so that I can cast any BO calling this rule and obtain the value of "IsSystemEntry".

 

Top 500 Contributor
16 Posts

I need to correct something I stated above.  This following statement is false:

Since Property level authorizations are already instance based, I did not have to worry about them in my custom class (hence there is no place holder for "element" in the Sub New).

The business rules contained in "AddBusinessRules" apply at the BO level (i.e., per-type).  The "AddBusinessRules" sub is only called once so you cannot place instance based property level authorization in it.

One of the property level authorization rules I omitted from my example above states:

  • The Name property can never be changed for system entries

I mistakenly had code in "AddBusinessRules" as such:

        If IsSystemEntry Then
            'protect Name
            BusinessRules.AddRule(New Rules.CommonRules.IsInRole(Rules.AuthorizationActions.WriteProperty, NameProperty, "**NoOne**"))
        Else
            BusinessRules.AddRule(New Rules.CommonRules.IsInRole(Rules.AuthorizationActions.WriteProperty, NameProperty, "User"))
        End If

Since the system entries are the first fetched from the database, the Name property was write protected for every ColorBO ... even those created by the user.

I now realize that I need to handle the read/write authorization for the Name property in my SysEntryIsInRole class since the authorization is based on the IsSystemEntry flag like the instance level edit and delete authorizations.

Page 1 of 1 (4 items) | RSS

Copyright (c) 2006-2014 Marimer LLC. All rights reserved.
Email admin@lhotka.net for support.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems