Rhino.Security in progress....

May 29, 2010 at 9:06 PM
Edited May 30, 2010 at 11:19 PM

I have forked Jon's project, and pushed my initial adds. http://github.com/kujotx/Who-Can-Help-Me. The branch is called rhinosecurity. It is a VS2010 based solution.

There's still more to do, but I thought I'd post the progress.

Kurt

EDITED: Remove pre-github-move project.

May 29, 2010 at 9:10 PM
Edited May 30, 2010 at 11:15 PM

** DELETED **  edited above

Jun 28, 2010 at 6:35 PM

Hi kujotx,

I was wondering what was the status of your rhinosecurity project. Are you still planning to work on the project?

Thanks,

fromano2802

Jun 28, 2010 at 7:22 PM

Sorry about the progress. Meatspace demands are limiting my work lately.

I had placed an initial commit on http://github.com/kujotx/Who-Can-Help-Me under the rhinosecurity branch. You can check it out to see my progress to date.

It is very raw at present, and I haven't been in side-project mode for the usual reasons. The project was derived from Jon's VS2010 branch in mid-May. I haven't rebased since.

So far I have...

Added database tables for the security tables.

Added contracts and abstract classes to DOmain[sic] (note the unfortunate typo -- how do I resolve that in git?!)

Added Infrastructure concrete implementations, which I may have to refactor to another location.


Still need to :

Need to get the DOmain typo resolved.

Create initial Security entities and operations. Involves inserting records into initial data load.

Determine where and how to secure WhoCanHelpMe. We can do simple page authorization -- like, the user must possess "/Page/Profile/Edit" or somesuch, otherwise they received a UnauthorizedResult (an ActionResult in Error.cs in *.Web)

I am going to get back on the horse...

Let me know if you have any ideas on what you want secured.. Right now, I am thinking that page security might be quickest and easiest.

Jun 28, 2010 at 7:58 PM

Hi kujotx,

I already downloaded and went through your code in github. Correct me if I am wrong, but I was thinking to implement some sort of authorization similar to what Bart Reyserhove did with his winecellar tutorial. http://bartreyserhove.blogspot.com/2008/10/integrate-rhino-security-with-aspnet.html

Let me know what you think. 

Jun 28, 2010 at 9:33 PM

Oh, yeah -- I know what you're talking about there. I am very familiar with Bart's work, as I used that to understand Rhino.

I think Jon's work in this area is all we need (see his Forms branch) -- this functionality only requires that a login/pass is authenticated against a user with a hashed password -- our table will have all of this. Let me take a look and see if a rebase with Jon's latest work for Forms can be readily included. If not, I will include my wrapper and views.

 

Jun 29, 2010 at 2:02 PM
That's great! Thank you fore the work you are doing.
Jul 2, 2010 at 1:44 PM
Edited Jul 2, 2010 at 1:47 PM

Hi kujotx,

Are you planning on injecting the various rhino security components into the Task classes? If so, is there a problem with having the Rhino security services and repositories registered as Transient but the various tasks are registered as singleton. If you DI a IPermissionsService or IAuthorizationRepository object into the ProfileTask class constructor, will you get unexpected results?

Thanks
Dan

Jul 2, 2010 at 2:24 PM

My tasks only have interfaces of repositories that inherit from a custom ISecuredRepository<T>, where T is a SecurableEntity. ISecuredRepository currently inherits from ILinqRepository.

This enables you to keep the AuthorizationService on GetAll(), Delete() and Save(). All of my gets call the secured GetAll, so they all have security attached. I get the current user for IAuthorizationService via an ISecurityContext.User. Operations are standardized so that you have predictable /[Entity]/[Operation] dependent on the CRUD operation.

Per your lifestyle remark, yes! I did encounter problems with the various Lifestyles. All of my Registrars had to have a Lifestyle of transient. The differing lifestyles reaked havoc on Sessions in Rhino.Security. Once all of my interfaces were made transient, Rhino was able to use my factory method correctly to get the current session.

 

Jul 2, 2010 at 5:02 PM
Edited Jul 2, 2010 at 5:03 PM

Yes, it was how rhino was using sessions that tripped me up also.

I can't find a ISecuredRepository<T>, is this class not in your demo project yet or are you refering to another interface?

Thanks, and I appreciate your work on the demo project.
Dan

Jul 7, 2010 at 1:55 PM

I made a commit on Jul 5. And it is up on my rhinosecurity branch in my fork.

