I wouldn't have chosen to word the original comment the way it was worded, but it does identify a potentially legitimate issue.
Specifically, the concerns that warrant separation are authentication vs. authorization.
Authentication refers to the process of logging in and getting an identity. It is how the systems knows who you are, and used for things like personalization, object ownership, etc.
Authorization refers to what you are allowed to do, and this (generally) is not determined by who you are. Instead, it is determined by some security policy like roles or permissions, which don't care about things like your name or email address.
These two can change orthogonally to each other. For example, you might change the authentication model by adding OpenID/OpenAuth providers. And you might change the security policy by adding a new role, or changing from RBAC to ABAC.
If all of this goes into one class or abstraction, then your security code, which is one of your most important tools for risk mitigation, becomes, ironically, high-risk.
I have worked with systems where authentication and authorization were too tightly coupled. In one system, there were two parallel user databases, each for one type of "role". The person or team who designed it apparently never considered that a single physical user might be in both roles, or that there might be certain actions which were common to multiple roles, or that there could be problems with User ID collisions. This is an admittedly extreme example, but it was/is incredibly painful to work with.
Microsoft and Sun/Oracle (Java) refer to the aggregate of authentication and authorization information as the Security Principal. It's not perfect, but it works reasonably well. In .NET, for example, you have IPrincipal
, which encapsulates the IIdentity
- the former being a policy (authorization) object while the latter is an identity (authentication). You could reasonably question the decision to put one inside of the other, but the important thing is that most code you write will be for just one of the abstractions which means it is easy to test and refactor.
There's nothing wrong with a User.IsAdmin
field... unless there is also a User.Name
field. This would indicate that the "User" concept isn't properly defined and this is, sadly, a very common mistake among developers who are a bit wet behind the ears when it comes to security. Typically, the only thing that should be shared by identity and policy is the User ID, which, not coincidentally, is exactly how it is implemented in both the Windows and *nix security models.
It's completely acceptable to create wrapper objects that encapsulate both identity and policy. For example, it would facilitate the creation of a dashboard screen where you need to display a "hello" message in addition to various widgets or links that the current user is permitted to access. As long as this wrapper just wraps the identity and policy information, and doesn't claim to own it. In other words, as long as it's not being presented as an aggregate root.
A simplistic security model always seems like a good idea when you're first designing a new application, because of YAGNI and all that, but it almost always ends up coming back to bite you later, because, surprise surprise, new features get added!
So, if you know what's best for you, you'll keep authentication and authorization information separate. Even if the "authorization" right now is as simple as an "IsAdmin" flag, you'll still be better off if it's not part of the same class or table as the authentication information, so that if and when your security policy needs to change, you don't need to do reconstructive surgery on your authentication systems which already works fine.
User
object with anisAdmin()
method (whatever it does behind the scenes)