Backwards Authorization RulesBackwards Authorization Rules
Old forum URL: forums.lhotka.net/forums/t/6086.aspx
bpb2221 posted on Tuesday, January 06, 2009
Hi everyone,
I am having trouble with my authorization rules. I have a role that I am trying to deny write access to certain properties in my class. When I add an AuthorizationRules.AllowWrite, it denies write permissions by way of the ReadWriteAuthorization control disabling the correct controls on the form . When I add an AuthorizationRules.DenyWrite or no authorization rules, the ReadWriteAuthorization control does not disable these controls. The only other permission this role has is CanGetObject. It does not have CanAddObject, CanDeleteObject, Or CanEditObject permissions. If you need me to explain anything else, please ask. This problem is driving me crazy and I know it has to be something simple that I am missing. (using CSLA 2.1.4)
bpb2221 replied on Tuesday, January 06, 2009
I think I figured out part of the problem. I am using ASP.NET roles in my WinForms app. I just need to figure out where the roles are getting authenticated so I can change the code to use the roles provider.
bpb2221 replied on Tuesday, January 06, 2009
I figured it out. If you are using WindowsIdentity and ASP.NET you have to change two files: AuthorizationRules and RolesForProperty.
In AuthorizationRules, this is an example of the function I changed (original code is commented out)
Public Function IsWriteDenied(ByVal propertyName As String) As Boolean
Dim result As Boolean
'Dim user As System.Security.Principal.IPrincipal = ApplicationContext.User
Dim user As WindowsIdentity = WindowsIdentity.GetCurrent
If InstanceRules.GetRolesForProperty(propertyName).IsWriteDenied(user) Then
result = True
Else
result = TypeRules.GetRolesForProperty(propertyName).IsWriteDenied(user)
End If
Return result
End Function
In RolesForProperty, this is what I changed
Import the following:
Imports System.Security.Principal
Imports System.Web.Security
Public Function IsWriteDenied(ByVal user As WindowsIdentity) As Boolean
'Public Function IsWriteDenied(ByVal principal As IPrincipal) As Boolean
Dim result As Boolean
For Each role As String In WriteDenied
'If principal.IsInRole(role) Then
If Roles.IsUserInRole(user.Name, role) Then
result = True
Exit For
End If
Next
Return result
End Function
I do not know if it is 'correct' to do this, but it does work. If this method is incorrect, I would like to hear some opinions. Thanks
RockfordLhotka replied on Tuesday, January 06, 2009
This shouldn't be necessary. You should be able to set impersonation to true in web.config, and ASP.NET will put the windows identity as the HttpContext.Current.User, which is what you are getting from ApplicationContext.User.
bpb2221 replied on Wednesday, January 07, 2009
First, I want to thank you for creating this framework. I think it is great!
I am not using a web.config since this is a WinForms app, not a web app. I am using the ASP.NET roles classes (System.Web.Security) for my WinForms app because it has everything I need in roles management and saves me the trouble of having to write custom roles authentication. There is a big push for single sign on where I work so we don't want to 'bother' users with having to log on to anything once they sign into their computer. That is why I didn't use the PTIdentity & PTPrincipal classes from the book.
Is ApplicationContext.User the same thing as WindowsIdentity?
Can HttpContext.Current.User be used in a Winforms app?
Thanks again for the response.
ajj3085 replied on Wednesday, January 07, 2009
Hi,
Wouldn't it be easier just to use Windows authentication? Just set ApplicationContext.User = new WindowsPrincipal( WindowsIdentity.GetCurrent() ). Roles would be Active Directory groups. Or you could have custom code that maps an AD group to one or more database driven role.
HttpContext.Current will always be null because you're not running your WinForms app under Asp.Net.
bpb2221 replied on Wednesday, January 07, 2009
Thank you for the answers.
You are correct Windows authentication would be easier, but I thought that WindowsIdentity is Windows authentication.
I like your idea of setting ApplicationContext.User = new WindowsPrincipal( WindowsIdentity.GetCurrent() )
Where is ApplicationContext.User set initially? I see that is is being used in the AuthorizationRules class, but I don't see where it is initially set.
I can't use AD because we are not given access to it. So I settled on ASP.NET Roles, which does work, if you change the way CSLA checks roles.
ajj3085 replied on Wednesday, January 07, 2009
Well, you would set it as one of the first items for your program startup.
If you can't use AD though, I'm not sure that helps at all. You might look at Authorization Manager. It's included with the Server 2003 Admin toolset. I have to admit though that I haven't gone down this road myself, although it should work. It allows you to define an Authorization Store so you can define roles. One of the neat things is that a role is supposed to be pretty dynamic; so a user could be in a role only during certain times of day, for example. Sadly, I haven't seen much on this though..
Here's an MSDN page on it: http://msdn.microsoft.com/en-us/library/aa375774.aspx
RockfordLhotka replied on Wednesday, January 07, 2009
Again, you shouldn’t need to alter CSLA. While that may
work, it really isn’t the right approach, and you’ll almost
certainly find other unexpected problems.
You really need to get the current principal
(System.Threading.Thread.CurrentPrincipal) to be correct – and this is
also the value used by Csla.ApplicationContext.User in a WinForms app.
And yes, you can set that value directly, but really THAT isn’t
right either, not if you want Windows identities. What you should do is set the
appdomain’s principal policy to Windows so .NET knows that you want it to
use Windows principal/identity objects.
In other words, there are various hack solutions, and there’s
really only one correct solution. In the end you can use any of them, just be
aware of the consequences of your choice.
Rocky
bpb2221 replied on Wednesday, January 07, 2009
Thanks for taking the time to explain this. This has been a big help.
On Page 458 it shows the AppDomain.CurrentDomain.SetPrincipalPolicy(). I was able to set it in my main form load. Then I was able to change the AuthorizationRules class back to using:
Dim user As System.Security.Principal.IPrincipal = ApplicationContext.User
I think I will stick with editing the IF statement in the RolesForProperty class
Public Function IsWriteDenied(ByVal principal As IPrincipal) As Boolean
Dim result As Boolean
For Each role As String In WriteDenied
'If principal.IsInRole(role) Then
If Roles.IsUserInRole(User.Identity.Name, role) Then
result = True
Exit For
End If
Next
Return result
End Function
Since System.Security.Principal.IPrincipal.IsInRole determines whether the current principal belongs to the Windows user group and I need to figure out if it belongs to an ASP.NET role.
I will just have to deal with any repercussions of changing this one IF statement.
RockfordLhotka replied on Wednesday, January 07, 2009
Ahh, in that case you need to set the current AppDomain to use
the Windows identity. I describe this in the Expert 2005 Business Objects book
in the Windows Forms chapter.
I don’t remember the line of code offhand, but it is
literally one line of code you execute as the app starts up to set the AppDomain’s
principal policy so it uses the Windows identity. After that
ApplicationContext.User should work as expected.
If you are using VB, this is a project setting, and you can just
use the project properties to tell the app to use the Windows identity.
Rocky
Copyright (c) Marimer LLC