I have chosen to next work on enable FormsAuthentications using Rhino.Security with global/page level authorizations.

Entity security is the area where Rhino.Security really excels, but it would require me to make decisions on which domain entities require security from un-authorized users. The entity-level security model doesn't seem applicable to the application of WCHM.

 

Jul 8, 2010 at 2:58 PM
Edited Jul 8, 2010 at 2:59 PM

Yes, I guess that is a problem with WCHM. The domain is somewhat limited making it difficult to hang more complex concepts like security on to the few existing entities and processes. I'm not even sure where you could implement page level authorizations, are you going to authorize viewing the About page to only administrators?

I did find that the SecurityRepository class is not in sync with the ISecurityRepository interface. Several methods were renamed; names containing UsersGroup were change to Role, and Entities to Membership.

Just so I'm following you, the ISecuredRepository<T> interface defines properties for other security components like SecurableEntityService (ISecurableEntityService), which in turn have access to the Rhino.Security components like ISecurityRepository (getting around the LifeStyle.Transient problem by fetching a new instance from the ServiceLocator), or the ISecuredRepository<T> itself might have access to a Rhino.Security component, like IAuthorizationService so it can use the AddPersmissionToQuery method.

Does this mean that you maintain most of the security rules in the repositories that implement ISecuredRepository<T> instead of else where, like in the Tasks layer?

Thanks
Dan

Jul 9, 2010 at 5:05 PM
djs wrote:

Yes, I guess that is a problem with WCHM. The domain is somewhat limited making it difficult to hang more complex concepts like security on to the few existing entities and processes. I'm not even sure where you could implement page level authorizations, are you going to authorize viewing the About page to only administrators?

I did find that the SecurityRepository class is not in sync with the ISecurityRepository interface. Several methods were renamed; names containing UsersGroup were change to Role, and Entities to Membership.

Just so I'm following you, the ISecuredRepository<T> interface defines properties for other security components like SecurableEntityService (ISecurableEntityService), which in turn have access to the Rhino.Security components like ISecurityRepository (getting around the LifeStyle.Transient problem by fetching a new instance from the ServiceLocator), or the ISecuredRepository<T> itself might have access to a Rhino.Security component, like IAuthorizationService so it can use the AddPersmissionToQuery method.

Does this mean that you maintain most of the security rules in the repositories that implement ISecuredRepository<T> instead of else where, like in the Tasks layer?

Thanks
Dan

Yes, I guess that is a problem with WCHM. The domain is somewhat limited making it difficult to hang more complex concepts like security on to the few existing entities and processes. I'm not even sure where you could implement page level authorizations, are you going to authorize viewing the About page to only administrators?

Actually, page level authorizations can be relatively simple with a custom authorization attribute that checks for a Rhino.Security permission, and a standardized operation name like "/Page/Home/About".

I did find that the SecurityRepository class is not in sync with the ISecurityRepository interface. Several methods were renamed; names containing UsersGroup were change to Role, and Entities to Membership.

Yeah, I finally got ReSharper (temporarily under a trial license) for my home machine and located that naming problem. I had to familiarize myself with the git workflow -- my fork graph will attest to this. The Rhino.Security language -- and not my "Role" and "Membership" interpretation -- should be the go-forward UL for this concern -- mea culpa. I didn't like Ayende's domain at the time. I got over it. Changes to come.

Just so I'm following you, the ISecuredRepository<T> interface defines properties for other security components like SecurableEntityService (ISecurableEntityService), which in turn have access to the Rhino.Security components like ISecurityRepository (getting around the LifeStyle.Transient problem by fetching a new instance from the ServiceLocator), or the ISecuredRepository<T> itself might have access to a Rhino.Security component, like IAuthorizationService so it can use the AddPersmissionToQuery method.

SecurityRepository is nothing more than a facade for Rhino.Security entities. If I need to get a UsersGroup, EntitiesGroup, etc. I go here. SecurableEntityService is a service for making sure that securable entities have the requisite Rhino.Security requirements met -- security key, belong to a global entitiesgroup for browseability by a superuser, etc. The SecurableEntityService is simply there to maintain those Security relationships on any update.

There is also ISecuredRepository<T> coming in the next push. This is the repository where the AddPermissionsToQuery is automatically applied to the CRUD base operations of FindAll(), Save() and Delete(). You will notice that T is of type SecurableEntity. That's the abstract class that fulfills all of Rhino.Security's requirements that an entity must have to be securable. This repository inherits from ILinqRepository..

