Lions and tigers and handling user capabilities

Lions and tigers and handling user capabilities

Many applications restrict access to some features for some users for various reasons. For example: Only premium users get access to extra features. Only supervisors can edit product categories. I went on a hunt to gather patterns and techniques for handling the logic around user capabilities in client-side apps. Join me on a safari through the approaches, and I’ll tell you what I have learned.

A video of this talk as given at Nordic.js can be viewed here:
https://www.youtube.com/watch?v=_CgYWacSTmQ

Note: the code snippets are optimized for readability. Don't copy and paste them ;)

7b1746f5ae99453e6a67f022ec0d73bd?s=128

Tiffany Conroy

September 19, 2014
Tweet

Transcript

  1. LIONS AND TIGERS AND HANDLING USER CAPABILITIES

  2. None
  3. HI, I’M TIFFANY @THEOPHANI

  4. LIONS AND TIGERS AND HANDLING USER CAPABILITIES

  5. (EXAMPLES)

  6. None
  7. ON A HUNT FOR WAYS TO APPROACH USER CAPABILITIES

  8. PART I THE UX OF USER CAPABILITIES PART II IMPLEMENTING

    USER CAPABILITIES
  9. PART I THE UX OF USER CAPABILITIES

  10. GOOD USER CAPABILITY UX HELPS PEOPLE TO 1. AVOID MISTAKES

    2. UNDERSTAND THEIR CAPABILITIES 3. EASILY MANAGE PERMISSIONS
  11. GOOD USER CAPABILITY UX HELPS PEOPLE TO 1. AVOID MISTAKES

  12. WHY ADD USER ACCESS RESTRICTIONS TO A SYSTEM ANYWAY?

  13. PEOPLE SHOULD NOT BE ABLE TO DO THINGS THAT THEY

    ARE NOT ALLOWED DO
  14. PEOPLE SHOULD NOT BE ABLE TO DO THINGS THAT THEY

    ARE NOT ALLOWED DO
  15. PEOPLE SHOULD NOT BE ABLE TO DO THINGS THAT THEY

    DO NOT NEED TO DO
  16. THIS IS KNOWN AS THE PRINCIPLE OF LEAST PRIVILEGE

  17. Following this principle limits the potential damage of any security

    breach, whether accidental or malicious.
  18. GOOD USER CAPABILITY UX HELPS PEOPLE TO 2. UNDERSTAND THEIR

    CAPABILITIES
  19. INTERACTION DESIGN ASKS HOW DOES THE USER: affect change? understand

    the change? understand what they can change?
  20. INTERACTION DESIGN ASKS HOW DOES THE USER: affect change? understand

    the change? → understand what they can change? ←
  21. YOUR UI MUST COMMUNICATE WHAT THE PERSON CAN DO

  22. YOUR UI MUST NOT COMMUNICATE THAT THE PERSON CAN DO

    SOMETHING THEY CAN’T
  23. GOOD USER CAPABILITY UX HELPS PEOPLE TO 3. EASILY MANAGE

    PERMISSIONS
  24. FIRST, SOME DEFINITIONS

  25. SUBJECT, OBJECT, OPERATION & PERMISSION, CAPABILITY

  26. SUBJECT: ACTIVE ENTITY, SUCH A USER OR A PROCESS.

  27. OBJECT: THING THE SUBJECT ACTS UPON.

  28. OPERATION: ACTION ATTEMPTED BY THE SUBJECT ON THE OBJECT.

  29. PERMISSION: THE RIGHT TO PERFORM THE OPERATION.

  30. CAPABILITY: ALLOWED OPERATION THE SUBJECT HAS PERMISSION TO PERFORM ON

    AN OBJECT.
  31. SUBJECT: PERSON OBJECT: THING OPERATION: ACTION PERMISSION: GIVES CAPABILITY TO

    A PERSON TO PERFORM AN ACTION ON A THING
  32. ACL , RBAC ACL: ACCESS CONTROL LIST RBAC: ROLE-BASED ACCESS

    CONTROL
  33. ACL ACCESS CONTROL LIST

  34. ACCESS CONTROL LIST

  35. THE UX OF MAINTAINING AN ACCESS CONTROL LIST

  36. None
  37. HOW DO YOU KNOW WHICH ACTIONS TO ALLOW ON WHICH

    THINGS?
  38. WHAT IF YOU NEEDED TO UPDATE SUCH A LIST?

  39. GROSS

  40. NOT GOOD UX

  41. PERMISSION GROUPS?

  42. ROLE-BASED ACCESS CONTROL TO THE RESCUE!

  43. RBAC ROLE-BASED ACCESS CONTROL

  44. ROLE: JOB FUNCTION IN AN ORGANIZATION

  45. ROLE: COLLECTION OF CAPABILITIES

  46. PEOPLE CAN HAVE MORE THAN ONE ROLE

  47. WHEN A ROLE IS CHANGED, PEOPLE’S CAPABILITIES CHANGE TOO

  48. ROLE-BASED ACCESS CONTROL or ACCESS CONTROL LISTS?

  49. BAD UX LEADS TO MISTAKES

  50. MISTAKES CAN LEAD TO VIOLATIONS OF THE PRINCIPLE OF LEAST

    PRIVILEGE
  51. ROLE-BASED ACCESS CONTROL is better UX than ACCESS CONTROL LISTS

  52. RECAP PART I

  53. GOOD USER CAPABILITY UX HELPS PEOPLE TO 1. AVOID MISTAKES

    2. UNDERSTAND THEIR CAPABILITIES 3. EASILY MANAGE PERMISSIONS
  54. 1. AVOID MISTAKES BY FOLLOWING THE PRINCIPLE OF LEAST PRIVILEGE

  55. PEOPLE SHOULD BE ABLE TO 2. UNDERSTAND THEIR CAPABILITIES BECAUSE

    YOUR IU COMMUNICATES THEM
  56. 3. EASILY MANAGE PERMISSIONS BY USING ROLE-BASED ACCESS CONTROL

  57. PART II IMPLEMENTING USER CAPABILITIES

  58. BUT FIRST, MY ASSUMPTIONS

  59. ▸ Client-side rendered apps, ▸ that use REST APIs to

    load and save data asynchronously, ▸ and the server can tell the client details about the authenticated user. (Though, same ideas can apply to server-side rendered views)
  60. IMPLEMENTATION CONSTRAINTS: 1. ONLY GRANT NECESSARY CAPABILITIES 2. UI MUST

    COMMUNICATE CAPABILITIES 3. USE ROLE-BASED ACCESS CONTROL
  61. 0. THE SERVER-SIDE MUST ENFORCE THE RESTRICTIONS

  62. THE SERVER-SIDE MUST ENFORCE THE RESTRICTIONS ← OR ELSE STUFF

    LIKE THIS IS POSSIBLE
  63. THE SERVER-SIDE MUST ENFORCE THE RESTRICTIONS, AND THE CLIENT-SIDE MUST

    REFLECT THE RESTRICTIONS
  64. // Don’t do this if ( "Junior Warehouse Clerk" in

    user.roles || "Warehouse Clerk" in user.roles || "Warehouse Manager" in user.roles ) { // Show "View Orders" button ... }
  65. // Do it like this! if ( "view orders" in

    user.capabilities ) { // Show "View Orders" button ... }
  66. $.ajax( url: "/_api/me/capabilities", success: function (response) { user.capabilities = response.capabilities

    } })
  67. // Checking for one capability if ( "view orders" in

    user.capabilities ) { // Show "View Orders" button ... }
  68. None
  69. // Checking for more than one capability if ( "view

    orders" in user.capabilities || "edit orders" in user.capabilities || "manage customers" in user.capabilities ) { // Show drop down menu icon ... }
  70. [ THIS KIND OF ] CAPABILITY CHECKING IS ADDITIVE

  71. can ( user, ["view orders"] ) // returns true if

    user can view orders can ( user, ["action one", "action two", "action three"] ) // returns true if the user can do any of the actions
  72. function can (user, requiredCapabilities) { return requiredCapabilities.some(function (capability) { return

    capability in user.capabilities }) }
  73. if ( can (user, ["do something"]) ) { // ...

    }
  74. if ( can (user, ["do action", "do another action"]) )

    { // ... }
  75. WHAT ABOUT “LOGIC-LESS” TEMPLATES?

  76. // in your view code mustache.render(template, { can: user.capabilities, //

    ... }) <!-- in your mustache template --> {{#can.viewOrders}} <a link=“/orders">View Orders</a> {{/can.viewOrders}}
  77. <nav> {{#can.viewOrders}} <a link="/orders">View Orders</a> {{/can.viewOrders}} {{#can.createOrders}} <a link="/orders/new">Add Order</a>

    {{/can.createOrders}} </nav>
  78. <!-- This doesn’t work --> {{#can.viewOrders}} {{#can.createOrders}} <nav> ... </nav>

    {{/can.createOrders}} {{/can.viewOrders}}
  79. // Augment capabilities with view-specific ones if ( can(user, ["view

    orders", "create orders"]) ) { user.capabilities.viewMenu = true; } mustache.render(template, { can: user.capabilities, // ... })
  80. {{#can.viewMenu}} <nav> ... </nav> {{/can.viewMenu}}

  81. <!-- Handlebar template containing a “can” block helper --> {{#can

    "viewOrders editOrder"}} <nav> ... </nav> {{/can}} // Define the block helper ... function canBlockHelper (requiredCapabilities, options) { // ... return hasSomeCapabilities ? options.fn(this) : "" } // ... and register it as “can” Handlebars.registerHelper("can", canBlockHelper);
  82. {{#can "viewOrders editOrder"}} <nav> {{#can "viewOrders"}} <a link="/orders">View Orders</a> {{/can}}

    {{#can "createOrders"}} <a link="/orders/new">Add Order</a> {{/can}} </nav> {{/can}}
  83. # Use the same kind of “can” per route server-side

    get "/_api/orders" can ( user, "view orders" ) do # ... end end post "/_api/orders" can ( user, "add orders" ) do # ... end end
  84. IN CONCLUSION …

  85. IMPLEMENTATION CONSTRAINTS: 1. ONLY GRANT NECESSARY CAPABILITIES 2. UI MUST

    COMMUNICATE CAPABILITIES 3. USE ROLE-BASED ACCESS CONTROL
  86. CONSIDER WHEN IMPLEMENTING: 1. ENFORCE IN BOTH SERVER AND CLIENT

    BUT MAKE THE SERVER THE AUTHORITY 2. CHECK AGAINST CAPABILITIES, NOT ROLES
  87. THANK YOU! TIFFANY CONROY – @THEOPHANI