Custom Authorization

I have JWT tokens working well now with custom User Session working nicely.

For us now, we want to Authorize the method call according to the AccountId contained in the request objects. e.g. If you are requesting objects for company A (request), you yourself must be from company A.(session)

Currently I am doing this as follows:

    public object Any(GetObjects request)
    {

        if (Authorize(request)){
            using (var db = DbFactory.Open())
            {

                CheckTableExistsAndInitialize<Object>(db);

                var response = db.LoadSelect<Object>()
                    .Where(x => x.AccountID == request.AccountID);
                return response.ToList<Object>();
            }
        }
        else
        {
            return null;
        }

    }

With the Authorize call using reflection in a service class, to check jwt session accountid against request accountid as:

    public bool Authorize(Object msg)
    {
        try
        {
            var session = (GetSession() as CustomSession);
            bool validAccount = false;

            // If Request contains AccountId then Return Authorized if AccountId matches Request Object.
            if ((msg != null) && (msg.GetType().GetProperty("AccountID") != null))
            {
                
                if (session != null)
                {
                    var guid = new Guid(session.AccountID);
                    var account = (Guid)msg.GetType().GetProperty("AccountID")?.GetValue(msg);
                    validAccount = (guid == account);
                }
            }

            // Return True if Role is SysAdmin.
            if (validAccount || session.Roles.Contains("SysAdmin"))
            {
                return true;
            }
        }
        catch (Exception ex)
        {

        }

What I really want however is to do it like:

    [Authenticate HasRole("SysAdmin") || HasAccount(request)]
    public object Any(GetObjects request)
    {

            using (var db = DbFactory.Open())
            {

                CheckTableExistsAndInitialize<Object>(db);

                var response = db.LoadSelect<Object>()
                    .Where(x => x.AccountID == request.AccountID);
                return response.ToList<Object>();
            }
        }
    }

The above obviously does not work yet as the request is not in scope yet,
Is there a way I can achieve this in this way or at a higher message handler level ?

C# attributes are static so you’re limited to using constants and literals.

The easiest solution would be if you assigned users with accounts an Account role then you could use the [RequiresAnyRole] attribute, e.g:.

[RequiresAnyRole("SysAdmin","Account")]
public object Any(GetObjects request) => ...;

Which ensures the user is Authenticated and has either the SysAdmin or Account role.

Otherwise you’d need to implement your own custom Request Filter Attribute. Have a look at the implementation of RequiresAnyRoleAttribute.cs for an example.

Hi Mythz, thanks for the quick response. This doesn’t quite do what I need as I want to prevent a user from company A from accessing data from company B

That is why I want to compare AccountId properties to check that the company requests is the same as the session company. Is there any way I could handle this e.g. with a global message filter before it enters the rest of the pipeline ?

You can use a Global Request Filter to add custom validation for each Service request or custom Request Filter Attribute to apply validation adhoc using attributes.

1 Like

Thanks, I’ll give the Request Attribute Filter a try. Will let you know

That works thanks, appreciate the guidance!

1 Like