oso-oso 0.25.1 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 82a8f9d2d54d8179e5a6067c929ec37ab0363250
4
- data.tar.gz: 28a9724e32230d89c3e6140ab3d914aa6e0bd798
3
+ metadata.gz: 9c6a70f052d3142dbaf1f8d9c699a7f3c6697060
4
+ data.tar.gz: 9820ca345e2b1bb85c31183a3f43a1748d412d77
5
5
  SHA512:
6
- metadata.gz: cd73f0a8bb0dd364229686d212c8b8cd56512ba9affee5dfd1a1f3b32b466cd793774121e2dd4425a708f7a35dd03bd35568d7097296fd568979cbfce77cffc8
7
- data.tar.gz: 60a6991495c8666c8cab642e82d0f11988b726d5911ecccd7aec079e5f3041dfb978e21181bd910dbde1b7e551aef29a0d05e901432f2a1a1789e0c9fd16c137
6
+ metadata.gz: '08cabc94530a44164fef27de25cac7477fc8906b6a4766197b003c4f629332ce4a24b88fc96e7fa78e305c23f0e16f0f5df5481bc7ffb82e5c51a9ffb7cd260c'
7
+ data.tar.gz: f534eec40e00a8c10dc9379843e8b08dc4bc95bd6526e4c00e0a88aaca11877b31bf643d82e934fe0b01ccdb1d957ae25c3fa069875e46ea7765634313bd43ec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oso-oso (0.25.1)
4
+ oso-oso (0.26.0)
5
5
  ffi (~> 1.0)
6
6
 
7
7
  GEM
Binary file
Binary file
Binary file
data/lib/oso/oso.rb CHANGED
@@ -182,16 +182,7 @@ module Oso
182
182
  #
183
183
  # @return A query for resources accessible to the actor.
184
184
  def authorized_query(actor, action, resource_cls)
185
- if host.use_new_data_filtering?
186
-
187
- unless host.types[resource_cls].build_query == ::Oso::Polar::Host::DEFAULT_BUILD_QUERY
188
- warn 'Warning: redundant data filtering configuration detected'
189
- end
190
-
191
- new_authorized_query(actor, action, resource_cls)
192
- else
193
- old_authorized_query(actor, action, resource_cls)
194
- end
185
+ new_authorized_query(actor, action, resource_cls)
195
186
  end
196
187
 
197
188
  # Determine the resources of type +resource_cls+ that +actor+
@@ -203,25 +194,7 @@ module Oso
203
194
  #
204
195
  # @return A list of resources accessible to the actor.
205
196
  def authorized_resources(actor, action, resource_cls)
206
- q = authorized_query(actor, action, resource_cls)
207
-
208
- if host.use_new_data_filtering?
209
- host.adapter.execute_query q
210
- elsif q.nil?
211
- []
212
- else
213
- host.types[resource_cls].exec_query[q]
214
- end
215
- end
216
-
217
- # Register default values for data filtering query functions.
218
- # These can be overridden by passing specific implementations to
219
- # `register_class` or by defining `build_query`, `exec_query` and
220
- # `combine_query` methods on the class object.
221
- def set_data_filtering_query_defaults(build_query: nil, exec_query: nil, combine_query: nil)
222
- host.build_query = build_query if build_query
223
- host.exec_query = exec_query if exec_query
224
- host.combine_query = combine_query if combine_query
197
+ host.adapter.execute_query authorized_query(actor, action, resource_cls)
225
198
  end
226
199
 
227
200
  def data_filtering_adapter=(adapter)
@@ -4,110 +4,6 @@ module Oso
4
4
  module Polar
5
5
  # Data filtering interface for Ruby
6
6
  module DataFiltering
