oso-cloud 0.2.0 → 0.4.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
  SHA256:
3
- metadata.gz: f79239f03cdcaddbb6a8c9800b4c83a5d28b4acccd3cae2875a9585306c1531e
4
- data.tar.gz: 59764d372207e4beda482bddf6f4489573a640d61ba9d064d2644931ffe6dde0
3
+ metadata.gz: ae0bc3e70a6d9ea8aeb9f6f02af64afa1ca65099ea036d75d2a611bed86e3f83
4
+ data.tar.gz: d46f670990a2ffff708c3a72d54f9bed2da6602e8699d3ffab3108d18750851a
5
5
  SHA512:
6
- metadata.gz: f68bf249055cf164b296a945a3149e0b4328f6da4843105b9455c9e864dd87d7b25374cb8cc2d3c76f971368b9944bd72784e15f36564ba5f9ed89ca538f955e
7
- data.tar.gz: be9850f671f35bc24f64061b9975e92aba2c66d5c6ce9c4b33bbf2027c4e4cba7b7e62bef2f82d1057b1ed15763022d51d32d8200397629050145e271520bc45
6
+ metadata.gz: 118581772825e045e4f1237a43d8d8077fef30c2f8118d9886ab5d3bbfdbdfa1de383216b2426520a0aee0e0b61239a0153c177cac48de874b4832fac87b50a3
7
+ data.tar.gz: 6a66ab888f95a43e64ae69e3d8e9c378077da17d5dd580185b25b77371c532bb2ec169df9cdd6781cf0f43b11a68ded664d26ed9efff0d877f9019e75967a2aa
data/.gitignore CHANGED
@@ -1,3 +1,2 @@
1
- Gemfile.lock
2
1
  .bundle
3
2
  vendor
