Pro Yearly is on sale from $80 to $50! »

[RubyRussia 2019] Welcome, or access denied

52cc8a838bf44a589d2572833b2dd1b9?s=47 Vlad Dem
September 28, 2019

[RubyRussia 2019] Welcome, or access denied

Video (RU): https://www.youtube.com/watch?v=y15a2g7v8i0

Popular Ruby frameworks bring us a lot of useful tools out-of-the-box, but there are missing parts too.
For example, for such essential task as authorization we are on our own.
The variety of open source solutions comes with the problem of choice—there is no silver bullet.

Nevertheless, it's possible to extract common patterns of designing authorization systems and define common technical problems, such as:
performance, code maintainability and testability, integration with client-side applications.

This talk aims to shed light on both theoretical and practical problems: from different authorization models to useful code techniques I came up with while working
on the Action Policy framework (https://actionpolicy.evilmartians.io) .

52cc8a838bf44a589d2572833b2dd1b9?s=128

Vlad Dem

September 28, 2019
Tweet

Transcript

  1. WELCOME Vladimir Dementyev or access denied?

  2. AUTHORIZATION авторизация povolení autorització 認可 упълномощаване Genehmigung овлашћење авторлык аўтарызацыя

    дозвіл танылған autoryzacja !"#$%&'!(&!
  3. AUTHORIZATION or naming is hard palkan_tula palkan 3

  4. I’M USING DEVISE FOR AUTHORIZATION!

  5. palkan_tula palkan AUTHORIZATION Who’s there? 5 AUTHENTICATION ТУК-ТУК! КТО ТАМ?

    * — Knock-knock! — Who’s there?
  6. palkan_tula palkan Am I allowed to do that? 6 AUTHORIZATION

  7. HELLO

  8. palkan_tula palkan VLADIMIR DEMENTYEV 8 " Brooklyn # Moscow $

  9. palkan_tula palkan 9

  10. None
  11. palkan_tula palkan evl.ms/blog 11

  12. palkan_tula palkan 12 @palkan @palkan_tula Vladimir Dementyev 1.1k 836 456

    650
  13. RailsClub 2017

  14. THE TALK

  15. LINES OF DEFENSE or what else authorization is not palkan_tula

    palkan 15 * lost in translation
  16. palkan_tula palkan 16 authentication authorization constraints validations LINES OF DEFENSE

  17. palkan_tula palkan AUTHORIZATION Is system allows to do that? 17

    SYSTEM CONSTRAINTS ПО ПОМЫТОМУ НЕ ХОДИТЬ! * No step on washed floor
  18. palkan_tula palkan BY EXAMPLE 18 class ReposController < AppController def

    create if current_account.available_repos.zero? head :payment_required end # ... end end constraint check
  19. palkan_tula palkan AUTHORIZATION 19 Authorization model How to grant/revoke access?

    (roles, permission, accesses) Authorization layer How to verify access? (policies, rules, helpers)
  20. palkan_tula palkan AUTHORIZATION 20 Model Layer

  21. FORMAL MODELS palkan_tula palkan 21 Authorization Models DAC MAC RBAC

  22. palkan_tula palkan ?AC 22 ? User Resource Access Control

  23. palkan_tula palkan DAC 23 Discretionary Permission 1 0,* 0,* 1

    User Resource
  24. palkan_tula palkan DAC 24 Discretionary # => granting permissions @stove.permissions.create!(user:

    @vovka, activity: :cook) # => checking permissions @stove.permissions.exists?(user: @vovka, activity: :cook)
  25. palkan_tula palkan DAC 25 Discretionary Permission 0,* 0,* UserGroup Resource

    1 1
  26. palkan_tula palkan MAC 26 User Resource Mandatory Top Secret Confidential

    Unclassified
  27. palkan_tula palkan MAC 27 Mandatory # => checking permissions @report.security_level

    <= @colleague.security_clearance # => MUST have security level >= user clearance @colleague.reports.create!(params)
  28. palkan_tula palkan MAC 28 Bell & LaPadula (Multi-level security) Chinese

    Wall http://www.cs.cornell.edu/courses/cs5430/2015sp/notes/mac.php
  29. palkan_tula palkan RBAC 29 Role-based Role 0, * 0,* User

    Resource PrivilegeA PrivilegeB
  30. palkan_tula palkan RBAC https://github.com/the-teacher/the_role 30

  31. palkan_tula palkan ABAC 31 Attribute-based Policy User Resource attributes attributes

    Context
  32. palkan_tula palkan 32 ABAC Attribute-based class Ability def initialize(user) can

    :sleep, Bed, user_id: user.id end end class BedPolicy def sleep? bed.user_id == user.id end end
  33. palkan_tula palkan 33 <xacml3:Rule RuleId="c01d7519-be21-4985-88d8-10941f44590a" Effect="Permit"> <xacml3:Description>Allow if time between

    9 and 5 </xacml3:Description> <xacml3:Target> <xacml3:AnyOf> <xacml3:AllOf> <xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:time-greater-than"> <xacml3:AttributeValue DataType="http: // www.w3.org/2001/XMLSchema#time">09:00:00 </xacml3:AttributeValue> <xacml3:AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" AttributeId="urn:oasis:names:tc:xacml:1.0:environment:current-time" MustBePresent="false" DataType="http: // www.w3.org/2001/XMLSchema#time" /> </xacml3:Match> </xacml3:AllOf> </xacml3:AnyOf> <xacml3:AnyOf> <xacml3:AllOf> <xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:time-less-than"> <xacml3:AttributeValue DataType="http: // www.w3.org/2001/XMLSchema#time">17:00:00 </xacml3:AttributeValue> <xacml3:AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment" AttributeId="urn:oasis:names:tc:xacml:1.0:environment:current-time" MustBePresent="false" DataType="http: // www.w3.org/2001/XMLSchema#time" /> </xacml3:Match> </xacml3:AllOf> </xacml3:AnyOf> </xacml3:Target> </xacml3:Rule> XACML eXtensible Access Control Markup Language
  34. palkan_tula palkan 34 namespace exampleBoolean { policy article{ target clause

    userRole == “editor" and actionId == "edit" and itemType == "article" apply firstApplicable rule publishedArticles { target clause published == true permit } } } ALFA (XACML) Abbreviated Language For Authorization
  35. palkan_tula palkan 35 [ { "resource": “TaleApp ::Bed", "action": ["sleep"],

    "description": "Allow owners to sleep in their beds”, "effect": "allow", "conditions": [ { "equal": { "resource ::owner ::id": ["user ::id"] } } ] } ] https://github.com/TheClimateCorporation/iron_hide ABAC Attribute-based
  36. WHICH MODEL TO CHOOSE?

  37. palkan_tula palkan IN REAL LIFE 37 RBAC MAC DAC ABAC

  38. palkan_tula palkan class CoursePolicy < ApplicationPolicy def show? user.permissions.view_courses? &&

    (record.account_id == user.account_id) && ( record.owner_id == user.id || record.visibility_level <= user.visibility || user.assigned_courses.where(id: record.id).exists? ) end end IN REAL LIFE 38
  39. palkan_tula palkan class CoursePolicy < ApplicationPolicy def show? user.permissions.view_courses? &&

    (record.account_id == user.account_id) && ( record.owner_id == user.id || record.visibility_level <= user.visibility || user.assigned_courses.where(id: record.id).exists? ) end end IN REAL LIFE 39 RBAC
  40. palkan_tula palkan class CoursePolicy < ApplicationPolicy def show? user.permissions.view_courses? &&

    (record.account_id == user.account_id) && ( record.owner_id == user.id || record.visibility_level <= user.visibility || user.assigned_courses.where(id: record.id).exists? ) end end IN REAL LIFE 40 ABAC
  41. palkan_tula palkan class CoursePolicy < ApplicationPolicy def show? user.permissions.view_courses? &&

    (record.account_id == user.account_id) && ( record.owner_id == user.id || record.visibility_level <= user.visibility || user.assigned_courses.where(id: record.id).exists? ) end end IN REAL LIFE 41 MAC
  42. palkan_tula palkan class CoursePolicy < ApplicationPolicy def show? user.permissions.view_courses? &&

    (record.account_id == user.account_id) && ( record.owner_id == user.id || record.visibility_level <= user.visibility || user.assigned_courses.where(id: record.id).exists? ) end end IN REAL LIFE 42 DAC
  43. palkan_tula palkan AUTHORIZATION MODEL 43 Could not be generalized well

    Should reflects your business domain rules => No “right tool for the job”
  44. palkan_tula palkan AUTHORIZATION 44 Authorization model How to grant/revoke access?

    (roles, permission, accesses) Authorization layer How to verify access? (policies, rules, helpers) ✅
  45. palkan_tula palkan AUTHORIZATION LAYER 45

  46. palkan_tula palkan AUTHORIZATION LAYER 46 Controllers (Rails), Actions (Hanami) Views

    (templates, serializers) Channels (Action Cable) GraphQL mutations and types
  47. palkan_tula palkan LAYER: PROBLEMS 47 performance ? backend -> frontend

    maintainability ? ?
  48. SOLUTIONS and their problems palkan_tula palkan 48

  49. AUTHORIZATION eaco SimonSays action_policy the_role cancancan pundit kan moat declarative_authorization

    access-granted six consul
  50. palkan_tula palkan CANCAN(-CAN) 50 class Ability include CanCan ::Ability def

    user_abilities can :create, [Question, Answer] can :update, [Question, Answer], user_id: user.id can :destroy, [Question, Answer], user_id: user.id can :destroy, Attachment, attachable: { user_id: user.id } can [:vote_up, :vote_down], [Question, Answer] do |resource| resource.user_id != user.id end end end
  51. palkan_tula palkan 51 Ability

  52. palkan_tula palkan PUNDIT 52 class QuestionPolicy def index? true end

    def create? true end def update? user.admin? || (user.id == target.user_id) end end
  53. palkan_tula palkan PUNDIT 53 ls -r app/policies class RolePolicy <

    ApplicationPolicy end
  54. palkan_tula palkan THE EVOLUTION 54 Start with CanCan Migrate to

    Pundit Customize Pundit Customize Pundit…
  55. palkan_tula palkan THE EVOLUTION 55 Start with CanCan Migrate to

    Pundit Write your own framework
  56. palkan_tula palkan THE EVOLUTION 56 Start with CanCan Migrate to

    Pundit Write your own framework — Kan
  57. palkan_tula palkan THE EVOLUTION 57 Start with CanCan Migrate to

    Pundit Write your own framework — Action Policy
  58. gem "action_policy"

  59. palkan_tula palkan RAILSCONF 2018 http://bit.ly/action-policy-rc2018 59

  60. palkan_tula palkan class ProductsController < ApplicationController before_action :load_product, except: [:index,

    :new, :create] def load_product @product = current_account.products.find(params[:id]) # auto-infer policy and rule authorize! @product # explicit rule and policy authorize! @product, to: :manage?, with: SpecialProductPolicy end end ACTION POLICY 60
  61. palkan_tula palkan class ProductPolicy < ApplicationPolicy relation_scope do |rel| next

    rel if user.manager? rel.where(owner_id: user.id) end def create? user.manager? end def show? record.account_id == user.account_id end end ACTION POLICY 61
  62. palkan_tula palkan IT’S PUNDIT, ISN’T IT? 62

  63. palkan_tula palkan Action Policy has flexible architecture 63

  64. palkan_tula palkan SEATTLERB 2019 http://bit.ly/action-policy-2019 64

  65. palkan_tula palkan LAYER: PROBLEMS 65 performance ? backend -> frontend

    maintainability ? ?
  66. palkan_tula palkan 66 performance ? LAYER: PROBLEMS

  67. palkan_tula palkan PERFORMANCE 67 “Heavy” rules N+1 authorization

  68. palkan_tula palkan “HEAVY” RULES 68 Complex SQL queries External API

    calls (e.g., external authorization service)
  69. HOW TO FIND BOTTLENECKS?

  70. palkan_tula palkan INSTRUMENTATION 70 Instrument policy checks (both raising and

    non-raising) Instrument authorize! calls separately => Detect missing checks, monitor high “Access denied” rate, etc.
  71. palkan_tula palkan N+1 AUTHORIZATION 71 14 Mar 2018 14:08:30.722241 <190>1

    2018-03-14T11:08:30.349156+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] Started GET "/test_account/openings/public-funnel/dashboard" for 185.13.112.107 at 2018-03-14 11:08:30 +0000 14 Mar 2018 14:08:30.722186 <190>1 2018-03-14T11:08:30.358367+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] Processing by DashboardsController#show as HTML 14 Mar 2018 14:08:30.722216 <190>1 2018-03-14T11:08:30.358391+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] Parameters: {"account_slug"=>"test_account", "opening_id"=>"public-funnel"} 14 Mar 2018 14:08:30.722174 <190>1 2018-03-14T11:08:30.368142+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.scope.hit=0ms 14 Mar 2018 14:08:30.722175 <190>1 2018-03-14T11:08:30.399348+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.scope.miss=6ms 14 Mar 2018 14:08:30.722176 <190>1 2018-03-14T11:08:30.407044+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.scope.miss=21ms 14 Mar 2018 14:08:30.722174 <190>1 2018-03-14T11:08:30.441693+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.scope.hit=0ms 14 Mar 2018 14:08:30.722175 <190>1 2018-03-14T11:08:30.471756+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.miss=2ms 14 Mar 2018 14:08:30.722174 <190>1 2018-03-14T11:08:30.474080+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:30.722175 <190>1 2018-03-14T11:08:30.504566+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.miss=1ms 14 Mar 2018 14:08:30.722175 <190>1 2018-03-14T11:08:30.505893+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.miss=1ms 14 Mar 2018 14:08:30.722175 <190>1 2018-03-14T11:08:30.507222+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.miss=1ms 14 Mar 2018 14:08:30.722175 <190>1 2018-03-14T11:08:30.508522+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.miss=1ms 14 Mar 2018 14:08:30.722175 <190>1 2018-03-14T11:08:30.509846+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.miss=1ms 14 Mar 2018 14:08:30.722175 <190>1 2018-03-14T11:08:30.511189+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.miss=1ms 14 Mar 2018 14:08:30.796175 <190>1 2018-03-14T11:08:30.512857+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.miss=1ms 14 Mar 2018 14:08:30.796174 <190>1 2018-03-14T11:08:30.523828+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:30.796174 <190>1 2018-03-14T11:08:30.527719+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:30.796174 <190>1 2018-03-14T11:08:30.529970+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:30.928734+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.039388+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.040101+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.137807+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.138677+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.139952+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.140577+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.141658+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.142342+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.143228+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.143837+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.144657+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.145339+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.146206+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.146852+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.147671+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.148303+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.149119+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.149849+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.150702+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.151359+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.152254+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.152879+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.153761+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.295174 <190>1 2018-03-14T11:08:31.154353+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.370174 <190>1 2018-03-14T11:08:31.155193+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.370174 <190>1 2018-03-14T11:08:31.155826+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.370174 <190>1 2018-03-14T11:08:31.156625+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 14 Mar 2018 14:08:31.370174 <190>1 2018-03-14T11:08:31.157286+00:00 app web.1 - - [1bb8d912-308a-4966-b436-a407ef34bac2] [U#6] measure#action_policy.check.hit=0ms 45 policy checks per request
  72. palkan_tula palkan 72 N+1 AUTHORIZATION <% @course.materials.each do |material| %>

    <li><%= material.title %> <% if allowed_to?(:edit?, @course) %> = link_to "Edit", material <% end %> </li> <% end %>
  73. palkan_tula palkan BETTER PERFORMANCE 73 Use cache Use cache Use

    cache
  74. palkan_tula palkan 74 ACTION POLICY: CACHE LAYERS

  75. palkan_tula palkan CACHE 75

  76. palkan_tula palkan PERFORMANCE 76 How to measure? — Instrumentation How

    to fix? — Cache
  77. palkan_tula palkan 77 maintainability ? LAYER: PROBLEMS

  78. palkan_tula palkan MAINTAINABILITY 78 Boilerplate Testability Debuggability

  79. palkan_tula palkan MAINTAINABILITY 79 Boilerplate Testability Debuggability See previous talks

  80. TESTABILITY or effective authorization testing palkan_tula palkan 80 *slap s**t

    together and deploy
  81. 100% COVERAGE

  82. 100% BUSINESS LOGIC COVERAGE

  83. HOW TO TEST

  84. palkan_tula palkan THE SURVEY 84 % of answers 0 17.5

    35 52.5 70 requests/controllers tests unit tests (e.g. policy tests) system tests other Where do you test authorization logic?
  85. palkan_tula palkan IN REAL LIFE 85 describe "GET #index" do

    subject { get :index, params: {account_id: account.id} } include_examples "account access" include_examples "permission access", "view_reports" end Testing in controllers
  86. palkan_tula palkan 86 55% 45% Authorization Other Testing in controllers

    IN REAL LIFE ⛔
  87. palkan_tula palkan AUTHORIZATION TESTS 87 Test that the required authorization

    has been performed — just one test!
  88. palkan_tula palkan 88 describe "GET #index" do subject { get

    :index, params: {account_slug: account.slug} } it "is authorized" do policy = instance_double(ApplicantPolicy, index ?: false) expect(ApplicantPolicy).to receive(:new) .with(user, Applicant) { policy } expect { subject } .to raise_error Pundit ::NotAuthorizedError end end PUNDIT
  89. palkan_tula palkan 89 describe "GET #index" do subject { get

    :index, params: {account_slug: account.slug} } it "is authorized" do expect { subject } .to be_authorized_to(:index?).with(ApplicantPolicy) end end ACTION POLICY
  90. palkan_tula palkan AUTHORIZATION TESTS 90 Test that the required authorization

    has been performed — just one test! Test that the required scoping has been applied
  91. palkan_tula palkan ACTION POLICY 91 @posts = authorized_scope(Post.all) expect {

    subject }.to have_authorized_scope(:relation) .with_policy(PostPolicy) .with_target { |target| expect(target).to eq(Post.all) }
  92. palkan_tula palkan AUTHORIZATION TESTS 92 Test that the required authorization

    has been performed — just one test! Test that the required scoping has been applied Test authorization rules (policy classes) separately
  93. binding.pry

  94. DEBUGGABILITY or why does it fail? palkan_tula palkan 94

  95. palkan_tula palkan 95 def rsvp? rsvp_opened? && show? && (seats_available?

    || rsvp_to_pack?) end EXAMPLE Why can this check fail?
  96. palkan_tula palkan 96 def rsvp? binding.irb rsvp_opened? && show? &&

    (seats_available? || rsvp_to_pack?) end EXAMPLE Why can this check fail? MAYBE BREAK?
  97. palkan_tula palkan 97 EXAMPLE Typical debugging session

  98. palkan_tula palkan 98 EXAMPLE Debugging with Action Policy

  99. palkan_tula palkan DEBUGGABILITY 99 Debugging PORO is much easier than

    debugging DSL Provide debugging helpers => make developers happier
  100. palkan_tula palkan 100 backend -> frontend ? LAYER: PROBLEMS

  101. palkan_tula palkan BACKEND VS FRONTEND 101 How to share permissions?

    How to “raise” actionable errors?
  102. REIMPLEMENT RULES IN JAVASCRIPT!

  103. NO TALK CAN AVOID GRAPHQL

  104. palkan_tula palkan GRAPHQL CASE 104 class EventPolicy < ApplicationPolicy def

    rsvp? # checks end end One rule to render the button
  105. palkan_tula palkan GRAPHQL CASE 105 class EventPolicy < ApplicationPolicy def

    rsvp? check?(:no_rsvp_manager?) && check?(:rsvp_opened?) && show? && check?(:seats_available?) && allowed_to?(:rsvp_to_pack?) end end different reasons => different messages
  106. FAILURE REASONS or “Not authorized” is not enough palkan_tula palkan

    106
  107. palkan_tula palkan REASONS 107 Provide information on why action is

    not allowed Allow generate actionable/meaningful errors
  108. palkan_tula palkan 108 class ApplicantPolicy < ApplicationPolicy def show? allowed_to?(:view?)

    && allowed_to?(:show?, stage) end def view? user.has_permission?(:view_applicants) end end Wrap nested checks to track their results ACTION POLICY: REASONS
  109. palkan_tula palkan 109 # in controller rescue_from ActionPolicy ::Unauthorized do

    |ex| # either p exception.reasons.details # => { stage: [:show?] } # or p exception.reasons.details # => { applicant: [:view?] } end ACTION POLICY: REASONS
  110. palkan_tula palkan PERMISSIONS API 110

  111. palkan_tula palkan GRAPHQL CASE 111

  112. gem "action_policy-graphql"

  113. palkan_tula palkan 113 https://evl.ms/blog/exposing-permissions-in-graphql-apis-with-action-policy ACTION_POLICY-GRAPHQL

  114. palkan_tula palkan 114 Never expose authorization model Expose activity permissions

    (canDoSmth) via API BACKEND VS FRONTEND
  115. palkan_tula palkan 115 true/false is not enough Provide human-readable feedback

    Provide machine-readable details BACKEND VS FRONTEND
  116. AUTHORIZATION IS… palkan_tula palkan 116

  117. palkan_tula palkan AUTHORIZATION IS… 117 …as simple as adding ability.rb

  118. palkan_tula palkan AUTHORIZATION IS… 118 …a critical part of your

    application requiring special attention …a model you need to choose or design yourself …a mechanism to enforce the policies (authorization layer)
  119. palkan_tula palkan AUTHORIZATION 119 Authorization model — Use your brain

    Authorization layer — Use Action Policy
  120. СПАСИБО! Vladimir Dementyev @evilmartians evilmartians.com @palkan @palkan_tula