Ayende @ Rahien

Refunds available at head office

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

Scott Muc
06/14/2008 03:27 AM by
Scott Muc

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.

Mike
06/14/2008 04:35 AM by
Mike

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.

AzamSharp
06/14/2008 04:45 AM by
AzamSharp

Hi,

Since, you are using ASP.NET MVC you can use ActionFilters to perform security. Here is one example:

http://azamsharp.com/Posts/11ASPNETMVCControllerandActionRoleAuthentication.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.

frederikm
06/14/2008 05:10 AM by
frederikm

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;

k03123
06/14/2008 06:50 AM by
k03123

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.

Ken Egozi
06/14/2008 08:51 AM by
Ken Egozi

@Ayende:

I see two valid options:

  1. the Controller will setup a parameter ( PropertyBag["AllowEdit"] = true ) and then the view needs no logic, but a simple if AllowEdit:

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

Tobin Harris
06/14/2008 09:29 AM by
Tobin Harris

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}")

Dan
06/14/2008 11:04 AM by
Dan

I'm using Ken Egozi's first option, but with an enumeration for rights levels at presentation layer ( PropertyBag["Mode"] = Mode.User )

Ayende Rahien
06/14/2008 12:12 PM by
Ayende Rahien

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

Ayende Rahien
06/14/2008 12:18 PM by
Ayende Rahien

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.

k03123
06/14/2008 02:27 PM by
k03123

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.

Adam B
06/16/2008 07:58 AM by
Adam B

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.

Ayende Rahien
06/16/2008 08:10 AM by
Ayende Rahien

My question was related more to the problem of where I should specify the security information

Bunter
06/17/2008 09:18 AM by
Bunter

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?

Ayende Rahien
06/17/2008 10:05 AM by
Ayende Rahien

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

Bunter
06/17/2008 10:29 AM by
Bunter

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

Ayende Rahien
06/17/2008 10:34 AM by
Ayende Rahien

The decision if to render or not is view logic.

HOW you get this is the question.

Bunter
06/17/2008 12:41 PM by
Bunter

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.

Ayende Rahien
06/17/2008 12:42 PM by
Ayende Rahien

It would most certainly would be injected.

My point is that I don't want the operation itself in the view.

Bunter
06/17/2008 01:25 PM by
Bunter

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.

Ayende Rahien
06/17/2008 05:28 PM by
Ayende Rahien

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.

Bunter
06/18/2008 08:48 AM by
Bunter

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.

Derek Ekins
06/24/2008 11:13 PM by
Derek Ekins

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

Comments have been closed on this topic.