Hi,
I'm trying to implement a custom permission to determine access to Actions. But I think something is wrong and need a little push.
<code lang="cs>
using System;
using System.Security;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Utils;
using DevExpress.Xpo;
namespace XXX.Security
{
[NonPersistent]
public class ActionAccessPermission : PermissionBase
{
public ActionAccessPermission()
{
}
public ActionAccessPermission(string actionId, ActionAccessModifier modifier)
{
this.ActionId = actionId;
this.Modifier = modifier;
}
public string ActionId { get; set; }
public ActionAccessModifier Modifier { get; set; }
public override System.Security.IPermission Copy()
{
return new ActionAccessPermission(ActionId, Modifier);
}
public override string ToString()
{
EnumDescriptor enumDescriptor = new EnumDescriptor(typeof(ActionAccessModifier));
return String.Format("{0} {1} ({2})", CaptionHelper.GetClassCaption(GetType().FullName), ActionId, enumDescriptor.GetCaption(Modifier));
}
public override void FromXml(SecurityElement e)
{
ActionId = e.Attributes["actionId"].ToString();
Modifier = (ActionAccessModifier)Enum.Parse(typeof(ActionAccessModifier), e.Attributes["modifier"].ToString());
}
public override SecurityElement ToXml()
{
SecurityElement result = base.ToXml();
result.AddAttribute("actionId", ActionId);
result.AddAttribute("modifier", Modifier.ToString());
return result;
}
public override bool IsSubsetOf(System.Security.IPermission target)
{
if (base.Intersect(target) != null)
{
if (((ActionAccessPermission)target).ActionId == this.ActionId
&& ((ActionAccessPermission)target).Modifier == this.Modifier)
{
return true;
}
return false;
}
return false;
}
}
}
</code>
If I only have one of these permissions in a role, it works fine. However, If I have multiple instances, things don't work right and it only ever checks one permission.
For example:
SecuritySystem.IsGranted("ResetPassword", ActionAccessModifier.Allow) (works fine)
SecuritySystem.IsGranted("SomeOtherAction", ActionAccessModifier.Allow) (doesn't work, inside my ActionAccessPermission class, it keeps checking for the first one I passed in… why?)
Do you see anything immediatley wrong wih my permission?
Thanks!
Hello Nate,
Thanks for contacting us. Please check out the end of the Action based Permission issue for some example code, showing how to check Actions permissions in a Controller. That should help you.
If there is further difficulty with your task, please attach a small demo, showing all the code you implemented. We will be glad to research it and help you.
Thanks,
Dennis
Thanks Dennis, I've seen that issue and I am doing something similar.
I've attached our project (again, though it's much cleaner than in the past, so don't be scared! :))
Particular areas of interest:
XXX\Security\ActionAccessPermission.cs (the permission)
XXX\WindowControllers\ActionPermissionWindowController.cs (window controller that sets actions Active status)
This user is in the Administrators role. I've added 3 (deny) action access permissions there. InvoiceClients, EnvelopeClients and ResetPassword. All of these appear on the client listview. InvoiceCLients is removed properly, however that's the only one that works! I don't get why. There isn't a lot of documentation on custom permissions so I'm sure I'm missing something!
Based on the fact that someone else has implemented a similar approach, does it make sense to create a suggestion for such a permission from DX? Seems like a pretty useful thing.
Thanks!!!
Oh yeah, I uncommented some code so it will give you a compile error to take you right to that spot (override IsSubsetOf) where I belive the problem is.
Hello Nate,
Thanks for the update. Your ActionAccessPermission implementation is not correct. It mimics the EditModelPermission but it should be similar to the ObjectAccessPermission one.
I will provide further details as soon as I can. Please bear with me.
Thanks,
Dennis
Hello Nate,
After more thinking, and discussing your issue with the Team, I tend to think that handling your scenario with the help of the security system is not the best option.
In fact, you're just tweaking the visibility of an Action. This task can already be done via a Controller in a more elegant way.
If you think that it can be done with the Security system, then please tell us more about your scenario and describe exactly which Actions, and under which conditions you would like to hide.
I would also say that we had a similar suggestion in the past: ConditionalAppearance - Make it possible to manage Action availability against the currently logged user, but it was not quite clear.
Some standard XAF Actions already depend on the Security system via the DataManipulationRight class. If you want, you can use it the same way it's used in the standard controllers, to prevent a user from executing the Actions.
For example, use the NewObjectViewController and DeleteObjectViewController classes as examples.
Let me know if you have additional questions.
Thanks,
Dennis
Thanks for your input Dennis.
Our purpose of wanting to handle this in the security system is simple. Our clients have a lot of custom needs as far as permissions go. Originally we had just a few simple roles, but more and more people are wanting to customize these. All of our viewControllers used to check if it could activate the action based on role name, but people creating custom permissions then get left in the dust. We are looking at sunsetting this particular application and a system like this will allow for our customers to have full customization over what roles can do. Currently we're having to either create roles that the software supports, or ignore these requests. We liked the idea so much that it will be implemented in our other XAF applications as well (if we can get it working right)
I did not see that previous suggestion, but it is exactly what I want (even the class name i used in my example!)
I think this fits in well to XAF by default, honestly and am suprised that there is a little resistence on the XAF team's end. ObjectAccess combined with something like this and the upcoming member level security would really give full control over the XAF application.
Here are a few examples of why we need soemthing like this…
I'll answer the questions in that suggestion though:
- which actions do you need to disable?
all of them, custom and built in
- everywhere or for strict business classes?
everywhere
- for ListViews or for DetailViews?
both
- for WindowsForms or for ASP.NET applications?
both
- do you want to hide an action from a toolbar, or from a menu, or from everywhere?
everywhere
- for a specific user or for all users?
personally, role based is fine for me, so all users in a role
Hello Nate,
Thanks for your time and a lot of valuable feedback! It's greatly appreciated. We need some time to think it through and discuss it internally. We will update this ticket once we are done.
Meantime, if you are having any other problems with XAF or with my previous suggestions on your problem, then feel free to contact us again.
Thanks,
Dennis
Hey Dennis,
Was wondering if there was any discussion on this. We're at the point where we need to figure this out. Does this seem like a doable scenario with the current release? If so, can you nudge me in the rght direction for how this permission should be dealt with?
Thanks, dude!
Nate
Hello Nate,
Thanks for the feedback, and sorry for the delay.
We are uncertain that this functionality will be implemented by the Security module, because it's more about the protection of data rather than about protection of the UI. As you probably know, we are going from UI-based security to data-based security that works on the server side. However, we agree that the ConditionalAppearance - Make it possible to manage Action availability against the currently logged user suggestion makes sense. Possibly, it will be addressed by the ConditionalAppearance module, once it is able to evaluate a criteria against a global criteria or method instead of just business objects shown in Views. I would like to demonstrate my idea with some pseudo code:
[Appearance(AppearanceItemType = AppearanceItemType.Action, TargetItems = "MyCustomAction", Enabled = false, Criteria = "'@GlobalCurrentUser'.Roles[Name='Administrators'].Count>0")]
Will it suit you?
Thanks,
Dennis
P.S.
Hey Dennis,
Yes, please feel free to strip this issue and make it public.
RE: the Conditional appearance portion, I don't think that will work for this case, since the goal of this is to create totally customizable roles, giving end-users, not the developers full control over every aspect of the software.
I really think the best option is an ActionAccessPermission with a simple Allow/Deny modifier and an ActionId and it definitely seems do-able, I just can't seem to figure it out. It would benefit XAF developers to the extent that I would highly suggest you consider it as a KB article (you do such good ones, you know! :))
>>Yes, please feel free to strip this issue and make it public.
Thanks!
>>RE: the Conditional appearance portion, I don't think that will work for this case, since the goal of this is to create totally customizable roles, giving end-users, not the developers full control over every aspect of the software.
It's possible to create Appearance rules via the Model Editor in the Model.XAFML (intended for application's administrators). Creating these rules doesn't need extensive development skills. Does this suit you?
>>I really think the best option is an ActionAccessPermission with a simple Allow/Deny modifier and an ActionId and it definitely seems do-able
To be honest, we don't think that this is a good solution, due to the strong reasons described above. We will unlikely implement the ActionAccessPermission in XAF, but anyway, thanks for the idea about creating a KB.
Thanks,
Dennis
Dennis,
I disable model customization in all my deployed apps, so that won't work.
You mention that SecuritySystem does not handle UI, but that's not true. You only need to look as far as ObjectAccessPermission and the Navigate permission specifically. Beyond that, creating an action that calls myObject.Delete() does not enforce if the logged in user has the ability to delete or not, that's only handled on the UI.
While I maintain that I think this fits in well to your current model, I respect your decision in that regard. That said, I really need a push in the right direction to get this working in a way that makes sense for my end users, and according to the duplicate issues surrounding this one, other xaf'ers end users :) Am I not correct that you, Dennis, the king of XAF could whip this permission up in a matter of minutes? :P