creating a _simple_ fine grained user based security system

G

giddy

hi,

(I want someone to check if my idea is utterly stupid or ok??)

I have a mid complex app for a hotel that needs a fine grained user
security system. In other words an admin should be able to deny/grant
specific access to users like Ability to make a Reservation or the
ability to print reports.

Now, I'm thinking the business objects could take something like:

enum UserPrivileges { various privileges....... };

IPrivilegedUser
{
public UserPrivileges Privileges
{
get;
}
}

The user class inherits from this interface, the business objects
could take this user in a function and return true/false as per the
needed privileges, or maybe throw an exception:

User user1 = new User(); //class User inherits from IPrivilegedUser
and loads the right privileges from the DB
Reservations.LoadPrivileges(user1);//check the returned value..??
Reservations.EditReservation() // calling this should fail if the
privileges are not enough!?

Is this a good enough design, will it break apart somewhere or is
there a better way to do this?

Declarative security like CAS in .NET would be an overkill since its
not a very large app, but I do need the design to be flexible enough
so that if the app does grow big I'm not in a mess.

Thanks

Gideon
 
P

Peter Morris

I'd create an interface, something like this

IUserPermissionService
{
bool CanCreateReservations(User user);
bool CanEditReservation(User user, Reservation reservation);
etc
}

I'd then create a class that implements this and register it in a class that
implements IServiceProvider. If you make sure the instance of
IServiceProvider is always available then any layer of your app can access
stuff via interfaces in a loosely coupled way. Another benefit of this is
that when you write your unit tests you can create a mock
IUserPermissionService and register it in the service provider in order to
control the outcome of the test.




Pete
 
G

giddy

hi Peter,

Thanks so much for your reply.
IUserPermissionService
{
    bool CanCreateReservations(User user);
    bool CanEditReservation(User user, Reservation reservation);
    etc

}

This is nice, I've still got just few simple question, should I make
the ServiceProvider singleton? So its available everywhere?

Also, I will be testing for user rights in the UI's presentation
classes so is there a nice way to Disable/Enable menus, buttons based
on when a new User signs in?

I was thinking the MainWorkspace(Form) and the subview(usercontrols)
and menus respond to a UserChanged event and then call the service to
check for the right privileges. But where should the UserChanged event
come from in the first place?

Thanks so much

Gideon
 
M

Marc Gravell

To be honest, I'd still be tempted to use an IPrincipal. This does
everything you want with existing APIs. You could always add a static
class to provide simplified access, i.e.

public static bool CanCreateReservation() {
return HasAccess(some constant)
}
private static bool HasAccess(string role) {
// get principal and call IsInRole...
}

If you don't want to create your own principal, you can use
GenericPrincipal / GenericUser very simply.

Marc
 
P

Peter Morris

This is nice, I've still got just few simple question, should I make
the ServiceProvider singleton? So its available everywhere?
<<

You could do, yes, as long as you ensure thread safety in your services.
Also, I will be testing for user rights in the UI's presentation
classes so is there a nice way to Disable/Enable menus, buttons based
on when a new User signs in?
<<

You'd have to execute some code after login to enable or disable them based
on results from the security service.

I was thinking the MainWorkspace(Form) and the subview(usercontrols)
and menus respond to a UserChanged event and then call the service to
check for the right privileges. But where should the UserChanged event
come from in the first place?
<<

You expect the user to change whilst your app is running? Can you explain?



Pete
 
M

Marc Gravell

Also, I will be testing for user rights in the UI's presentation
classes so is there a nice way to Disable/Enable menus, buttons based
on when a new User signs in?

I didn't add anything to support hot-swapping of the user (since that
isn't usually expected), but for a lazy way to enable/disable buttons,
etc - how about a custom UI component that lets you specify roles on
controls in the IDE?

http://groups.google.com/group/micr...read/thread/3c9eb4ca945ae674/6b4930682504e819

Note that UI enabling/disabling should really be just a convenience -
your "real" code should enforce the access - hence why declarative
security ([PrincipalPermission] etc) can be useful for simple code.

Marc
 
G

giddy

hi thanks for your replies,
You expect the user to change whilst your app is running? Can you explain?
oh, seem like an odd thing for you guys? Different users with
different privileges work in different shifts on the same machine
which runs the app, so after a certain time the app on Machine1 will
have another user with different privileges logging in. It would be a
little odd for me to tell them to shut the app down just for the next
person. Also, its only a matter of calling UIEnable routines through
an event.

