Implement authorization in win forms

  • Thread starter Thread starter parez
  • Start date Start date
P

parez

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.
 
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
 
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

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
 
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
 
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

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..
 
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
 
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

That sounds good. I will look into extention properties.
Thanks.
 
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
 
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;
}
}
 
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;
}
}

Thanks..

How will i use the RoleDisabler ? would i drag it from the toolbar
like tooltip?
 
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;
}
}

Thanks..

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

That was great.. thanks...
I have a question..
When will the SetEnabled function execute?
 
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;
}
}

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

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

I think i got it. thanks..once again..you were a life saver..
 
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 quotedtext -

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

Marc
 
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.
 
Basically I need function RoleLevel( role, department) which returns access

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
 
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.


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

Marc

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
 
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;
}
}
 
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;
}

}

I tried that .. It did not work... it still doesnt show it..
 
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
 

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

Back
Top