Content "for members only" ?

Topics: Customizing Orchard
May 23, 2011 at 11:01 PM
Edited May 23, 2011 at 11:04 PM

Hi, I'm new to Orchard and to CMS in general. Will appreciate some help with the following.

I'm setting up a website for a small association. Although some pages are meant for general public (contact, meeting times), there is going to be much more content intended for members only - e.g. meeting minutes, reports, current affairs.

I've found layers but am not sure how this could be used to achive the goal. Obviously I could add some widget on "Authenticated" layer only and then edit this widget, but this seems like a very clumsy solution as such widged is not recognized as "proper" content. Also there does not seem to be a way to add Navigation buttons which would be visible/available only to authenticated users.

I feel I must have missed something obvious, or is such functionality really not implemented?

 

May 23, 2011 at 11:36 PM

I too would like to know how to set this up.

May 24, 2011 at 11:28 AM

There's some ongoing discussion regarding this :)

See the following thread for some of the latest info: http://orchard.codeplex.com/discussions/246434

In a nutshell the situation is: this feature isn't available in Orchard, and there are certain security issues with layers and widgets, but between myself and Piotr we very nearly have a module that will allow this, and there is a hope (at least from me) of changes being made in Orchard core to better facilitate this scenario. You can also vote up the following workitem which is pretty relevant: http://orchard.codeplex.com/workitem/17667 - although I'm thinking we need a new workitem to cover the security issues Piotr has highlighted.

Developer
May 24, 2011 at 2:18 PM

I've opened a workitem about the security issue: http://orchard.codeplex.com/workitem/17868.

I managed to create a module that adds a possibility to add custom authorization logic inside content handlers (OnAuthorization/OnAuthorized methods) - I'll publish it to the gallery later today and keep you posted. Basically it allows to filter out the content current user is not supposed to see. Authorization events get fired on different levels (starting from getting the content item, through CRUD operations, to building the final display) - it allows you to create very precise custom authorization schemes.

May 24, 2011 at 2:30 PM

Voted, and also updated http://orchard.codeplex.com/workitem/17667.

Looking forward to seeing that module, should easily be able to hook in the Quanta item permissions from those events :)

Developer
May 24, 2011 at 2:41 PM

Surely, I guess with a single line of code (call to authorization service):)

May 24, 2011 at 2:49 PM

Well, it's a bit different how it works - it will check for "EffectiveRole" connectors from the user to the content item, and then check the permission based on those roles instead of the user's base role. So for example you can have an effective role of Admin but just over that content item; so you can view it but other people can't.

Developer
May 24, 2011 at 3:08 PM

Right, I understand. It looks like a perfect fit, because the OnAuthorization/OnAuthorized events are called per-item. The only problem I see would be dealing with performance, as those events get fired lots of times in a single request, so some caching scheme has to be applied. 

May 24, 2011 at 3:16 PM
Edited May 24, 2011 at 3:17 PM

OK just so I understand the above discussion. With your proposed changes will it be possible to support "private" urls/pages that only the authenticated user and administrators can access? A simple example would be in a Forum where only the user and administrators are allowed to access and modify the user profile edit page?

May 24, 2011 at 3:30 PM

Yep, it's something I need to look at in general with Mechanics. For viewing an ordinary page, there will just be a couple of extra queries for that item and any widgets etc. that display. But, with more complex usage of Mechanics you suddenly have a whole load of different types of connector rendering further content items, all of which of course also need to be checked for permissions.

There are a number of ways I could approach this. Having said that, the overhead of performing a few extra DB queries is pretty minor compared to Orchard's overhead in general and I'm thinking about sort of shape / display cache for an overall optimization which could be applied anywhere.

Developer
May 24, 2011 at 3:48 PM
Edited May 24, 2011 at 3:49 PM

Quick answer - yes. The module provides the generic functionality to tell whether given user is authorized to perform given action on a given content item. If not, the whole application acts like such item would not exist. So basically you are free to use it as a base for building a custom authorization scheme.

Small example of a scenario in which you can grant/deny access to display a given routable content item. We are inside some custom content handler:

