Backwards Authorization Rules

Backwards 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