CSLA - IPrincipal - Permissions

CSLA - IPrincipal - Permissions

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


gajit posted on Wednesday, September 08, 2010

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

 

 

 

 

 

richardb replied on Wednesday, September 08, 2010

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.

gajit replied on Wednesday, September 08, 2010

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