...
OnAuthorized<RoutePart>((ctx, item) => {
    // We need to authorize only the process of building final display
    if(ctx.Location == ProcessingLocation.BuildDisplay)
    {
        // Do some custom checking, eg. for a role and such
        bool authorized = ShouldIGrantAccess(ctx.User, item);
        ctx.Authorized = authorized;
    }

}
...

And that is all. The ShouldIGrantAccess method is just for the example purposes, btw. If authorized is false the Content Manager would end up returning empty result (should be null, but had some issues with null values and shapes).

I'm thinking about adding a functionality to allow user to state (via the provided context object) whether he wants just not to display an item (silent way) or throw the security exception (verbose way) upon unsuccessfull authorization. Throwing an OrchardSecurityException can be needed sometimes, because it forces Orchard to return HttpUnauthorized result to the browser. One could also throw the OrchardSecurityException from the OnAuthorized method above, but that would implicitly stop processing all subsequent events from this and other content handlers.

May 24, 2011 at 3:48 PM

@bcronje - yes that's exactly it. There are actually several levels of security being discussed here;

- "Edit" permissions. These are already in core and very flexible. The forum example you mention is in part already supported by Orchard. It has "Edit" and "EditOwn" permissions for each content type, so you can configure it so a user can edit their own profile and an admin can edit anybody's (and you can further customize specific roles).

- "View" permissions. With the module pszmyd has written this will be applicable to content in a generic way. I'm not sure if he's including a per-content-type view permission (as per edit etc.), but it'd be easy to do, so you could also limit the User profile so it can only be viewed by registered users, which is the normal kind of behavior you see in forums.

- "Per-item" permissions. This is implemented by my Quanta module. It allows you to assign any users individual roles over specific content items. The obvious example for a Forum module would be assigning moderators to each sub-forum. With just Orchard and Quanta, this is already working for Edit/Delete permissions (as well as any custom permissions you define in your module) - but in addition to pszmyd's module, or with a resolution to the workitem he created, this can also apply to "View" permissions. I also support "Group" item roles. So you could mark individual sub-forums as "private" but then create special member groups that can view the forum. There are a lot of potential applications.

May 24, 2011 at 4:06 PM
pszmyd wrote:

... OnAuthorized<RoutePart>((ctx, item) => { // We need to authorize only the process of building final display if(ctx.Location == ProcessingLocation.BuildDisplay) { // Do some custom checking, eg. for a role and such bool authorized = ShouldIGrantAccess(ctx.User, item); ctx.Authorized = authorized; } } ...

And that is all. The ShouldIGrantAccess method is just for the example purposes, btw. If authorized is false the Content Manager would end up returning empty result (should be null, but had some issues with null values and shapes).

I'm thinking about adding a functionality to allow user to state (via the provided context object) whether he wants just not to display an item (silent way) or throw the security exception (verbose way) upon unsuccessfull authorization. Throwing an OrchardSecurityException can be needed sometimes, because it forces Orchard to return HttpUnauthorized result to the browser. One could also throw the OrchardSecurityException from the OnAuthorized method above, but that would implicitly stop processing all subsequent events from this and other content handlers.

That is awesome, I really like the way this opens up a broad spectrum of authorization schemes. pszmyd, what is your module's name so I can have a look in the Gallery for it?

 

May 24, 2011 at 4:06 PM
Edited May 24, 2011 at 4:08 PM

@randompete - That sounds good. When do you plan to release Quanta to Gallery?

Developer
May 24, 2011 at 4:09 PM
Edited May 24, 2011 at 4:09 PM

@randompete - I will publish it to Gallery and on Codeplex later today - have to add some finishing touches. I'll keep you posted.

May 24, 2011 at 4:29 PM

I like how this is shaping up and will be monitoring closely.

I too am building a website for an association using Orchard to replace our generic CMS. Currently, we throw up a login form if the user does not match up with the "Who can see" attribute, or the "Who can access" attribute.

May 24, 2011 at 4:37 PM

@BeyersCronje - definitely by the end of the week, hopefully sooner. I'm just working on a few things simultaneously and I don't want to publish until they're all functioning reasonable, because at that point the API will be reasonably stable.

May 24, 2011 at 9:00 PM
Edited May 24, 2011 at 9:01 PM

Wow, I'm amazed!!! Not only swift reply but also actual development work, almost completed in a day! This is beyond wildest dreams!

I will give it a try when the module is ready, but given my total lack of experience with CMS it might be looong try.

In case someone gets to prepare the walkthrough, the scenario is : define content (pages), navigation (buttons) and media folder (individual media files) which are only accessible to authenticated users. Will post here if I learn how to do it first - which is unlikely ;)

May 24, 2011 at 9:13 PM

@Bronek - to have media files fully participate in permissions checks, you'll also need Media Garden (which is another project of mine!)

Oct 26, 2011 at 5:10 PM

hi guys, it's been a while since any activity on this thread...

here is my situation, I have a custom module, where I am using a simple MVC app, so I am not really using handlers and drivers but my own controllers. 

I would like to keep this module in the authenticated mode, essentially because i need to persist the user's id to the DB when they use my forms. How can I implement this where I check if the user is logged on or not first, then get is userid and making it part of the model that I pass to the view?

I know i can create a menu item in the authenticated layer, but I aslo need to enforce it and get the users data when they hit my controller. 

Thanks for your help!

G

Coordinator
Oct 27, 2011 at 12:15 AM

You can get to the current user through the work context.

Oct 10, 2012 at 4:50 PM

Has the ability to show or hide links to media based on authentication status changed in the 18 since randompete's initial drop of Media Gardens?