Class: Stytch::PolicyCache
- Inherits:
-
Object
- Object
- Stytch::PolicyCache
- Defined in:
- lib/stytch/rbac_local.rb
Instance Method Summary collapse
- #get_org_policy(organization_id:, invalidate: false) ⇒ Object
- #get_policy(invalidate: false) ⇒ Object
-
#initialize(rbac_client:) ⇒ PolicyCache
constructor
A new instance of PolicyCache.
-
#perform_authorization_check(subject_roles:, subject_org_id:, authorization_check:) ⇒ Object
Performs an authorization check against the project’s policy and a set of roles.
-
#perform_consumer_authorization_check(subject_roles:, authorization_check:) ⇒ Object
Performs an authorization check against the project’s policy and a set of roles.
-
#perform_scope_authorization_check(token_scopes:, authorization_check:) ⇒ Object
Performs an authorization check against the project’s policy and a set of scopes.
- #reload_org_policy(organization_id:) ⇒ Object
- #reload_policy ⇒ Object
Constructor Details
#initialize(rbac_client:) ⇒ PolicyCache
Returns a new instance of PolicyCache.
8 9 10 11 12 13 14 15 16 |
# File 'lib/stytch/rbac_local.rb', line 8 def initialize(rbac_client:) @rbac_client = rbac_client @policy_last_update = 0 @cached_policy = nil @cached_org_policies = {} # TTL, in seconds, before a cached policy is considered stale # and should be refreshed. Amounts to 5 minutes. @cache_ttl = 300 end |
Instance Method Details
#get_org_policy(organization_id:, invalidate: false) ⇒ Object
34 35 36 37 38 39 40 41 42 |
# File 'lib/stytch/rbac_local.rb', line 34 def get_org_policy(organization_id:, invalidate: false) is_missing = @cached_org_policies[organization_id].nil? is_stale = !is_missing && @cached_org_policies[organization_id].last_update < Time.now.to_i - @cache_ttl reload_org_policy(organization_id: organization_id) if invalidate || is_missing || is_stale return { 'roles' => [] } if @cached_org_policies[organization_id].nil? @cached_org_policies[organization_id].org_policy end |
#get_policy(invalidate: false) ⇒ Object
29 30 31 32 |
# File 'lib/stytch/rbac_local.rb', line 29 def get_policy(invalidate: false) reload_policy if invalidate || @cached_policy.nil? || @policy_last_update < Time.now.to_i - @cache_ttl @cached_policy end |
#perform_authorization_check(subject_roles:, subject_org_id:, authorization_check:) ⇒ Object
Performs an authorization check against the project’s policy and a set of roles. If the check succeeds, this method will return. If the check fails, a PermissionError will be raised. It’s also possible for a TenancyError to be raised if the subject_org_id does not match the authZ request organization_id. authorization_check is an object with keys ‘action’, ‘resource_id’, and ‘organization_id’
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/stytch/rbac_local.rb', line 49 def ( subject_roles:, subject_org_id:, authorization_check: ) raise Stytch::TenancyError.new(subject_org_id, ['organization_id']) if subject_org_id != ['organization_id'] policy = get_policy org_policy = get_org_policy(organization_id: subject_org_id) all_roles = policy['roles'].concat(org_policy['roles']) return if all_roles.any? do |role| next unless subject_roles.include?(role['role_id']) role['permissions'].any? do || actions = ['actions'] resource = ['resource_id'] has_matching_action = actions.include?('*') || actions.include?(['action']) has_matching_resource = resource == ['resource_id'] has_matching_action && has_matching_resource end end # If we get here, we didn't find a matching permission raise Stytch::PermissionError, end |
#perform_consumer_authorization_check(subject_roles:, authorization_check:) ⇒ Object
Performs an authorization check against the project’s policy and a set of roles. If the check succeeds, this method will return. If the check fails, a PermissionError will be raised. This is used for role based authorization.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/stytch/rbac_local.rb', line 79 def ( subject_roles:, authorization_check: ) policy = get_policy # For consumer authorization, we check roles without tenancy validation return if policy['roles'].any? do |role| next unless subject_roles.include?(role['role_id']) role['permissions'].any? do || actions = ['actions'] resource = ['resource_id'] has_matching_action = actions.include?('*') || actions.include?(['action']) has_matching_resource = resource == ['resource_id'] has_matching_action && has_matching_resource end end # If we get here, we didn't find a matching permission raise Stytch::PermissionError, end |
#perform_scope_authorization_check(token_scopes:, authorization_check:) ⇒ Object
Performs an authorization check against the project’s policy and a set of scopes. If the check succeeds, this method will return. If the check fails, a PermissionError will be raised. This is used for OAuth-style scope-based authorization. authorization_check is an object with keys ‘action’ and ‘resource_id’
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/stytch/rbac_local.rb', line 106 def ( token_scopes:, authorization_check: ) policy = get_policy # For scope-based authorization, we check if any of the token scopes match policy scopes # and if those scopes grant permission for the requested action/resource action = ['action'] resource_id = ['resource_id'] # Check if any of the token scopes grant permission for this action/resource return if policy['scopes'].any? do |scope_obj| scope_name = scope_obj['scope'] next unless token_scopes.include?(scope_name) # Check if this scope grants permission for the requested action/resource scope_obj['permissions'].any? do || actions = ['actions'] resource = ['resource_id'] has_matching_action = actions.include?('*') || actions.include?(action) has_matching_resource = resource == resource_id has_matching_action && has_matching_resource end end # If we get here, we didn't find a matching permission raise Stytch::PermissionError, end |
#reload_org_policy(organization_id:) ⇒ Object
23 24 25 26 27 |
# File 'lib/stytch/rbac_local.rb', line 23 def reload_org_policy(organization_id:) @cached_org_policies[organization_id] = CachedOrgPolicy.new( org_policy: @rbac_client.organizations.get_org_policy(organization_id: organization_id) ) end |
#reload_policy ⇒ Object
18 19 20 21 |
# File 'lib/stytch/rbac_local.rb', line 18 def reload_policy @cached_policy = @rbac_client.policy['policy'] @policy_last_update = Time.now.to_i end |