data/Gemfile.lock ADDED
@@ -0,0 +1,21 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ oso-cloud (0.4.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ minitest (5.15.0)
10
+ rake (12.3.3)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ minitest (~> 5.15)
17
+ oso-cloud!
18
+ rake (~> 12.0)
19
+
20
+ BUNDLED WITH
21
+ 2.3.13
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
data/lib/oso/client.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'json'
2
- require 'logger'
3
2
  require 'net/http'
4
3
  require 'uri'
5
4
 
@@ -7,103 +6,117 @@ require 'oso/version'
7
6
 
8
7
  module Oso
9
8
  class Client
10
- def initialize(url: 'https://cloud.osohq.com', api_key: nil, logger: nil)
9
+ def initialize(url: 'https://cloud.osohq.com', api_key: nil)
11
10
  @url = url
12
11
  @api_key = api_key
13
- @logger = logger || Logger.new(STDOUT)
14
- # TODO: why does this need to be configurable?
15
- # @to_type_and_id = method(default_to_type_and_id)
12
+ end
13
+
14
+ def policy(policy)
15
+ POST('policy', { src: policy })
16
16
  end
17
17
 
18
18
  def authorize(actor, action, resource)
19
- actor_type, actor_id = default_to_type_and_id actor
20
- resource_type, resource_id = default_to_type_and_id resource
21
- result = post('authorize', {
22
- actor_type: actor_type, actor_id: actor_id,
23
- action: action,
24
- resource_type: resource_type, resource_id: resource_id
25
- })
19
+ actor_typed_id = extract_typed_id actor
20
+ resource_typed_id = extract_typed_id resource
21
+ result = POST('authorize', {
22
+ actor_type: actor_typed_id.type, actor_id: actor_typed_id.id,
23
+ action: action,
24
+ resource_type: resource_typed_id.type, resource_id: resource_typed_id.id
25
+ })
26
26
  allowed = result['allowed']
27
- @logger.debug { "AUTHORIZING (#{actor}, #{action}, #{resource}) => ALLOWED? = #{allowed ? 'true' : 'false'} " }
28
-
29
27
  allowed
30
28
  end
31
29
 
32
30
  def list(actor, action, resource_type)
33
- actor_type, actor_id = default_to_type_and_id actor
34
- result = post('list',
35
- {
36
- actor_type: actor_type, actor_id: actor_id,
37
- action: action,
38
- resource_type: resource_type
39
- })
31
+ actor_typed_id = extract_typed_id actor
32
+ result = POST('list', {
33
+ actor_type: actor_typed_id.type, actor_id: actor_typed_id.id,
34
+ action: action,
35
+ resource_type: resource_type,
36
+ })
40
37
  results = result['results']
41
- @logger.debug { "AUTHORIZING (#{actor}, #{action}, #{resource_type}). RESULTS: #{results}" }
42
-
43
38
  results
44
39
  end
45
40
 
46
- def add_role(actor, role_name, resource)
47
- add_role_or_relation('role', resource, role_name, actor)
41
+ def tell(predicate, *args)
42
+ typed_args = args.map { |a| extract_typed_id a}
43
+ POST('facts', { predicate: predicate, args: typed_args })
48
44
  end
49
45
 
50
- def delete_role(actor, role_name, resource)
51
- delete_role_or_relation('role', resource, role_name, actor)
46
+ def bulk_tell(facts)
47
+ params = facts.map { |predicate, *args|
48
+ typed_args = args.map { |a| extract_typed_id a}
49
+ { predicate: predicate, args: typed_args }
50
+ }
51
+ POST('bulk_load', params)
52
52
  end
53
53
 
54
- def add_relation(subject, name, object)
55
- add_role_or_relation('relation', subject, name, object)
54
+ def delete(predicate, *args)
55
+ typed_args = args.map { |a| extract_typed_id a}
56
+ DELETE('facts', { predicate: predicate, args: typed_args })
56
57
  end
57
58
 
58
- def delete_relation(subject, name, object)
59
- delete_role_or_relation('relation', subject, name, object)
59
+ def bulk_delete(facts)
60
+ params = facts.map { |predicate, *args|
61
+ typed_args = args.map { |a| extract_typed_id a}
62
+ { predicate: predicate, args: typed_args }
63
+ }
64
+ POST('bulk_delete', params)
60
65
  end
61
66
 
62
- def get_roles(resource: nil, role: nil, actor: nil)
63
- params = {}
64
- unless actor.nil?
65
- actor_type, actor_id = default_to_type_and_id actor
66
- params[:actor_type] = actor_type
67
- params[:actor_id] = actor_id
68
- end
69
- unless resource.nil?
70
- resource_type, resource_id = default_to_type_and_id resource
71
- params[:resource_type] = resource_type
72
- params[:resource_id] = resource_id
67
+ def get(predicate, *args)
68
+ params = {predicate: predicate}
69
+ args.each_with_index do |arg, i|
70
+ typed_id = extract_arg_query(arg)
71
+ if typed_id
72
+ params["args.#{i}.type"] = typed_id.type
73
+ params["args.#{i}.id"] = typed_id.id
74
+ end
73
75
  end
74
- params[:role] = role unless role.nil?
75
76
 
76
- get('roles')
77
+ GET('facts', params)
77
78
  end
78
79
 
79
80
  private
80
81
 
81
- def auth()
82
- {"Authorization" => "Basic %s" % @api_key}
82
+ def headers()
83
+ {
84
+ "Authorization" => "Basic %s" % @api_key,
85
+ "User-Agent" => "Oso Cloud (ruby)",
86
+ "Accept": "application/json",
87
+ "Content-Type": "application/json"
88
+ }
83
89
  end
84
90
 
85
- def get(path)
86
- result = Net::HTTP.get(URI("#{@url}/api/#{path}"), auth)
87
- handle_result result
88
- end
89
91
 
90
- def post(path, params)
91
- result = Net::HTTP.post(URI("#{@url}/api/#{path}"), params.to_json, auth)
92
+ def GET(path, params)
93
+ uri = URI("#{@url}/api/#{path}")
94
+ uri.query = URI::encode_www_form(params)
95
+ use_ssl = (uri.scheme == 'https')
96
+
97
+ result = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl ) { |http|
98
+ http.request(Net::HTTP::Get.new(uri, headers)) {|r|
99
+ r.read_body
100
+ }
101
+ }
92
102
  handle_result result
103
+
93
104
  end
94
105
 
95
- def delete(path, params)
96
- result = Net::HTTP.delete(URI("#{@url}/api/#{path}"), params.to_json, auth)
106
+ def POST(path, params)
107
+ result = Net::HTTP.post(URI("#{@url}/api/#{path}"), params.to_json, headers)
97
108
  handle_result result
