User Object Nightmare - A Question of Responsibility?

User Object Nightmare - A Question of Responsibility?

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


JabbaTheNut posted on Thursday, May 10, 2007

As I am somewhat new to the OO game, I am still struggling to realign my data-centric way of thinking to one that is more responsibility focused.  With that acknowledgement... 

I am facing a bit of a problem designing objects to handle User management in my application.  Specifically, I am trying to satisfy the following general use cases:

1.  All users can Get/View non-sensitive user information.

2.  An Administrator can Add, Edit and Delete any user information.

3.  A user can Edit certain portions of his or her own user information (i.e., password, last name, etc.)

My first approach was to create the following objects:

- UserList (read-only list containing UserInfo objects)

- UserInfo (read-only, non-sensitive user information that can be viewed by all users)

- User (editable root object containing all user information and related methods)

The User object contains all of the user's information, including account related stuff such as FailedLoginAttempts, IsLockedOut, IsActive, etc.  In addition to the standard CRUD methods, the object also contains methods for managing the User's account (e.g., SetPassword, LockUser , UnlockUser, etc.).

The problems I am facing are centered around authorization.  My User object is a nightmare!  I have to implement three levels of authorization to properly control who can do what within the object:

1.  Type Level (CanAddObject, CanGetObject, CanEditObject, CanDeleteObject) - To provide high level access to the object.

2.  Instance Level (IsReadable, IsEditable, IsDeleteable) - To allow a user to edit his or her own object.

3.  Property Level (CanReadProperty, CanWriteProperty) - To control access to each property.

Further, I am realizing that I also need to implement Method Level authorization for methods such as LockUser and UnlockUser.  From the UI perspective, this object is cumbersome and is not very databinding friendly (does the UI call static, instance, property or method authorization, and under what circumstances?)

Ultimately I have come to the conclusion that I have missed the OO mark on this one.  Can someone provide me with some guidance?

I am considering the following objects:

UserList and UserInfo - as described above

User - containing all user information and related methods, but restricted to Administrator (maybe this should be split into User and UserAccount?).  This would implement Type Level authorization.

UserOwned - containing information and methods that can be edited/executed only by the owning user (e.g., ChangePassword).  This would implement Instance Level authorization.

How are others doing this?  Any help would be appreciated.

RockfordLhotka replied on Thursday, May 10, 2007

Your UserEdit object and UserInfo object should be quite different from your princpal object.

I would expect that you'd (at least) have the following:

To get your editing authorization correct you'd do:

  1. UserEdit would have authorization rules on its properties to (dis)allow anyone from seeing certain data.
  2. UserEdit would have authorization rules on its properties to allow people in the Administrator role to view/edit all properties.
  3. UserEdit would override CanWriteProperty() to also allow the current user to edit specific properties if the object represents that user.

Of course your UserPrincipal/UserIdentity would be a read-only representation of the currently logged in user's identity/roles. If you want live updates, you could have UserEdit notify UserIdentity (using a Friend/internal method) that it is invalid so it could reload itself.

stefan replied on Friday, May 11, 2007

Rocky,

could you explain on why you see a need for special readonly versions of the custom principal/identity objects in this case. We usually already access these object (from within the BOs) when calling IsInRole(...), so the check whether the current user is editing his own record already works with the existing objects.

Stefan


RockfordLhotka replied on Friday, May 11, 2007

Single responsibility design says that an object should have exactly one responsibility.

 

The principal/identity objects have a very clear responsibility: provide identity and role information about the current user.

 

The responsibility to edit that data is entirely different, and so it must be a different object. In other words, the principal/identity objects shouldn’t be responsible for editing the data they contain in addition to providing identity/role information for the application.

 

Rocky

malloc1024 replied on Friday, May 11, 2007

You might want to also look into the protection proxy design pattern.

Copyright (c) Marimer LLC