Hi gents,
It's seem an eon since I last visited this forum - which I guess is a testament to the CSLA framework I've been using for so many years.
I'm looking for some pointers/advice or a shove in the right direction here.
I have been and am still using csla v2.1 in my win application and I now have the requirement to incorporate some permissions that are proprietary to the backend database we use.
Essentially, the permissions have two relevant columns (beyond USERID) - a [MODULENAME] and an [ACTION],
e.g. "CUSTOMER" might be the [MODULENAME] and [ACTION] may be "VIEW", "EDIT", "EXEC", etc. A row will exist for each permission given.
Now, I've been using the CSLA authentication from day one, and looking at the model I thought this was a fairly simple inclusion - and that I could simply add a new child/necessary functions to my PTPrincipal, PTIdentity, BusinessPrincipalBase and so on.
The code changes I have implemented compile, but I'm missing something....
Here's what I have changed....
added to csla - BusinessPrincipalBase.vb
''' <summary>
''' Returns a value indicating whether the
''' user has permission for a given module / action.
''' </summary>
Public Overridable Function HasPermission(ByVal modulename As String, ByVal action As String) As Boolean
Return False
End Function
My PtIdentity now looks like this in my projectlibrary;
Imports
System.Security.Principal
Namespace
Security
<Serializable()> _
Public Class PTIdentity
Inherits ReadOnlyBase(Of PTIdentity)
Implements IIdentity
#Region " Business Methods "
Protected Overrides Function GetIdValue() As Object
Return mName
End Function
#End Region
#Region " IsInRole "
Private mRoles As New List(Of String)
Friend Function IsInRole(ByVal role As String) As Boolean
Return mRoles.Contains(role)
End Function
#End Region
#Region " Permissions "
Private Class mPerm
Private mMODULENAME As String
Private mACTION As String
Public ReadOnly Property MODULENAME() As String
Get
Return mMODULENAME
End Get
End Property
Public ReadOnly Property ACTION() As String
Get
Return mACTION
End Get
End Property
Public Sub New(ByVal modulename As String, ByVal action As String)
mMODULENAME = modulename
mACTION = action
End Sub
End Class
Private mPerms As New List(Of mPerm)
Friend Function HasPermission(ByVal modulename As String, ByVal action As String) As Boolean
For Each PERM As mPerm In mPerms
If PERM.MODULENAME = modulename And PERM.ACTION = action Then
Return True
End If
Next
Return False
End Function
#End Region
#Region " IIdentity "
Private mIsAuthenticated As Boolean
Private mName As String = ""
Public ReadOnly Property AuthenticationType() As String _
Implements System.Security.Principal.IIdentity.AuthenticationType
Get
Return "Csla"
End Get
End Property
Public ReadOnly Property IsAuthenticated() As Boolean _
Implements System.Security.Principal.IIdentity.IsAuthenticated
Get
Return mIsAuthenticated
End Get
End Property
Public ReadOnly Property Name() As String _
Implements System.Security.Principal.IIdentity.Name
Get
Return mName
End Get
End Property
#End Region
#Region " Factory Methods "
Friend Shared Function UnauthenticatedIdentity() As PTIdentity
Return New PTIdentity
End Function
Friend Shared Function GetIdentity( _
ByVal username As String, ByVal password As String) As PTIdentity
Return DataPortal.Fetch(Of PTIdentity)(New Criteria(username, password))
End Function
Private Sub New()
' require use of factory methods
End Sub
#End Region
#Region " Data Access "
<Serializable()> _
Private Class Criteria
Private mUsername As String
Private mPassword As String
Public ReadOnly Property Username() As String
Get
Return mUsername
End Get
End Property
Public ReadOnly Property Password() As String
Get
Return mPassword
End Get
End Property
Public Sub New(ByVal username As String, ByVal password As String)
mUsername = username
mPassword = password
End Sub
End Class
Private Overloads Sub DataPortal_Fetch(ByVal criteria As Criteria)
Using cn As New SqlConnection(Database.SecurityConnection)
cn.Open()
Using cm As SqlCommand = cn.CreateCommand
cm.CommandText = "Login"
cm.CommandType = CommandType.StoredProcedure
cm.Parameters.AddWithValue("@user", criteria.Username)
cm.Parameters.AddWithValue("@pw", criteria.Password)
Using dr As SqlDataReader = cm.ExecuteReader()
If dr.Read() Then
'roles
mName = criteria.Username
mIsAuthenticated = True
If dr.NextResult Then
While dr.Read
mRoles.Add(dr.GetString(0))
End While
End If
' perms
If dr.NextResult Then
While dr.Read
mPerms.Add(New mPerm(dr.GetString(0), dr.GetString(1)))
End While
End If
Else
mName = ""
mIsAuthenticated = False
mRoles.Clear()
mPerms.Clear()
End If
End Using
End Using
End Using
End Sub
#End Region
End Class
End
Namespace
and my PTPrincipal in the projectlibrary has the following addition;
Public Overrides Function HasPermission( _
ByVal modulename As String _
, ByVal action As String _
) As Boolean
Dim identity As PTIdentity = DirectCast(Me.Identity, PTIdentity)
Return identity.HasPermission(modulename, action)
End Function
Now, I suspect having looked closer at this, it relates to the fact that something - and I don;t understand exactly what inherits the windows system security Principal class - which has a roles() property.
But should I not be able to inherit and add my own properties from that?
Basically, what I'm trying to achieve is in my projectlibrary classes, i want to be able to check permissions in the same way as i check roles;
e.g.
Instead of
Public Shared Function CanAddObject() As Boolean
Return Csla.ApplicationContext.User.IsInRole("SALES") _
I want to do something like;
Public Shared Function CanAddObject() As Boolean
Return Csla.ApplicationContext.User.HasPermissions("CUSTOMER", "ADD") _
I do see that ApplicationContext inherits from IPrincipal...
Frankly, I'm lost when I have to dig so deep into the CSLA framework - and am uncertain if this is even possible.
My only other option is to 'fuj' the permissions into looking like a 'role' .. so, I'd end up with roles 'CUSTOMER_VIEW", "CUSTOMER_EXEC", etc .. this would work - but I kind of liked the idea of separation between roles and permissions...
Any comments or suggestions would be greatly appreciated - provided laughter does not accompany them ;)
Many thanks,
Graham
Rocky has an example in the latest Samples code download, a Permissions project which shows how to do custom roles and HasPermissions method.
Take a look at that as it will show you - essentially I think you'll end up with a wrapper class called somthing like CurrentUser around it so you can do things like If CurrentUser.HasPermissions("CanAddCustomer") Then....
We've done the same thing here although we have users in Roles for periods of time (Start and End Dates) and also a permissions table too (we have some project planning and resource capacity reports where our end users want to know who's in a role that month to help out). Fun.
Thanks Richard - I'll go looking for that...
I think my biggest obstacle may be that my CSLA version is so far behind. I have to address that at some point in the near future - using .Net 08 will be the next step and a subsequent move up to CSLA 4.
I did find an article that suggests using the Roles as a roles/permissions do-all.
http://www.lhotka.net/weblog/PermissionbasedAuthorizationVsRolebasedAuthorization.aspx
As my particular "roles" and "permissions" should never clash it will probably suffice, but I do plan on looking at the sample and making my judgment then...
Thanks so much for a quick reply - this is a great framework - and I am always happily surprised by its community of developers and participants.
Thanks again!
Copyright (c) Marimer LLC