I didn't add anything to support hot-swapping of the user (since that
isn't usually expected), but for a lazy way to enable/disable buttons,
etc - how about a custom UI component that lets you specify roles on
controls in the IDE?

http://groups.google.com/group/microsoft.public.dotnet.languages.csha...

I like your component Marc although I was thinking more along the
lines of a service.

Note that UI enabling/disabling should really be just a convenience -
your "real" code should enforce the access - hence why declarative
security ([PrincipalPermission] etc) can be useful for simple code.

Yes, i understand what you're saying, i did think about this, was kind
of hard to explain. (I'm not formally computer literate)

If Base Code enforces security I would still be doing the same thing
in the UI code.

if(userPermService.CanEditReservations(user1))
{
Reservations.Edit(res1);//now whether my code enforces permissions or
not would make a difference here right?
}
Unless of course if i tried to directly call Reservations.Edit(res1);
without checking for permissions the code would throw an exception if
he didn't.

So does that make it a better design? Enforcing rules so that I
*might* not end up making a mistake?

Thanks so much
Gideon
 
P

Peter Morris

oh, seem like an odd thing for you guys? Different users with
different privileges work in different shifts on the same machine
which runs the app, so after a certain time the app on Machine1 will
have another user with different privileges logging in. It would be a
little odd for me to tell them to shut the app down just for the next
person. Also, its only a matter of calling UIEnable routines through
an event.

But it wouldn't be odd to ask them to sign out of the app when they leave,
returning the user to the sign in form. So you wont be "hot" swapping the
user then (changing the user in the middle of something).
So does that make it a better design? Enforcing rules so that I
*might* not end up making a mistake?

I always do that. For example; my business objects are able to produce a
list of validation errors. I use those in the GUI to prevent the user from
saving. However, it is possible that something might eventually call
UpdateDatabase on my persistence service without first checking these
constraints, so my persistence service will check the validity of each
object before attempting to save and throw an exception if there is
something wrong.



Pete
 
M

Marc Gravell

Just to second what Pete said:

* returning to a login form makes for a clean place to swap users
without existing forms needing to worry
* your business logic should definitely enforce any rules

The biggest point about the second bullet is that it allows you to
cleanly separate the UI from the business rules; for example, you
might have an alternative UI for some users (perhaps a web/winform/wpf/
silverlight/CF version etc), but it would be nice if the same rules
were applied in case you forget things. Declarative security just
happens to be a simple way of handling the "check access and throw an
exception" in a single statement, without cluttering the code:

[PrincipalPermission(SecurityAction.Demand, Role =
MyRoles.ReservationEdit)]
public void EditReservation(...)
{
//...
}

(obviously you can do more sophisticated things if you want to check
different roles in different scenarios, etc)

For re-use (and to avoid duplication / typos) you can keep the roles
together like:

static class MyRoles
{
public const string ReservationEdit = "RES EDIT";
// ...
}

If you wanted to get fancy you could probably also hook it into that
IDE component without too much pain...

The point of the IPrincipal usage is partly that it allows use of
declarative security - but more importantly this is how all the core
framework identity code operates: if you login to ASP.NET, you get an
IPrincipal. If you login via WCF you get a IPrincipal; etc. You can,
of course, invent your own API - but using the core API allows you to
exploit all the framework code. For example, you could use "client
application services" in VS2008 to use the same identity/roles model
for aspx and winform/wpf.

Marc
 
G

giddy

hi,

thanks for your help. I get what you saying.

I'm just a little afraid of over complicating this app, its in its
second version now. I ruined the first by created a mess of code that
was too complicated with all sorts of "features"

I want make it simple but sturdy so It can change later, and this
seems like the way to go.

I know .NET very well actually, but i'm just not old/experienced
enough to design an app all on my own.

Thanks so much

Gideon
 
M

Marc Gravell

I'm just a little afraid of over complicating this app

IMO - creating your own identity/roles model adds complexity. Using
IPrincipal, especially if you just start at the simplest level using
GenericPrincipal etc keeps the complexity low while allowing you to
switch to more sophisticated models later.

Here's some code that tells the system that the current user is Fred,
and the roles he has:

Thread.CurrentPrincipal = new GenericPrincipal(
new GenericIdentity("Fred"),
new string[] { "GUEST", "USER", "CUST EDIT", "CUST
ADMIN" }
);

Obviously in most cases you'd build the list of roles separately
(perhaps in a List<string>).

Marc
 
G

giddy

thanks so much Marc,

I've already planned a User class so I think it would be better for me
to derive from IPrinciple .

Gideon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top