7
- GETATTR = ->(x, attr) { attr.nil? ? x : x.send(attr) }
8
- # Represents a set of filter sequences that should allow the host
9
- # to obtain the records satisfying a query.
10
- class FilterPlan
11
- attr_reader :result_sets
12
-
13
- def self.parse(polar, partials, class_name)
14
- types = polar.host.serialize_types
15
- parsed_json = polar.ffi.build_filter_plan(types, partials, 'resource', class_name)
16
- result_sets = parsed_json['result_sets'].map do |rset|
17
- ResultSet.parse polar, rset
18
- end
19
-
20
- new polar: polar, result_sets: result_sets
21
- end
22
-
23
- def initialize(polar:, result_sets:)
24
- @polar = polar
25
- @result_sets = result_sets
26
- end
27
-
28
- def build_query # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
29
- combine = nil
30
- result_sets.each_with_object([]) do |rs, qb|
31
- rs.resolve_order.each_with_object({}) do |i, set_results|
32
- req = rs.requests[i]
33
- cs = req.ground(set_results)
34
- typ = @polar.host.types[req.class_tag]
35
- q = typ.build_query[cs]
36
- if i != rs.result_id
37
- set_results[i] = typ.exec_query[q]
38
- else
39
- combine = typ.combine_query
40
- qb.push q
41
- end
42
- end
43
- end.reduce(&combine)
44
- end
45
-
46
- # Represents a sequence of filters for one set of results
47
- class ResultSet
48
- attr_reader :requests, :resolve_order, :result_id
49
-
50
- def self.parse(polar, parsed_json)
51
- resolve_order = parsed_json['resolve_order']
52
- result_id = parsed_json['result_id']
53
- requests = parsed_json['requests'].each_with_object({}) do |req, reqs|
54
- reqs[req[0].to_i] = Request.parse(polar, req[1])
55
- end
56
-
57
- new resolve_order: resolve_order, result_id: result_id, requests: requests
58
- end
59
-
60
- def initialize(requests:, resolve_order:, result_id:)
61
- @resolve_order = resolve_order
62
- @requests = requests
63
- @result_id = result_id
64
- end
65
- end
66
-
67
- # Represents a filter for a result set
68
- class Request
69
- attr_reader :constraints, :class_tag
70
-
71
- def self.parse(polar, parsed_json)
72
- @polar = polar
73
- constraints = parsed_json['constraints'].map do |con|
74
- Filter.parse polar, con
75
- end
76
- class_tag = parsed_json['class_tag']
77
-
78
- new(constraints: constraints, class_tag: class_tag)
79
- end
80
-
81
- def ground(results) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
82
- xrefs, rest = constraints.partition do |c|
83
- c.value.is_a?(Ref) and !c.value.result_id.nil?
84
- end
85
-
86
- yrefs, nrefs = xrefs.partition { |r| %w[In Eq].include? r.kind }
87
- [[yrefs, 'In'], [nrefs, 'Nin']].each do |refs, kind|
88
- refs.group_by { |f| f.value.result_id }.each do |rid, fils|
89
- if fils.length > 1
90
- value = results[rid].map { |r| fils.map { |f| GETATTR[r, f.value.field] } }
91
- field = fils.map(&:field)
92
- rest.push(Filter.new(kind: kind, value: value, field: field))
93
- else
94
- fil = fils[0]
95
- field = fil.value.field
96
- value = results[rid].map { |r| field.nil? ? r : r.send(field) }
97
- rest.push(Filter.new(kind: kind, field: fil.field, value: value))
98
- end
99
- end
100
- end
101
- rest
102
- end
103
-
104
- def initialize(constraints:, class_tag:)
105
- @constraints = constraints
106
- @class_tag = class_tag
107
- end
108
- end
109
- end
110
-
111
7
  # Represents relationships between resources, eg. one-one or one-many
112
8
  class Relation
113
9
  attr_reader :kind, :other_type, :my_field, :other_field
@@ -124,92 +20,6 @@ module Oso
124
20
  @other_field = other_field
125
21
  end
126
22
  end
