views:

331

answers:

1

How do you implement Roles and Security in your C# Domain Driven Designs? We have some debate raging on wether it should be implemented by the calling application (ASP.NET MVC) or in the Domain Model itself (model entities and services). Some argue that it should be in the web site itself since that's where the authentication already exists. But that means you have to re-implement security every time you integrate with the core business systems.

As an example: an Admin should be able to do pretty much any action in the system such as edit and deleting records (ie they can delete a user's order). A User on the other hand should only be able to edit and delete their own records (ie they can add/remove items from their shopping cart).

BTW Here is a nice thesis on the topic which covers 7 different scenarios regarding DDD & Security:

Security in Domain-Driven Design

  • Chapter 4 Security service design scenarios
    • 4.1 Scenario 1: Security service as regular service
    • 4.2 Scenario 2: Security embedded in the UI
    • 4.3 Scenario 3: Security service encapsulating the domain model
    • 4.4 Scenario 4: Security service as a gateway for the UI
    • 4.5 Scenario 5: Security service as an adapter for the UI
    • 4.6 Scenario 6: Security service integrated by AOP with adapters
    • 4.7 Scenario 7: Security service integrated with AOP

I would personally lean towards AOP using PostSharp but not having do much with it before I'm hesitant to take the leap.

+1  A: 

Don't forget that the runtime already has an abstracted security/user system built in - the principal (see this existing answer - note that GenericIdentity is just one option; it is pretty trivial to write your own).

Your UI can handle creating and assigning the principal based on the specific implementation (indeed, IIRC ASP.NET and WCF do this automatically, or for winforms/wpf you can use the windows identity, or (via a web-service) the same ASP.NET login).

Your business logic then just checks Thread.CurrentPrincipal; from this you can get the name, the authentication method, and check for roles (without needing to know how roles are implemented).

The runtime also provides inbuilt checks:

    [PrincipalPermission(SecurityAction.Demand, Role = Roles.Admin)]
    public void Foo() {...}

(where Roles.Admin is a string constant of your role name) This will check access automatically, throwing a SecurityException if not in the role. You can also check via code (useful if the role isn't fixed at compile time).

Obviously your UI should check roles (to disable/hide functionality), but it is good to have the business code enforce the roles without needing to know about the UI.

(added)

I should mention that GenericIdentity is handy for unit tests. Of course, you could role your own security API, and nobody will stop you...

Marc Gravell
What's to prevent a user from forming their own url /Order/Delete/42 when they are not the owner of that specific order number? I understand restricting access based on roles but that doesn't cover ownership, does it?
Todd Smith
Indeed it doesn't (by itself); you'd need to pick the role based on the individual request data.
Marc Gravell
So in addition to the role authorization provided by something like the PrincipalPermission attribute I'd would still need to perform an ownership check such as if (!order.IsOwnedBy (User.Identity.Name)) {throw} ?
Todd Smith
Marc Gravell