Class: Oso::Oso

Inherits:
Polar::Polar show all
Defined in:
lib/oso/oso.rb

Overview

oso authorization API.

Instance Attribute Summary

Attributes inherited from Polar::Polar

#host

Instance Method Summary collapse

Methods inherited from Polar::Polar

#clear_rules, #ffi, #load_file, #load_files, #load_str, #name_to_class, #query, #query_rule, #query_rule_once, #register_class, #register_constant, #repl

Constructor Details

#initialize(not_found_error: NotFoundError, forbidden_error: ForbiddenError, read_action: 'read') ⇒ Oso

Create an Oso instance, which is used to configure and enforce an Oso policy in an app.

Parameters:

  • forbidden_error (Class) (defaults to: ForbiddenError)

    Optionally override the “forbidden” error class thrown by the `authorize*` methods. Defaults to ForbiddenError.

  • not_found_error (Class) (defaults to: NotFoundError)

    Optionally override the “not found” error class thrown by #authorize. Defaults to NotFoundError.

  • read_action (defaults to: 'read')

    The action used by the #authorize method to determine whether an authorization failure should raise a NotFoundError or a ForbiddenError



20
21
22
23
24
25
# File 'lib/oso/oso.rb', line 20

def initialize(not_found_error: NotFoundError, forbidden_error: ForbiddenError, read_action: 'read')
  super()
  @not_found_error = not_found_error
  @forbidden_error = forbidden_error
  @read_action = read_action
end

Instance Method Details

#allowed?(actor:, action:, resource:) ⇒ Boolean

Query the knowledge base to determine whether an actor is allowed to perform an action upon a resource.

Parameters:

  • actor (Object)

    Subject.

  • action (Object)

    Verb.

  • resource (Object)

    Object.

Returns:

  • (Boolean)

    An access control decision.



34
35
36
# File 'lib/oso/oso.rb', line 34

def allowed?(actor:, action:, resource:)
  query_rule_once('allow', actor, action, resource)
end

#authorize(actor, action, resource, check_read: true) ⇒ Object

Ensure that actor is allowed to perform action on resource.

If the action is permitted with an allow rule in the policy, then this method returns None. If the action is not permitted by the policy, this method will raise an error.

The error raised by this method depends on whether the actor can perform the “read” action on the resource. If they cannot read the resource, then a NotFoundError error is raised. Otherwise, a ForbiddenError is raised.

Parameters:

  • actor

    The actor performing the request.

  • action

    The action the actor is attempting to perform.

  • resource

    The resource being accessed.

  • check_read (Boolean) (defaults to: true)

    If set to false, a ForbiddenError is always thrown on authorization failures, regardless of whether the actor can read the resource. Default is true.

Raises:

  • (Oso::ForbiddenError)

    Raised if the actor does not have permission to perform this action on this resource, but does have “read” permission on the resource.

  • (Oso::NotFoundError)

    Raised if the actor does not have permission to perform this action on this resource and additionally does not have permission to “read” the resource.



63
64
65
66
67
68
69
70
71
# File 'lib/oso/oso.rb', line 63

def authorize(actor, action, resource, check_read: true)
  return if query_rule_once('allow', actor, action, resource)

  if check_read && (action == @read_action || !query_rule_once('allow', actor, @read_action, resource))
    raise @not_found_error
  end

  raise @forbidden_error
end

#authorize_field(actor, action, resource, field) ⇒ Object

Ensure that actor is allowed to perform action on a given resource's field.

If the action is permitted by an allow_field rule in the policy, then this method returns nothing. If the action is not permitted by the policy, this method will raise a ForbiddenError.

Parameters:

  • actor

    The actor performing the request.

  • action

    The action the actor is attempting to perform on the field.

  • resource

    The resource being accessed.

  • field

    The name of the field being accessed.

Raises:



106
107
108
# File 'lib/oso/oso.rb', line 106

def authorize_field(actor, action, resource, field)
  raise @forbidden_error unless query_rule_once('allow_field', actor, action, resource, field)
end

#authorize_request(actor, request) ⇒ Object

Ensure that actor is allowed to send request to the server.

Checks the allow_request rule of a policy.

If the request is permitted with an allow_request rule in the policy, then this method returns nothing. Otherwise, this method raises a ForbiddenError.

