Validation rules vs read only authorization rules

Validation rules vs read only authorization rules

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


TEK posted on Sunday, June 04, 2006

How do you validate fields that you do not have read access to?

One example (actual) is handling of password fields.
No user should ever be allowed to read a password. However, there is likely to be a business rule that defines that a password must be no longer than 10 characters long, or minimum 5 characters long or some other rules.

However, when the rule tries to gain access to the password string, it's denied access and the whole operation fails.

I guess there is several other situations like it, as salary beeing non readable. However, the business layer needs to check the salary to for example ensure that a given raise is within the range allowed by a special role.

One possible solution would be to check the business rules before the value is actually set, but that would trigger order dependency when setting properties and open up a whole new can of worms that I for sure does not want to look into...

Hope someone has a point of view (and preferrable some really nice solution) for this issue.
I'm pritty sure I'm not the first one hitting this one...

Best regards TEK

Brian Criswell replied on Sunday, June 04, 2006

I think you might need to keep those rules within the business object so they can directly access the local fields.  That way you can bypass the read authorization.

xal replied on Sunday, June 04, 2006

Exactly. Another thing you can do, is create your own validation rules and do something like:

Public Class StringLengthRuleArgs
    Inherits Csla.ValidationRules.RuleArgs

    Private mValue as String
    Public ReadOnly Property Value as String
    Get
        Return mValue
    End Get
    Public Sub New (ByVal propertyName as  String, ByVal propertyValue as  String)
       MyBase.New(propertyName)
       mValue = propertyValue
    End Sub
End Property
End Class

And then your rule could look something like this:

Public Shared Function StringLengthRule(ByVal target as object, _
        e as RuleArgs) as Boolean
If Not TypeOf e Is StringLengthRuleArgs Then
    Throw New ArgumentException("Argument must be of type StringLengthRuleArgs")
End If
Dim args as StringLengthRuleArgs = DirectCast(e,StringLengthRuleArgs)
If args.Value.Trim.Length() > 20 Then
    e.Description = "Password can't exceed 20 chars"
    Return False
ElseIf args.Value.Trim.Length() < 5 Then
    e.Description = "Password must be at least 5 chars long"
    Return False
End If
Return True
End Function



Of course, you can extend your rule args to contain min / max value params so that the rule can be useful in other BOs, but I'll leave that to you....

Andrés

xal replied on Sunday, June 04, 2006

I posted that an hour ago, and I was just having breakfast when I realized how completely wrong that is. Sorry, I shouldn't post until I'm really awake :D.

Anyway, what you can do is similarily to what I posted, pass along the field name and then use reflection to get it just as you would do with the property name.


Public Class StringLengthRuleArgs
    Inherits Csla.ValidationRules.RuleArgs

    Private mFieldName as String
    Public ReadOnly Property FieldName as String
    Get
        Return mFieldName
    End Get
    End Property ' (yeah, this was misplaced, too)

    Public Sub New (ByVal propertyName as  String, ByVal fieldName as  String)
       MyBase.New(propertyName)
       mFieldName = fieldName
    End Sub
End Class


Anyway, the validation rule would be somewhat similar, but using reflection to get the field's value...
Sorry for posting garbage... i really shouldn't post on sunday mornings.. Angry [:@]

Andrés

TEK replied on Sunday, June 04, 2006

Thank your both for your replies.

My current solution is "Don't use read only fields" ;-). Leave it to the UI to hide the password.
However, this is of course not something that I'm able to live with on a long term basic.

I will problably target one of the suggested solutions in my system.

But.. for the sake of discussion and interest in the topic, I would like to comment  on the suggested solutions, and to throw on a new alternative approch on the fire.

There is two possible solutions so far:
- Keep the validation inside the classes
- Use reflection to bypass the properties and access the fields directly

I think that both these solutions is acceptable and get the job done, but I also think that they are hacks. I guess that using reflection would be the most general solution of the two, as it would be possible to reuse between different classes.
But this means that:
a) You have to be aware of the internal workings of the class to be able to write the rule
b) You have to know what fields that might be set as read only fields and handle them specially
c) You have to be sure that the get property does not alter the internal field value in any way
Concolution for this is that you will problably get a lot of special cases if you for example want to set non-readable fields from configuration files (as discussed in earlier post)

I can also see this problem reappering if you start to prevent user from getting object (CanGetObject() returns false), and then I do not think that any of the suggested solutions will be able to solve the issue.

The idea that I came up with to solve this is to add a quite advanced feature to the system, and in special to authorization and rules handling.
If some part of the code was able to run either without authorization, or run as a system account that always will have full access to all values. That way, whenever your code should peform operations that is internal in the business layer it could run as SYSTEM (or something) and authorization rules would not apply. Business rules could be a candidate for this type of access.

The trick to do this would be how to in a given context switch the user, peform some work, and then switch the user back to the original user.

What do you folks think? Is this a possible way to go, or am I far, far out there?
To complex, to unmanagable, not doable or an briliant idea?

Regards, TEK

Copyright (c) Marimer LLC