Deciding on the correct syntax for UI permissions
Going back to why I hate new projects, I am trying to figure out how to perform UI level security. Right now I need to dynamically decide whatever or not a user can edit a webcast. I came up with the following options.
Explicitly allow this for administrators only:
<% component adminOnly: %> ${ Html.LinkTo( "Edit", "webcast", "edit", webcast.Id) } <% end %>
Allow this by operation:
<% component securedBy, {@operation: '/webcast/edit': %> ${ Html.LinkTo( "Edit", "webcast", "edit", webcast.Id) } <% end %>
The second is much more flexible, but I am not sure that I am happy about putting the operation in the view.
I can create this, for that matter, which might be better all around, in which case this encapsulate everything inside it.
<% component edit, {@entity: webcast} %>
Thoughts?
Comments
Let me know when you figure it out! I've been doing it the explicit way bet it feels wrong. Sort of like I'm putting logic in the presentation, but sometimes it feels like that logic should be there anyways.
I created a similar component to your second option and I had the same kind of feeling where I didn't want to put that in the view. However since I am not relying on the view to ENFORCE the authorization but simply using RhinoSecurity to answer the question on whether or not to render something I am okay with it.
Hi,
Since, you are using ASP.NET MVC you can use ActionFilters to perform security. Here is one example:
http://azamsharp.com/Posts/11_ASP_NET_MVC_Controller_and_Action_Role_Authentication.aspx
If you are interested in displaying option of editing or delete then you can use LoginView template but that is for webforms and not for MVC.
HI
In webforms I usually use the strategy pattern to decide what should or shouldn't be acessable/visible to the user. that way I only have to do the security checking once, and your syntax boils down to
element.visible = strategyInstance.ElementVisible;
Hi Ayende
i am getting started with Monorails and i am using RhinoCommons. but i am bit lost on how to go about testing Controllers. as i am using UnifOfWork i guess i need to inherit from DatabaseTextFixtureBase but for testing controllers inheriting from BaseControllerTest would help. i checked your HibernatingForum and Exesto samples but there are no tests for Controllers. just wondering if you could suggest on how to test controllers.
@Ayende:
I see two valid options:
the Controller will setup a parameter ( PropertyBag["AllowEdit"] = true ) and then the view needs no logic, but a simple if AllowEdit:
Use an encapsulated EditLink component.
no. 2 looks better more scalable - should if more checks will be needed, or moving from Admin/NonAdmin to SecuredBy etc. will be a single-place-change.
@AzamSharp:
We're talking about not even rendering the 'offending' action links, not about blocking the actions on the server. for this we can use many different methods (PrincipalPermission, IFilter, DbC, etc.)
In one ASP.NET project I built a few customised controls for this, that looked a bit like this:
<SWBH:SECUREHYPERLINK id="HyperlinkPathology" Runat="server" Allowed="Doctor, Clinician, Administrator" WhenNotAllowed="Disable">Pathology & Radiology</SWBH:SECUREHYPERLINK>
I liked the fact that security was handled by this mini-framework rather than being scattered far and wide. Haven't given this much though, but in an MVC framework something like this might work
Html.LinkTo("Edit", "webcast", "edit", webcast.Id).Secure(Rule="Admin Only", FailAction="hide")
Controllers could init a security gateway, and you could test that various rules fail for a given controller/user.
Assert.IsTrue( myController.SecurityGateway.Allows("Admin Only"), "Admin Only should pass for user {0} in controller {1}")
I'm using Ken Egozi's first option, but with an enumeration for rights levels at presentation layer ( PropertyBag["Mode"] = Mode.User )
AzamSharp,
I am using MonoRail, and this is not something that you can do using filters, this is an action that is allowed, but you need to turn off & on certain parts of the UI.
The login view is very simple case of what I want, and what I am trying to get is the right syntax to use here
k03123,
I would not test controllers using DBFB. They should be tested entirely in memory.
I test repositories using this way.
I posted how to create such a test a few days ago.
ok got it. so if u r using repositories in controllers you will Mock it. i guess that's the way to go. right?
thanks Ayende! appreciated.
If you had a role EditWebcast you could use MonoRail's SecurityComponent http://www.castleproject.org/monorail/documentation/trunk/viewcomponents/security.html
I used something like this for a CRM system although on the downside I ended up with a lot of roles.
My question was related more to the problem of where I should specify the security information
Hmm, you have no problem putting
${ Html.LinkTo( "Edit", "webcast", "edit", webcast.Id) }
to the view basically encoding action and objecttype and ID into link but you have a problem with
<% component securedBy, {@operation: '/webcast/edit': %>
encoding action and objecttype info secure area component.
Why I don't see problem with second if there is no problem with first?
Because one is a view concern, the other is an applicative concern.
The view is responsible for setting things up so user actions will call the appropriate controllers actions.
The view is by no means responsible for security
Well, isn't hiding some of the actions from user depending on external information a procedure you do in your view's anyway? If you write single IF condition based on data controller sends, you have already involved application in your view :)
The decision if to render or not is view logic.
HOW you get this is the question.
The knowledge for that decision can be injected to your securedBy component by some external security framework. The component itself must just pass the parameters and context. In the end your view is doing exactly the same as if acting according to input parameters and knowing about actions on controllers.
It would most certainly would be injected.
My point is that I don't want the operation itself in the view.
Your view knows about controller actions, doesn't it? If you tie controller actions with security metadata somewhere, you probably had no problem referencing those actions from the view. Now if you call your operations just a special controller actions never called directly, you get your securedBy component syntax.
You have to tie security and UI information somewhere, I'm pretty sure with a system more complex than "view" "edit" you just cannot meta it away to edit/view component.
I am not sure that I follow that logic. Can you expain it with example?
In most cases, the question I have is whatever this is allowed or not, nothign else.
Ok, lets view it this way: view knows about the model. For example, it knows about the Customer type, it knows customer has property Id or Name.
Why cannot view know about security, it's just another part of the model? We have "security entity" webcast with property "edit". View doesn't have to know who and on what conditions can "access" this property, only that it exists.
On my entities I have a property called Access that returns a class that defines the options available. So things like CanSave, CanApprove, CanSubscibe etc. then in the view you just go entity.Access.CanSave.
Benefits are you have one class that defines the the operations that can be perfomed and the view code is very lite and readable. I also make this class implement an interface that I then use to check for permission before saving.. but I guess you use Rhino.Security for that..
Comment preview