How to handle user-defined roles and permissions?

How to handle user-defined roles and permissions?

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


rsbaker0 posted on Thursday, November 15, 2007

In our application, the user is in complete control over what roles are defined, and what specific functions are allowed for each role (e.g. the "permissions").

In the Project Tracker example, the roles and authorization rules are static (at least this was my interpretation), so how would you handle our scenario in CSLA?

One possibility is to call the permissions themselves "roles", so instead of a role being "Administrator", etc. the roles would be "Can Edit Project", "Can Delete Project", etc. In our application there are over 300 such permissions, so I'm not sure if this is advisable as it might add too much weight to the objects.

 

JoeFallon1 replied on Friday, November 16, 2007

This has been discussed many times.

Do a search for HasPermissions and see what you come up with.

Joe

 

Biceman replied on Friday, November 16, 2007

See this article as an alternative.  It's what I used as my template since I found the hardcoded role list and permissions too limiting as well.

Bryan

rsbaker0 replied on Friday, November 16, 2007

I looked at both suggestions -- it appears from this thread that Rocky says you can interpret "IsInRole" to be the equivalent of "HasPermission" except in unusual cases (unless I am missing something).

http://forums.lhotka.net/forums/thread/12198.aspx

I have our "HasPermission" functionality completely migrated over from the legacy application we are converting. My main question was how to integrate it into the CSLA framework. The authorization rules would seem to not be useful unless we interpret the roles as permissions.

Maybe some future version of CSLA could support a flexible authorization rule implementation comparable to the validation rule mechanism, where you can implement almost anything you want rather than just provide a list of strings to be tested elsewhere in the framework.

Biceman replied on Saturday, November 17, 2007

I'm new to CSLA as well so I feel your pain about trying to take that leap from the sample project.  While I've read both the VB.NET Business Objects and Expert VB 2005 Business Objects books, I learn best from examples. 

 
The Project Tracker is a good start but far too simplistic for what we are trying to do so I've been scouring this forum and trying different things out.   I wish there were more sample applications to learn from but I supposed businesses using CSLA don't want to post their work products for the world to see.

 So in the interest of sharing, here is my approach:

 I have three database tables:

The User table contains a list of each user (e.g., Name, Password, Password Expiration Date, List of most recently used passwords).  The Roles table contains a row for each Role the User belongs to.  Finally, the Role Permissions table contains a list of the permission(s) associated with each Role (i.e., Role, Function and Permission Level).
 
When the user logs on the application, his/her password is validated.  Assuming a valid password, the Roles and Role Permissions tables are joined to find all the permissions for the particular user.
 
Using the Project Tracker Identity as a template, I created a new Identity class.  Here’s the important stuff I added:

 
   <Serializable()> _
   Public Class YAIdentity
      Inherits ReadOnlyBase(Of YAIdentity)
      Implements IIdentity
 
      Private
_UserSctyList As New List(Of UserScty)  ‘Holds list of permissions

      ''' <summary>
     
''' Internal class to hold custom security info used during authorization checks
     
''' </summary>
     
''' <remarks></remarks>
     
Private Class UserScty
         Public FuncNme As String  ‘Function Name
        
Public SctyAcesCde As Integer  ‘Security Access Code

         Public Sub New(ByVal pFuncNme As String, ByVal pSctyAcesCde As Integer)
            FuncNme = pFuncNme
            SctyAcesCde = pSctyAcesCde
         End Sub
End
Class

      ''' <summary>
     
''' Indicates whether user is authorized for specified function and accesses
     
''' </summary>
     
Friend Function IsAuthorized(ByVal FuncNme As String, ByVal SctyAcesCde As SctyAcesCdes) As Boolean
         For Each item As UserScty In _UserSctyList
            If item.FuncNme = FuncNme AndAlso SctyAcesCde = item.SctyAcesCde Then
              
Return True
           
End If
        
Next

         Return False
    
End Function
 

In the DataPortal_Fetch method, I populate _UserSctyList based on the contents of the second result set (like Rocky does in the Project Tracker example).
 
     Using dr As New SafeDataReader(cm.ExecuteReader)
        While dr.Read()
           With dr
              _UserSctyList.Add(New UserScty(.GetString("FUNC_NME"), .GetInt32("SCTY_ACES_CDE")))
           End With
       
End While
    
End Using

 
I created a new Principal class again using the PT Principal as a guide.

Namespace Security
   <Serializable()> _
  Public Class YAPrincipal
      Inherits Csla.Security.BusinessPrincipalBase

      Public Shared Function Login( _
        ByVal UserNme As String, ByVal UserPswdTxt As String) As Boolean

         Dim identity As YAIdentity = YAIdentity.GetIdentity(UserNme, UserPswdTxt)
         If identity.IsAuthenticated Then
           
Dim principal As New YAPrincipal(identity)
            Csla.ApplicationContext.User = principal
         End If

         Return identity.IsAuthenticated
      End Function

      ''' <summary>
     
''' Does the user have permission?
     
''' </summary>
     
Public Shared Function IsAuthorized(ByVal FuncNme As String, ByVal SctyAcesCde As SctyAcesCdes) As Boolean
        
Dim identity As YAIdentity = DirectCast(Csla.ApplicationContext.User.Identity, YAIdentity)
         Return identity.IsAuthorized(FuncNme, SctyAcesCde)
      End Function

   <Flags()> _
Public
Enum SctyAcesCdes As Integer
     
Read = 1
      Edit = 2
      Add = 4
      Delete = 8
      Execute = 16
      End Enum

And finally in my business objects I check for authorization as shown below:

   ''' <summary>
  
''' Is the user allowed to Add new items?
  
''' </summary>
  
''' <returns></returns>
  
''' <remarks></remarks>
  
Public Shared Function CanAddObject As Boolean
     
Return Security.YAPrincipal.IsAuthorized(“Project”, Security.SctyAcesCdes.Add)
   End Function
  
''' <summary>
  
''' Is the user allowed to Read existing items?
  
''' </summary>
  
''' <returns></returns>
  
''' <remarks></remarks>
  
Public Shared Function CanReadObject As Boolean
     
Return Security.YAPrincipal.IsAuthorized((“Project”, Security.SctyAcesCdes.Read)
   End Function
  
''' <summary>
  
''' Is the user allowed to Delete existing items?
  
''' </summary>
  
''' <returns></returns>
  
''' <remarks></remarks>
  
Public Shared Function CanDeleteObject As Boolean
     
Return Security.YAPrincipal.IsAuthorized((“Project”, Security.SctyAcesCdes.Delete)
   End Function
  
''' <summary>
  
''' Is the user allowed to Edit existing items?
  
''' </summary>
  
''' <returns></returns>
  
''' <remarks></remarks>
  
Public Shared Function CanEditObject As Boolean
     
Return Security.YAPrincipal.IsAuthorized((“Project”, Security.SctyAcesCdes.Edit)
   End Function

Obviously, “Project” will vary depending upon the Business Object but hopefully you get the idea.

Bryan

JoeFallon1 replied on Monday, November 19, 2007

If you look at the wish list (the items in green), the next version of CSLA has already implemented the Delegate for IsInRole which means you can use a different function (such as HasPermission) in the Authorization framework.

If you look at the source you may be able to port it backwards if you really need it now.

Joe

 

Copyright (c) Marimer LLC