Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Implement authorization in win forms

611 views
Skip to first unread message

parez

unread,
Apr 10, 2008, 4:49:26 PM4/10/08
to
Whats the best way of implementing authorization in a win forms
application.
I mean things like show/hide or enable/disable Save button ,creating
context menus etc.

Marc Gravell

unread,
Apr 10, 2008, 5:14:28 PM4/10/08
to
Not fully sure what the question is; personally, I would set up an
IPrincipal representing the user at entry into the app (VS2008 has an
IPrincipal implementation that hooks into asp.net/smart-client for
login & roles), and check IsInRole(...).

*what* to do depends on the scenario; smoetimes it is desirable to
hide things completely; sometimes it is preferable to show that they
exist (but are unavailable).

But the ***most important thing*** is: always treat the client as
hostile. In a smart-client scenario, then by all means do things at
the UI to help the user, but *first* ensure that the server applies
the same security limitations; i.e. it is trivial to write a custom
client (either by reverse engineering, or by simply hooking the wsdl)
that connects to your service but without *any* validation.

Marc

parez

unread,
Apr 10, 2008, 5:24:48 PM4/10/08
to

Let me explain my quesiton I am using item based authorization ( not
role based).
e.g I have 10 forms in the application. for each of the forms/actions
there will be View Update Delete permissions
for each user. so when the user logs in , should i hardcode the
enabling/disabling of the buttons that show the forms
or is there a better way. Also which event should be appropriate for
checking permissions.

I cannot use asp.net roles. I am using VS2008 winforms 3.0

Marc Gravell

unread,
Apr 10, 2008, 5:33:22 PM4/10/08
to
No; there is no magic roles code built into the UI framework itself;
having used this in some other environments, I do miss it.

If the security model was strictly roles-based, then OnLoad would be a
sensible time to disable buttons. If it is item-based, then only you
know when you have enough information to make an assertion about
security.

I suspect that some sensible level of specific coding is the most
pragmatic approach. If you have a large system, you might want to
think about describing security though metadata, but this is trickier,
and hard to assess in a vacuum (i.e. there isn't enough information
here to give a meaningful reply).

Marc

parez

unread,
Apr 10, 2008, 5:58:46 PM4/10/08
to

So what do you think about. Storing the ItemID(hardcoding) at design
time in the Tag property of the windows controls.
And at run time on Onload Event iterate thru all controls having tag
as some number.
and then based on my Permissions class set it to enabled/ or
disable..

Marc Gravell

unread,
Apr 10, 2008, 6:06:19 PM4/10/08
to
I'd say that this isn't a *bad* solution - but Tag is (by definition)
very vague... just make sure that this isn't going to confuse any
other UI code that expects to store some kind of state in there. If
your permissions code fires early enough, it might be sensible to
clear (set to null) the Tag after each, to avoid any confusion?

If you want to do it properly, I'd look at "extension properties";
kinda like how ToolTip works, i.e. an extra property ("Access" etc)
appears magically in the designer, but gets stored against a separate
container. This isn't trivial, but might be worthwhile for a non-
trivial project. It would also allow you to call
securityProvider.Enforce() [or whatever you code it as], which simply
has a nice ring to it ;-p

Marc

parez

unread,
Apr 10, 2008, 6:09:46 PM4/10/08
to

That sounds good. I will look into extention properties.
Thanks.

Marc Gravell

unread,
Apr 10, 2008, 6:20:23 PM4/10/08
to
If you get stuck, please let me know. This is part of
System.ComponentModel, an area that I know very well. Although I
understand them, I haven't personally *created* an extension property
before, but I imagine that it isn't too tricky *if* you understand how
the rest of that area works. Actually, I'd happily use it as an excuse
to do some more digging in that area... ;-p

Marc

Marc Gravell

unread,
Apr 11, 2008, 4:25:59 AM4/11/08
to
For info, here is a rough sketch of what the component would look
like... this allows both IDE and programmatic usage; note that for
roles-based security you'd also need to initialize the principal - at
the most primative this can be as simple as:

Thread.CurrentPrincipal = new GenericPrincipal(
new GenericIdentity("Marc"), // name of user
new string[] { "BASIC" } // array of roles that the
user has
);