127
-
128
- # Represents field-field relationships on one resource.
129
- class Field
130
- attr_reader :field
131
-
132
- def initialize(field:)
133
- @field = field
134
- end
135
- end
136
-
137
- # Represents field-field relationships on different resources.
138
- class Ref
139
- attr_reader :field, :result_id
140
-
141
- def initialize(field:, result_id:)
142
- @field = field
143
- @result_id = result_id
144
- end
145
- end
146
-
147
- # Represents a condition that must hold on a resource.
148
- class Filter
149
- attr_reader :kind, :field, :value
150
-
151
- CHECKS = {
152
- 'Eq' => ->(a, b) { a == b },
153
- 'In' => ->(a, b) { b.include? a },
154
- 'Neq' => ->(a, b) { a != b },
155
- 'Nin' => ->(a, b) { !b.include?(a) },
156
- 'Contains' => ->(a, b) { a.include? b }
157
- }.freeze
158
-
159
- # Create a new predicate for data filtering.
160
- # @param kind [String] Represents a condition. One of "Eq", "Neq", "In", "Contains".
161
- # @param field The field the condition applies to.
162
- # @param value The value with which to compare the field according to the condition.
163
- def initialize(kind:, field:, value:)
164
- @kind = kind
165
- @field = field
166
- @value = value
167
- end
168
-
169
- def ground(results)
170
- return unless value.is_a? Ref
171
-
172
- ref = value
173
- @value = results[ref.result_id]
174
- @value = value.map { |v| v.send ref.field } unless ref.field.nil?
175
- end
176
-
177
- def check(item) # rubocop:disable Metrics/AbcSize
178
- val = value.is_a?(Field) ? item.send(value.field) : value
179
- item = if field.nil?
180
- item
181
- elsif field.is_a? Array
182
- field.map { |f| GETATTR[item, f] }
183
- else
184
- item.send field
185
- end
186
- CHECKS[@kind][item, val]
187
- end
188
-
189
- def self.parse(polar, constraint) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
190
- kind = constraint['kind']
191
- field = constraint['field']
192
- value = constraint['value']
193
-
194
- value_kind = value.keys.first
195
- value = value[value_kind]
196
-
197
- case value_kind
198
- when 'Term'
199
- value = polar.host.to_ruby value
200
- when 'Ref'
201
- child_field = value['field']
202
- result_id = value['result_id']
203
- value = Ref.new field: child_field, result_id: result_id
204
- when 'Field'
205
- value = Field.new field: value
206
- else
207
- raise "Unknown value kind `#{value_kind}`"
208
- end
209
-
210
- new kind: kind, field: field, value: value
211
- end
212
- end
213
23
  end
214
24
  end
215
25
  end
@@ -319,17 +319,24 @@ module Oso
319
319
  end
320
320
  else
321
321
  instance_id = nil
322
- instance_id = types[value].id if value.is_a?(Class) && types.key?(value)
323
-
324
- # only pass class_repr for registered types
322
+ class_id = nil
325
323
  class_repr = nil
326
- class_repr = value.class.to_s if types.key?(value.class)
324
+ # id=class_id,
325
+
326
+ # pass `class_id` & `class_repr` for registered types
327
+ if value.is_a?(Class) && types.key?(value)
328
+ instance_id = class_id = types[value].id
329
+ elsif types.key?(value.class)
330
+ class_id = types[value.class].id
331
+ class_repr = types[value.class].name
332
+ end
327
333
 
328
334
  {
329
335
  'ExternalInstance' => {
330
336
  'instance_id' => cache_instance(value, id: instance_id),
331
337
  'repr' => nil,
332
- 'class_repr' => class_repr
338
+ 'class_repr' => class_repr,
339
+ 'class_id' => class_id
333
340
  }
334
341
  }
335
342
  end
@@ -407,10 +414,6 @@ module Oso
407
414
  get_instance(Regexp.last_match[1].to_i).to_s
408
415
  end
409
416
  end
410
-
411
- def use_new_data_filtering?
412
- !adapter.nil?
413
- end
414
417
  end
