11

I'm using OAuth2.0 Owin (password grant) in my WebAPI.My initial token Response is like below

{
    "access_token": "_ramSlQYasdsRTWEWew.....................",
    "token_type": "bearer",
    "expires_in": 17999,
    "permissions": {
        "user": [
            "Add",
            "Update",
            "Delete"
        ],
        "Product": [
            "Read",
            "Create"
        ]
    }
}

I've customized the response by creating a new Key called permissions which hold the privileges for the corresponding user.

From here I need to validate each Request from my Resource server,by checking whether the user has enough permissions to call the API using Authorize Attribute.

I found a similar example from here where it deals with Dot net Core, which is not suitable for my case.

The difficult part is that the permission JSON Key is itself making a complex with ArrayList

[CustomAuthorize(PermissionItem.Product, PermissionAction.Read)]
    public async Task<IActionResult> Index()
    {
        return View(Index);
    }

public class CustomAuthorize : AuthorizeAttribute {
    public AuthorizeAttribute (PermissionItem item, PermissionAction action) {
        //Need to initalize the Permission Enums
    }
    public override void OnAuthorization (HttpActionContext actionContext) {
        //Code to get the value from Permissions ArrayList and compare it with the Enum values
    }
}

The above is the idea I'm having. But due to the complexity of the Permissions Key and Enum comparison I'm couldn't able to move forward.

Also, there is a question like If the permission for User is Add as well as Update means I need to create two Attribute conditions before my Controller.

Like

[CustomAuthorize(PermissionItem.User, PermissionAction.Add)]
[CustomAuthorize(PermissionItem.User, PermissionAction.Update)]

Which leads to adding more lines of Attributes. So Is there is any way to make it as in a single Conditions with | separated?

[CustomAuthorize(PermissionItem.User, PermissionAction.Update|PermissionAction.Add)]
Jayendran
  • 6,972
  • 4
  • 39
  • 80

3 Answers3

6

Why don't you allow your CustomAuthorize constructor to have multiple Permission actions.

public class CustomAuthorize : AuthorizeAttribute
{
    private readonly PermissionAction[] permissionActions;

    public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
    {
        this.permissionActions = permissionActions;
    }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        var currentIdentity = System.Threading.Thread.CurrentPrincipal.Identity;
        if (!currentIdentity.IsAuthenticated) {
            // redirect to access denied page
        }

        var userName = currentIdentity.Name;
        // step 1 : retrieve user object

        // step 2 : retrieve user permissions

        // step 3 : match user permission(s) agains class/method's required premissions

        // step 4 : continue/redirect to access denied page
    }
}

And you'll annotate your class with: [CustomAuthorize(PermissionItem.User, PermissionAction.Update, PermissionAction.Add)]

I'm not sure, what does OP want to achieve here. If you are relying on HTTP request to provide access rights then that is A BIG SECURITY HOLE. On each request you should retrieve user's access right information from the database and then match is against the required permission of the class/method.

As a rule of thumb you should not rely on request object to tell you what are the permissions that current user have. You should retrieve them from the datastore.

My Implementation of CustomAttribute

public class CustomAuthorize : System.Web.Http.AuthorizeAttribute
{
    private readonly PermissionAction[] permissionActions;

    public CustomAuthorize(PermissionItem item, params PermissionAction[] permissionActions)
    {
        this.permissionActions = permissionActions;
    }

    protected override Boolean IsAuthorized(HttpActionContext actionContext)
    {
        var currentIdentity = actionContext.RequestContext.Principal.Identity;
        if (!currentIdentity.IsAuthenticated)
            return false;

        var userName = currentIdentity.Name;
        using (var context = new DataContext())
        {
            var userStore = new UserStore<AppUser>(context);
            var userManager = new UserManager<AppUser>(userStore);
            var user = userManager.FindByName(userName);

            if (user == null)
                return false;

            foreach (var role in permissionActions)
                if (!userManager.IsInRole(user.Id, Convert.ToString(role)))
                    return false;

            return true;
        }
    }
}
Dipen Shah
  • 23,609
  • 1
  • 21
  • 48
  • I need the actual logic part to do the comparison for the Permissions Enum with the Permission ArrayList. – Jayendran Aug 01 '18 at 05:15
  • I'm getting the user's access rights from Database only. Could you please explain the Step 3 in detail. I need the actual logic for that – Jayendran Aug 01 '18 at 05:45
1

You could make us of flags and binary operations to allow you to | the different operations together.

The following code shows a small example of how it could be done

class Program {
    static void Main(string[] args) {
        Test test = new Test();
        CustomAuthorizeAttribute customAuthorizeAttribute = (CustomAuthorizeAttribute)Attribute.GetCustomAttribute(typeof(Test), typeof(CustomAuthorizeAttribute));

        customAuthorizeAttribute.Test();

        Console.ReadKey();
    }
}

[CustomAuthorize(PermissionActions = PermissionAction.Add | PermissionAction.Delete)]
public class Test {

}

public class CustomAuthorizeAttribute : Attribute {
    public PermissionAction PermissionActions { get; set; }

    public void Test() {
        if ((PermissionActions & PermissionAction.Add) == PermissionAction.Add) Console.WriteLine("Add");
        if ((PermissionActions & PermissionAction.Delete) == PermissionAction.Delete) Console.WriteLine("Delete");
        if ((PermissionActions & PermissionAction.Update) == PermissionAction.Update) Console.WriteLine("Update");
    }
}

public enum PermissionAction {
    Add = 1,
    Update = 2,
    Delete = 4
}

Which yields the following output

enter image description here

3dd
  • 2,460
  • 11
  • 20
1

We have created below API filter for authentication.

Here, "SecretToken", "MerchantKey" this two key passing in API request. we are validating this two from database using "IsValidMerchant" function.

IsValidMerchant this function direct connect with database table where respective value are store

public void OnAuthorization(AuthorizationFilterContext actionContext)
{
  const string secretTokenName = "SecretToken";
  const string merchentKeyName = "MerchantKey";
  bool isValid = false;

  if (!actionContext.Filters.Any(item => item is IAllowAnonymousFilter))
    {
     CPServiceResponse response = new CPServiceResponse();
     var secretToken = actionContext.HttpContext.Request.Headers[secretTokenName].FirstOrDefault();
     var merchentKey = actionContext.HttpContext.Request.Headers[merchentKeyName].FirstOrDefault();

      isValid = this.IsValidMerchant(merchentKey, secretToken,_productCode);

       if (isValid == false)
        {
          response.Status = (int)HttpStatusCode.Unauthorized;
          response.Message = Hegic.Shared.Resource.Common.UnauthorizedRequestError;
          actionContext.Result = new JsonResult("")
                {
                    Value = new { Status = response }
                };
         }
      }
  }
Parth Akbari
  • 641
  • 7
  • 22