3
\$\begingroup\$

I've been maintaining a Rbac helper for some time now. My goal is to provide an easy way to tell the following:

  • When does an user have a role
  • What can a user do (with those roles)
  • Which users have which role in which resources

And I'm pretty happy with my result so far, I can do the following:

var rbac = new RbacSession();
rbac.AddPermission("owner", "Delete");
rbac.UserIsInRoleIf("mantainer", u => u.Identity.Name == "Bob");
rbac.AddUserRoleForTypeIf<string>("Teacher", (user, resource) => resource == "Hello world");

I have been told to get rid of my fluent interface because all of it was wrong.

And my thought was, well yeah... But hey, wouldn't it be really cool if I could support properties to check if a user has a role? If I did I could also support easy binding to WPF Applications. Here follows the implementation

public class RbacPrincipal : IPrincipal, IIdentity
{
    [Browsable(false)]
    public class CanDoAction
    {
        private readonly RbacPrincipal _principal;
        public CanDoAction(RbacPrincipal principal)
        {
            _principal = principal;
        }

        public bool this[string action]
        {
            get
            {
                return _principal._session.Query.IsUserAbleTo(_principal, action);
            }
        }

        public bool this[string action, object resource]
        {
            get
            {
                return _principal._session.Query.IsUserAbleTo(_principal, action, resource);
            }
        }
    }

    [Browsable(false)]
    public class IsUserInRole
    {
        private readonly RbacPrincipal _principal;

        public IsUserInRole(RbacPrincipal principal)
        {
            _principal = principal;
        }

        public bool this[string role]
        {
            get
            {
                return _principal._session.Query.IsUserInRole(_principal, role);
            }
        }

        public bool this[string role, object resource]
        {
            get
            {
                return _principal._session.Query.IsUserInRole(_principal, role, resource);
            }
        }
    }

    private readonly IPrincipal _principal;
    private readonly IRbacSession _session;
    public RbacPrincipal(IPrincipal principal, IRbacSession session)
    {
        _principal = principal;
        _session = session;
        CanDo = new CanDoAction(this);
        Is = new IsUserInRole(this);
    }

    public bool IsInRole(string role)
    {
        //check role on the decorated principal se we avoid stackoverflow
        return _session.Query.IsUserInRole(_principal, role);
    }

    public CanDoAction CanDo { get; private set; }
    public IsUserInRole Is { get; private set; }

    IIdentity IPrincipal.Identity { get { return _principal.Identity; } }
    public string Name { get { return _principal.Identity.Name; } }
    public string AuthenticationType { get { return _principal.Identity.AuthenticationType; } }
    public bool IsAuthenticated { get { return _principal.Identity.IsAuthenticated; } }
}

And an example of the usage of it

var owner = new RbacPrincipal(new Principal
{
    Roles = { "owner", "member", "user" }
}, rbac);
Assert.IsTrue(owner.Is["owner"]);
Assert.IsTrue(owner.Is["member"]);
Assert.IsTrue(owner.CanDo["Delete"]);

I leave the link to full test class on repo here

Now I have one limitation if I use bindings with this. The resources cannot be anything but strings, but at least, and most important I can let you check a role of a user with a binding Is[owner].

Is this it? Did I finally reach the "yayness"?

\$\endgroup\$
2
  • \$\begingroup\$ I don't understand, why is the syntax owner.Is["owner"] instead of owner.Is("owner") or maybe even better owner.IsInRole("owner")? \$\endgroup\$
    – svick
    Commented Feb 27, 2016 at 18:51
  • \$\begingroup\$ @svick If it were a method it couldn't be binded, at least not without help from converters. And notice that I also support owner.IsInRole("owner") \$\endgroup\$ Commented Feb 27, 2016 at 19:57

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.