415
418
  end
416
419
  end
@@ -217,6 +217,7 @@ module Oso
217
217
  exec_query: exec_query || maybe_mtd(cls, :exec_query)
218
218
  )
219
219
  register_constant(cls, name: name)
220
+ host.register_mros
220
221
  end
221
222
 
222
223
  # Register a Ruby object with Polar.
@@ -277,13 +278,6 @@ module Oso
277
278
  host.adapter.build_query filter
278
279
  end
279
280
 
280
- def old_authorized_query(actor, action, resource_cls)
281
- results = partial_query(actor, action, resource_cls)
282
- ::Oso::Polar::DataFiltering::FilterPlan
283
- .parse(self, results, class_to_name(resource_cls))
284
- .build_query
285
- end
286
-
287
281
  # handle Isa constraints in a partial query
288
282
  def prefilter_isas(key, val) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
289
283
  # this will usually be the case! sometimes not, if it's an instance.
@@ -343,7 +337,6 @@ module Oso
343
337
  # Register MROs, load Polar code, and check inline queries.
344
338
  # @param sources [Array<Source>] Polar sources to load.
345
339
  def load_sources(sources)
346
- host.register_mros
347
340
  ffi_polar.load(sources)
348
341
  check_inline_queries
349
342
  end
@@ -245,31 +245,22 @@ module Oso
245
245
  def handle_relationship(call_id, instance, rel) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
246
246
  typ = host.types[rel.other_type]
247
247
 
248
- if host.use_new_data_filtering?
249
- cls = typ.klass.get
250
-
251
- condition = ::Oso::Polar::Data::Filter::Condition.new(
252
- ::Oso::Polar::Data::Filter::Projection.new(cls, rel.other_field),
253
- 'Eq',
254
- instance.send(rel.my_field)
255
- )
256
-
257
- filter = ::Oso::Polar::Data::Filter.new(
258
- model: cls,
259
- relations: [],
260
- conditions: [[condition]],
261
- types: host.types
262
- )
263
-
264
- res = host.adapter.execute_query host.adapter.build_query(filter)
265
- else
266
- constraint = ::Oso::Polar::DataFiltering::Filter.new(
267
- kind: 'Eq',
268
- field: rel.other_field,
269
- value: instance.send(rel.my_field)
270
- )
271
- res = typ.exec_query[typ.build_query[[constraint]]]
272
- end
248
+ cls = typ.klass.get
249
+
250
+ condition = ::Oso::Polar::Data::Filter::Condition.new(
251
+ ::Oso::Polar::Data::Filter::Projection.new(cls, rel.other_field),
252
+ 'Eq',
253
+ instance.send(rel.my_field)
254
+ )
255
+
256
+ filter = ::Oso::Polar::Data::Filter.new(
257
+ model: cls,
258
+ relations: [],
259
+ conditions: [[condition]],
260
+ types: host.types
261
+ )
262
+
263
+ res = host.adapter.execute_query host.adapter.build_query(filter)
273
264
 
274
265
  if rel.kind == 'one'
275
266
  raise "multiple parents: #{res}" unless res.length == 1
data/lib/oso/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Oso
4
- VERSION = '0.25.1'
4
+ VERSION = '0.26.0'
5
5
  end
data/lib/oso.rb CHANGED
@@ -8,7 +8,6 @@ require 'oso/version'
8
8
  # Top-level namespace for Oso authorization library.
9
9
  module Oso
10
10
  Relation = ::Oso::Polar::DataFiltering::Relation
11
- Filter = ::Oso::Polar::DataFiltering::Filter
12
11
 
13
12
  def self.new(not_found_error: NotFoundError, forbidden_error: ForbiddenError, read_action: 'read')
14
13
  ::Oso::Oso.new(not_found_error: not_found_error, forbidden_error: forbidden_error, read_action: read_action)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oso-oso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.1
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oso Security, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-07 00:00:00.000000000 Z
11
+ date: 2022-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi