views:

292

answers:

1

I've been using PrincipalPermission for a while in wcf services. [PrincipalPermission(SecurityAction.Demand, Role = SecurityRoles.CanManageUsers)]

although now i have a requirement to simplify roles by business unit. - currently aspnet_roles has fine grained can* permissions.

Here is my approach and wanted to see if anyone can provide feedback, code review before i implement my suggestion.

1) aspnet_roles - business unit role

2) create permission table and Role_Permission table and User_Permission table (many to many)

3) create custom CodeAccessSecurityAttribute + that looks at new tables [CustomPermissionCheck(Security.Demand, HasPermission="can*")] first iteration i'll statically new the dependent repository.. ideally i would like an aop style attribute that has repository injected IPermissionRepository.HasPermission(...);

If i approach new aop way i probably will stop inheriting from CodeAccessSecurityAttribute -- what do the security guys have to say about this?

has anyone else solved this, is there something in the framework that i've missed?

==========================

I implemented first iteration and it is working nicely. [PermissionValidate(SecurityAction.Demand, HasPermission = CensusSchedulerRoles.CanUpdateCensusScheduler)]

The only thing i do not like is the IPermissionRepository cannot be injected .. anyone have an example using policy block in entlib or using postsharp?

        public void Demand()
        {
            var principal = Thread.CurrentPrincipal;
            if(principal == null || principal.Identity.IsAuthenticated == false)
            {
                throw new SecurityException("Unable to get IPrincipal.");
            }
            if(principal.Identity.IsAuthenticated == false)
            {
                throw new SecurityException("You must be authenticated.");
            }

#warning this should be moved to an aop attribute that is injected by a ioc container.
            using (var connection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["......."].ConnectionString))
            {
                connection.Open();
                using(var command = new SqlCommand(
                @"
                    SELECT COUNT(t.name) FROM
                    (
                        SELECT p.name, u.UserName FROM 
                            aspnet_Users as u
                            INNER JOIN [User_Permission] as up
                                ON up.user_id = u.UserId
                            INNER JOIN Permission as p
                                ON p.id = up.permission_id
                        UNION
                        SELECT p2.name, u2.UserName FROM 
                            aspnet_Users as u2
                            INNER JOIN aspnet_UsersInRoles as uir
                                ON uir.UserId = u2.UserId
                            INNER JOIN aspnet_Roles as r
                                ON r.RoleId = uir.RoleId
                            INNER JOIN Role_Permission as rp
                                ON rp.role_id = r.RoleId
                            INNER JOIN Permission as p2
                                ON p2.id = rp.permission_id
                    ) as t
                    WHERE t.UserName = @username AND t.name = @haspermission
                ", connection))
                {
                    command.Parameters.Add("@username", SqlDbType.VarChar).Value = Thread.CurrentPrincipal.Identity.Name;
                    command.Parameters.Add("@haspermission", SqlDbType.VarChar).Value = _permissionRequested;

                    if( Convert.ToInt32(command.ExecuteScalar()) <=0)
                    {
                        throw new SecurityException(String.Format("User '{0}' is not assigned permission '{1}'.", principal.Identity.Name, _permissionRequested));
                    }
                }
            }
        }
A: 

I would say that if you are in ASP.NET, then you should implement a custom RoleProvider.

In your custom RoleProvider, you would access another table which would have the business groups linked to the fine grained permissions.

Then, when you find out the user, you can find out the business group that they are in and assign all of the appropriate roles in the RoleProvider and not change any of the existing code that you have.

It also works better, because it allows you to change what groups have what permissions easily, while keeping the domain model for permissions pure on the code side.

casperOne