98
109
  end
99
110
 
100
- # TODO: why does this need to be configurable?
101
- def default_to_type_and_id(obj)
102
- if obj.nil?
103
- %w[null null]
104
- else
105
- [obj.class.to_s, obj.id.to_s]
106
- end
111
+ def DELETE(path, params)
112
+ uri = URI("#{@url}/api/#{path}")
113
+ use_ssl = (uri.scheme == 'https')
114
+ result = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl ) { |http|
115
+ http.request(Net::HTTP::Delete.new(uri, headers), params.to_json) {|r|
116
+ r.read_body
117
+ }
118
+ }
119
+ handle_result result
107
120
  end
108
121
 
109
122
  def handle_result(result)
@@ -111,32 +124,27 @@ module Oso
111
124
  raise "Got an unexpected error from Oso Service: #{result.code}\n#{result.body}"
112
125
  end
113
126
 
114
- # TODO: Always JSON?
115
127
  JSON.parse(result.body)
116
128
  end
117
129
 
118
- def to_params(role_or_relation, from, name, to)
119
- from_type, from_id = default_to_type_and_id from
120
- to_type, to_id = default_to_type_and_id to
130
+ def extract_typed_id(x)
131
+ return TypedId.new(type: "String", id: x) if x.is_a? String
121
132
 
122
- from_name = role_or_relation == 'role' ? 'resource' : 'from'
123
- to_name = role_or_relation == 'role' ? 'actor' : 'to'
133
+ raise "#{x} does not have an 'id' field" unless x.respond_to? :id
134
+ raise "Invalid 'id' field on #{x}: #{x.id}" if x.id.nil?
124
135
 
125
- {
126
- "#{from_name}_id" => from_id,
127
- "#{from_name}_type" => from_type,
128
- role_or_relation.to_s => name,
129
- "#{to_name}_id" => to_id,
130
- "#{to_name}_type" => to_type
131
- }
136
+ TypedId.new(type: x.class.name, id: x.id.to_s)
132
137
  end
133
138
 
134
- def add_role_or_relation(role_or_relation, from, name, to)
135
- post("#{role_or_relation}s", to_params(role_or_relation, from, name, to))
139
+ def extract_arg_query(x)
140
+ return nil if x.nil?
141
+ extract_typed_id(x)
136
142
  end
137
143
 
138
- def delete_role_or_relation(role_or_relation, from, name, to)
139
- delete("#{role_or_relation}s", to_params(role_or_relation, from, name, to))
144
+ TypedId = Struct.new(:type, :id, keyword_init: true) do
145
+ def to_json(*args)
146
+ to_h.to_json(*args)
147
+ end
140
148
  end
141
149
  end
142
150
  end
data/lib/oso/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Oso
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
data/oso-cloud.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.summary = 'Oso authorization library.'
9
9
  spec.homepage = 'https://www.osohq.com/'
10
10
 
11
- spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
11
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
12
12
 
13
13
  # Specify which files should be added to the gem when it is released.
14
14
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -18,4 +18,6 @@ Gem::Specification.new do |spec|
18
18
  spec.bindir = 'exe'
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'minitest', '~> 5.15'
21
23
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oso-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oso Security, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-01 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-05-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.15'
13
27
  description:
14
28
  email:
15
29
  - support@osohq.com
@@ -19,6 +33,7 @@ extra_rdoc_files: []
19
33
  files:
20
34
  - ".gitignore"
21
35
  - Gemfile
36
+ - Gemfile.lock
22
37
  - README.md
23
38
  - Rakefile
24
39
  - bin/console
@@ -37,14 +52,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
37
52
  requirements:
38
53
  - - ">="
39
54
  - !ruby/object:Gem::Version
40
- version: 2.3.0
55
+ version: 2.7.0
41
56
  required_rubygems_version: !ruby/object:Gem::Requirement
42
57
  requirements:
43
58
  - - ">="
44
59
  - !ruby/object:Gem::Version
45
60
  version: '0'
46
61
  requirements: []
47
- rubygems_version: 3.1.2
62
+ rubygems_version: 3.1.6
48
63
  signing_key:
49
64
  specification_version: 4
50
65
  summary: Oso authorization library.