Obviously if your security model is more complex, you may need to
change things ;-p

[ProvideProperty("Role", typeof(Control))]
[ToolboxItemFilter("System.Windows.Forms")]
[Description("Provides automatic role-checking")]
public class RoleDisabler : Component, IExtenderProvider
{
private Dictionary<Control, string> map
= new Dictionary<Control, string>();
[DefaultValue("")]
public string GetRole(Control control)
{
if (control == null) return "";
string role;
map.TryGetValue(control, out role);
return role ?? "";
}
public void SetRole(Control control, string role)
{
if (control == null) return;
bool add = false, remove = false;
if (string.IsNullOrEmpty(role))
{
remove = map.Remove(control);
}
else
{
add = !map.ContainsKey(control);
map[control] = role;
}
if (!DesignMode)
{
SetEnabled(control);
if (add)
{
control.ParentChanged += control_ParentChanged;

}
else if (remove)
{
control.ParentChanged -= control_ParentChanged;
}
}
}
private void SetEnabled(Control control)
{
if (DesignMode || control == null) return;
string role;
if (map.TryGetValue(control, out role))
{
IPrincipal principal = Thread.CurrentPrincipal;
control.Enabled = principal == null ? false :
principal.IsInRole(role);
}
}
void control_ParentChanged(object sender, EventArgs e)
{
SetEnabled(sender as Control);
}
bool IExtenderProvider.CanExtend(object obj)
{
return obj is Control;
}
}

parez

unread,
Apr 11, 2008, 1:49:56 PM4/11/08
to

Thanks..

How will i use the RoleDisabler ? would i drag it from the toolbar
like tooltip?

parez

unread,
Apr 11, 2008, 2:14:03 PM4/11/08
to

That was great.. thanks...
I have a question..
When will the SetEnabled function execute?

parez

unread,
Apr 11, 2008, 2:46:20 PM4/11/08
to

I think i got it. thanks..once again..you were a life saver..

Marc Gravell

unread,
Apr 11, 2008, 5:06:01 PM4/11/08
to
> > When will  the SetEnabled function execute?

When not in the designer (DesignMode), it executes when you either
change the role (SetRole), or when the control is added to a parent.
The reason for this second bit is this is always the last thing that
designer-generated code does - so it will take precendence over the
designer.

> I think i got it. thanks..once again..you were a life saver..- Hide quoted text -

No problem; I'm always up for an excuse to mess in the
System.ComponentModel ;-p

Marc

Andrus

unread,
Apr 12, 2008, 8:23:05 AM4/12/08
to
Marc,

> Not fully sure what the question is; personally, I would set up an
> IPrincipal representing the user at entry into the app (VS2008 has an
> IPrincipal implementation that hooks into asp.net/smart-client for
> login & roles), and check IsInRole(...).

I have 3 property security role:

1. Security item: Invoice, Order, Customer, Item etc.
2. Hierarchical access levels: View, Add, AddAndPost, Change. Every next
level includes
all previous levels.
3. Department: department code

I need to define security roles for WinForm application like:

User X can Changes invoices in department A
User X can view invoices in department B
User X can change change all departments orders

There are also user groups. User can be member in any number of groups and
inherits those group privileges.
All security information is hold in server database and retrieved using
DLinq.

Basically I need function RoleLevel( role, department) which returns access
level.

It it possible/reasonable to use any framework class for this or other ready
security manager or should I re-implement this from zero ?

Andrus.


Marc Gravell

unread,
Apr 12, 2008, 4:53:15 PM4/12/08
to
> Basically I need function RoleLevel( role, department) which returns access
> level.

The inbuilt roles-based security (IPrincipal) only covers single-
dimension roles. You can of course shim this by using roles like
SOMEDEPT_EDIT, SOMEDEPT_READ etc; whether that is sensible or not
depends on the scenario. Another option is NT ACLs, but then you need
to impersonate into that NT user - but it can be very flexible.

Marc

parez

unread,
Apr 14, 2008, 2:44:38 PM4/14/08
to

Hi,

