*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
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..
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.
Marc
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?
I think i got it. thanks..once again..you were a life saver..
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
> 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.
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
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 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..
[ProvideProperty("Role", typeof(Component))]
Marc
Hi,
Visual Guard .Net is probably a good solution:
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);
}
}
}
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