Does this mean that you maintain most of the security rules in the repositories that implement ISecuredRepository<T> instead of else where, like in the Tasks layer?

I think you are asking if I am adding AddPermissionToQuery() for filtering in the Task layer or in the repository. Having to filter every secured entity in the Tasks appears to be a DRY violation. I thought it best to include that in a common repository. 

The other problem is creating your security data, which is what you could mean. For another project, I made a console app for creating security configuration data -- all the UsersGroups, and EntitiesGroups, Operations, Permissions for groups, etc. I could implement a console for inserting our data here, and move the current insert SQL into that console. If we wanted to actually have entity-level security, this would be the course of action.

It appears that, for now, we can do with simply creating UserGroups manually in SQL, creating relationships to our users, and granting permissions to page level authorizations.

 

Jul 10, 2010 at 6:12 PM
Edited Jul 10, 2010 at 6:13 PM
kujotx wrote:
Actually, page level authorizations can be relatively simple with a custom authorization attribute that checks for a Rhino.Security permission, and a standardized operation name like "/Page/Home/About".

I'm not referring to the mechanics of how Rhino Security works, yes it is very simple to setup an operation for a page and lock it down by user or user group, it is just that there are very few pages in WCHM and very few entities in the domain.  This makes it a bit difficult to implement a security model that approaches the complexity of real world security needs.  Yes it can be done just to demonstrate the technique, but really what possible use case or security need is there to locking down the About page?

Thanks for the clarification on SecurityRepository and ISecuredRepository<T>.  As for the security rules I'm thinking more about the business domain. Again it is hard to discuss in the context of WCHM because of its limited domain model, but to take an example from a Human Resources application;  If I am a Manager for a work group I may be able to use the HR system to see the salary data for one of my subordinates, but I can't give that person a raise, as that would need to be done by the Department Supervisor or a Payroll Administrator.  This would require that the employee entity needs to be in the right "workgroup" entity group and that my user identity entity is a member of the user group that has permission to read (but not edit) the employee's salary.  Of course the Dept Super and Payroll Admin need to have user groups and permissions and entity groups setup in a way so they can have permission to edit an employee's salary.

 

Jul 20, 2010 at 8:22 PM
kujotx wrote:

The other problem is creating your security data, which is what you could mean. For another project, I made a console app for creating security configuration data -- all the UsersGroups, and EntitiesGroups, Operations, Permissions for groups, etc. I could implement a console for inserting our data here, and move the current insert SQL into that console. If we wanted to actually have entity-level security, this would be the course of action.

It appears that, for now, we can do with simply creating UserGroups manually in SQL, creating relationships to our users, and granting permissions to page level authorizations.

 

FYI, there is a new project on github for managing rhino.security users, groups, permissions, etc.

http://github.com/nexida/Rhino-Security-Administration

Regards
Dan

Aug 12, 2010 at 4:41 PM
Edited Aug 12, 2010 at 7:06 PM
Hi Kujotx, when do you think you will push the next realease of your project? I am interested to see how you implement and use the ISecuredRepository<T> in the Tasks. I tried to use the SecurityRepository at Tasks level, but I am having some problems. When I try to create a UsersGroup using the CreateRole method it says: No persister for: Rhino.Security.Model.UsersGroup. Am I missing something? Here's my code:
using System.Collections.Generic;
using Rhino.Commons;
using Rhino.Security.Interfaces;
using WhoCanHelpMe.Domain.Contracts.Repositories;
using WhoCanHelpMe.Domain.Contracts.Security;
using WhoCanHelpMe.Domain.Contracts.Services;

namespace WhoCanHelpMe.Tasks
{
public class SecurityTasks : ISecurityTasks
{
private ISecurityRepository securityRepository;

public SecurityTasks(ISecurityRepository securityRepository)
{
this.securityRepository = securityRepository;
}
public void Generate(IList<string> operations)
{

{
var userGroup = securityRepository.GetRole("developers");
if (userGroup == null)
{
userGroup = securityRepository.CreateRole("developers"); <-- it fails at line 37 in SecurityRepository.cs
}

foreach (var operation in operations)
{
if (securityRepository.GetOperation(operation) != null) continue;

securityRepository.CreateOperation(operation, "Comment");
}

}
}
}
}
Hope you can help, PPB
Aug 13, 2010 at 2:14 PM
Anyone can help?