I just one more issue... If a control has sub-control(component) then
it does not show up for the sub components.
e.g MenuStrip control has ToolStripMenuItem children. How do I make
it show up(in properties) for those controls.

TIA

Marc Gravell

unread,
Apr 14, 2008, 4:01:54 PM4/14/08
to
> I just one more issue... If a control has sub-control(component) then
> it does not show up for the sub components.
> e.g MenuStrip control has ToolStripMenuItem children.  How do I make
> it show up(in properties) for those controls.

I suspect that is because ToolStripMenuItem isn't a Control, and I
restricted it to Controls; Changed as below (I also removed the events
stuff - didn't seem necessary in hindsight):

[ProvideProperty("Role", typeof(Control))]
[ToolboxItemFilter("System.Windows.Forms")]
[Description("Provides automatic role-checking")]
public class RoleDisabler : Component, IExtenderProvider
{

private Dictionary<object, string> map
= new Dictionary<object, string>();
[DefaultValue("")]
public string GetRole(object obj)
{
if (obj == null) return "";
string role;
map.TryGetValue(obj, out role);
return role ?? "";
}
public void SetRole(object obj, string role)
{
if (obj == null) return;
if (string.IsNullOrEmpty(role))
{
map.Remove(obj);
}
else
{
map[obj] = role;
}
if (!DesignMode)
{
SetEnabled(obj);
}
}
private void SetEnabled(object obj)
{
if (DesignMode || obj == null) return;
string role;
if (map.TryGetValue(obj, out role))
{
IPrincipal principal = Thread.CurrentPrincipal;
bool isInRole = principal == null ? false :
principal.IsInRole(role);
if (obj is Control)
{
((Control)obj).Enabled = isInRole;
}
else if (obj is ToolStripItem)
{
((ToolStripItem)obj).Enabled = isInRole;
}
}
}
bool IExtenderProvider.CanExtend(object obj)
{
return obj is Control || obj is ToolStripItem;
}
}

parez

unread,
Apr 14, 2008, 6:13:39 PM4/14/08
to

I tried that .. It did not work... it still doesnt show it..

Marc Gravell

unread,
Apr 15, 2008, 2:49:46 AM4/15/08
to
Curoious - even though it accepts multiple ProvidePropertyAttribute
declarations, only the first is used... never mind; change the
[ProvideProperty] line to:

[ProvideProperty("Role", typeof(Component))]

Marc

stv....@gmail.com

unread,
Apr 16, 2008, 9:23:40 AM4/16/08
to
On Apr 10, 10:49 pm, parez <psaw...@gmail.com> wrote:
> Whats the best way of implementingauthorizationin a win forms

> application.
> I mean things like  show/hide or enable/disable Save button ,creating
> context menus  etc.

Hi,

Visual Guard .Net is probably a good solution:

http://www.visual-guard.com/EN/.net-security-user-role-permission/identity-management-access-control-authentication-tool#admin

parez

unread,
Apr 17, 2008, 10:55:31 AM4/17/08
to

Hi Marc,

I added the following to the RoleDisabler .. and now it also enables /
disables everytime my permission changes..
Thanks again..

private void HookUpEventhandlers()
{

UserAccessInfo.UserPermissionsUpdated += new
EventHandler<EventArgs>(UserAccessInfo_UserPermissionsUpdated);
}

void UserAccessInfo_UserPermissionsUpdated(object sender,
EventArgs e)
{
foreach (object obj in map.Keys)
{
try
{
SetEnabled(obj);
}
catch(Exception ex)
{

Trace.WriteLineIf(Logger.Instance.TraceSwitch.TraceError,
ExceptionUtility.GetInnerMostException(ex).Message);
}
}
}

Martin

unread,
Jul 16, 2008, 7:08:52 PM7/16/08
to
Hi Marc

Firstly thanks for posting your code - it's proving very useful for me (and many others I'm sure).

I've tested the code on my forms and it seems to deal very well with most things but "falls down" a little with things like datagridviews etc where more than one property would be bound - the code you've posted can happily enable/disable the entire control (i.e. all cols) but how would you go about hiding/making readonly some columns dependent on roles (i.e. "CanView"/"CanEdit" type properties?

Thanks in advance
Martin

0 new messages