Parameters:

  • actor

    The actor performing the request.

  • request

    An object representing the request that was sent by the actor.

Raises:



87
88
89
# File 'lib/oso/oso.rb', line 87

def authorize_request(actor, request)
  raise @forbidden_error unless query_rule_once('allow_request', actor, request)
end

#authorized_actions(actor, resource, allow_wildcard: false) ⇒ Object

Determine the actions actor is allowed to take on resource.

Collects all actions allowed by allow rules in the Polar policy for the given combination of actor and resource.

Parameters:

  • actor

    The actor for whom to collect allowed actions

  • resource

    The resource being accessed

  • allow_wildcard (defaults to: false)

    Flag to determine behavior if the policy includes a wildcard action. E.g., a rule allowing any action: allow(_actor, _action, _resource). If true, the method will return Set, if false, the method will raise an exception.

Returns:

  • A set of the unique allowed actions.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/oso/oso.rb', line 122

def authorized_actions(actor, resource, allow_wildcard: false) # rubocop:disable Metrics/MethodLength
  results = query_rule('allow', actor, Polar::Variable.new('action'), resource)
  actions = Set.new
  results.each do |result|
    action = result['action']
    if action.is_a?(Polar::Variable)
      return Set['*'] if allow_wildcard

      raise ::Oso::Error,
            'The result of authorized_actions() contained an '\
            '"unconstrained" action that could represent any '\
            'action, but allow_wildcard was set to False. To fix, '\
            'set allow_wildcard to True and compare with the "*" '\
            'string.'
    end
    actions.add(action)
  end
  actions
end

#authorized_fields(actor, action, resource, allow_wildcard: false) ⇒ Object

Determine the fields of resource on which actor is allowed to perform action.

Uses allow_field rules in the policy to find all allowed fields.

Parameters:

  • actor

    The actor for whom to collect allowed fields.

  • action

    The action being taken on the field.

  • resource

    The resource being accessed.

  • allow_wildcard (defaults to: false)

    Flag to determine behavior if the policy \ includes a wildcard field. E.g., a rule allowing any field: \ allow_field(_actor, _action, _resource, _field). If true, the \ method will return Set, if false, the method will raise an \ exception.

Returns:

  • A set of the unique allowed fields.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/oso/oso.rb', line 156

def authorized_fields(actor, action, resource, allow_wildcard: false) # rubocop:disable Metrics/MethodLength
  results = query_rule('allow_field', actor, action, resource, Polar::Variable.new('field'))
  fields = Set.new
  results.each do |result|
    field = result['field']
    if field.is_a?(Polar::Variable)
      return Set['*'] if allow_wildcard

      raise ::Oso::Error,
            'The result of authorized_fields() contained an '\
            '"unconstrained" field that could represent any '\
            'field, but allow_wildcard was set to False. To fix, '\
            'set allow_wildcard to True and compare with the "*" '\
            'string.'
    end
    fields.add(field)
  end
  fields
end

#authorized_query(actor, action, resource_cls) ⇒ Object

Create a query for resources of type cls that actor is allowed to perform action on.

Parameters:

  • actor

    The actor whose permissions to check.

  • action

    The action being taken on the resource.

  • resource_cls

    The resource being accessed.

Returns:

  • A query for resources accessible to the actor.



184
185
186
# File 'lib/oso/oso.rb', line 184

def authorized_query(actor, action, resource_cls)
  new_authorized_query(actor, action, resource_cls)
end

#authorized_resources(actor, action, resource_cls) ⇒ Object

Determine the resources of type resource_cls that actor is allowed to perform action on.

Parameters:

  • actor

    The actor whose permissions to check.

  • action

    The action being taken on the resource.

  • resource_cls

    The resource being accessed.

Returns:

  • A list of resources accessible to the actor.



196
197
198
# File 'lib/oso/oso.rb', line 196

def authorized_resources(actor, action, resource_cls)
  host.adapter.execute_query authorized_query(actor, action, resource_cls)
end

#data_filtering_adapter=(adapter) ⇒ Object



200
201
202
# File 'lib/oso/oso.rb', line 200

def data_filtering_adapter=(adapter)
  host.adapter = adapter
end