4

Goal:

I'm trying to figure out the best way to model/design and then implement a "user" feature in a system.

Background:

I am designing an on-line access request system, so our company can use a web-based method for users to request access to various software systems. Since the system is all about the "user", the user is the focal point of the system.

So, a User can request access to a system. Then, the User's Manager will approve/reject the request. After that, the System Owner will approve/reject the request. Then it's the System Admin who approves/rejects, and finally the Security Administrator approves/rejects and adds them to the appropriate Active Directory group so they have access to the target Active Directory-driven application (not this application).

Problem:

I see all entities that represent a User as a core (set of) class(es) in the system. The User object is straight-forward - just pass their Windows login to Active Directory (AD) via an LDAP query and get their info and load it into an object. In an LDAP query, if there are other Users that report to them (a user's manager is stored in our AD), then this "user" is not only a User in this system but also a Manager. If this User is also in the database as a System Owner, they are also a System Owner.

So Far:

(Assume a Manager is someone with at least one direct report assigned to them in AD.)

I've considered a single User object, with properties such as IsManager or IsSystemOwner. However, should I construct an object hierarchy where (for example) a Manager class inherits from User? There are quirks with this, because a System Owner could inherit from User or Manager. Not all system owners are managers. However, Managers, System Owners, System Admins, and Security Admins are all Users, because they can be requesting access to some software system where there role in this system is only as a User. Here is an overview of "is a" for all of the user entities:

  • A User can request access to some other software system in this system.
  • A Manager is a User.
  • A System Owner is a User.
  • A System Admin is a User.
  • A Security Admin is a User (but unlikely to be, due to our organization).
  • A Manager may be a System Owner, but not always.
  • A System Owner may be a Manager, but not always.
  • A System Admin may be a Manager, but not always.
  • A System Admin may be a System Owner, but not likely.
  • A Security Admin may be a Manager, but not always.
  • A Security Admin may be a System Owner, but not likely.

Some additional info:

  • I don't anticipate Security Admins to be using the system as a User to request access, but it's always a possibility.
  • A Manager may create an access request on behalf of one of their employees (to revoke access to a fired employee, for example)
  • All employees in the Windows domain will have access to this site. I assume that I will have some Active Directory groups created for System Admins and Security Admins, as the users in these groups will not be dynamic, rather, users in one team are Sys Admins and users in another team are Security Admins.
  • The System Owner is subject to changed and will be stored in the database, along with the option to designate an alternate approver when on vacation, etc.
  • I may need a Manager to have an alternate approver, but I didn't plan on storing all users on the domain in the database!

This seems like it's so easy to model on paper, but getting it into good, flexible code is stumping me. All suggestions are welcome.

EDIT: Based on Karl's feedback, I have this prototype model. Does it look solid from an OOP perspective, based on my intended use?

Public Class MyCustomUserObject
 Public Property LoginID As String
 Public Property FirstName As String
 Public Property LastName As String
 Public Property EmailAddress As String
 Public Property Roles As List(Of Role)
 Public Function IsManager() As Boolean
 ' If List(Of Role) contains an object of type ManagerRole, then True, else False.
 End Function
 Public Function IsSystemOwner(systemName As String) As Boolean
 ' If List(Of Role) contains an object of type SystemOwnerRole with matching name
 ' in SystemOwnerRole.SoftwareSystems, then True, else False.
 End Function
 Public Function IsSystemAdministrator(systemName As String) As Boolean
 ' If List(Of Role) contains an object of type SystemAdministratorRole with matching name
 ' in SystemAdministratorRole.SoftwareSystems, then True, else False.
 End Function
 Public Function IsSecurityAdministrator() As Boolean
 Return My.User.IsInRole("My Active Directory group name for Security Admins")
 End Function
End Class
Public Class SoftwareSystem
 Public Property ID As String
 Public Property Name As String
End Class
Public MustInherit Class Role
 Public Property DesignatedApproverLoginID As String
End Class
Public Class ManagerRole
 Inherits Role
 Public Property Subordinates As List(Of AafUser)
 ' Or this, with a List of login IDs?
 ' Public Property Subordinates As List(Of String)
End Class
Public Class SystemOwnerRole
 Inherits Role
 Public Property SoftwareSystems As List(Of SoftwareSystem)
End Class
Public Class SystemAdministratorRole
 Inherits Role
 Public Property SoftwareSystems As List(Of SoftwareSystem)
End Class
Public Class SecurityAdministratorRole
 Inherits Role
 ' Explictly a Security Admin for all Software Systems.
End Class
asked May 11, 2012 at 18:19

3 Answers 3

3

My suggestion is rather than making different User classes for different roles, have a single User class that contains a list of Role objects. Role would be a base class, with Manager, SystemOwner, SecurityAdmin, and SystemAdmin being derived classes, with fields specific to their needs. Manager would have a list of subordinates, SystemOwner would have descriptions of the system, etc. Role could have common fields, like an alternate approver, for example.

That architecture opens a lot of possibilities. Someone can easily be the owner of multiple systems, for example. That also makes queries like "list all system owners" easier.

answered May 11, 2012 at 19:03
1
  • I've prototyped some classes and put them in my OP. Does it look about right to what you were thinking? I am thinking that a SecurityAdministratorRole might not be needed, since it's target system independent, and will not have a designated approver. Commented May 11, 2012 at 19:25
1

I think the bit that you're missing is that Role is not an attribute of User. Role is an attribute of the relationship between two entities (either two users or a user and a system).

For example:

  • Bob might be the system owner of the Oracle database but have no ownership privileges with the SQL database.
  • Paul might be the manager of Bob but not the manager of Jason.

In the UML world, this sort of thing is called an association class. In the database world, it is called a descriptive attribute.

You will need

  1. A table of users, including user ID, name, and LAN ID
  2. A table of systems
  3. A table of user-user relationships. Each row should contain a FromUserID, ToUserID, and a RoleID (e.g. manager). You might also want a start and end date, since roles could change.
  4. A table of user-system relationships. Each row should contain UserID, SystemID, and a SystemRoleID (e.g. owner). Again, you might also want a start and end date.

You can still have a IsManagerOf method or IsOwnerOf method, of course, as a matter of convenience. But it terms of your data model, they don't belong to the user at all, they belong to the relationship that is attached to the user.

answered May 23, 2017 at 23:03
1

Your domain model is over-engineered for your use cases. For "Acess Management", you do not need to model or store who is in who's team in your database -- those information would be more current in your ldap systems.

I believe you are complicating by storing roles. The below diagrams may provide a simplistic model that may cover your use cases.

User object just needs an enterprise-wide-unique id, nothing more. Most hierarchy data may already be in enterprise ldap.

Class Diagram

Most of the heavy-weight business logic can be doe in service layer -- with ldap and your local db as your data sources.

Sequence diagram

The request object may go through various states, persisted/ queried for further processing, and data analytics etc.

State changes for request

answered Oct 14, 2018 at 6:14

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.