aserto 0.20.5 → 0.30.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: 7247661363785d8bcce7034a816c1d6c0d59ea054190066b599e590b140cf994
4
- data.tar.gz: f7cc418cdcf5ee823527a13ad959f4c38a53c470396a13c195eb59a298994dbe
3
+ metadata.gz: 4471efcec975432356d584d3d480e0ab503e139787c8f96ab88032ab15356175
4
+ data.tar.gz: aa46126a15fb9f583fd8dc9a1b064889f95ccfa3814bc4c6c7588c0ed7f78175
5
5
  SHA512:
6
- metadata.gz: d6f02241c7687ad870792af0fccde1ea326c2461a3b8535da94f2b309a4d65e2d478cf36fd7754b7b963388ae87e8bd1f38440fb33577a7ec03708fca8181424
7
- data.tar.gz: 80284a19aad72b4064a5626bbbc23aecf5c2ae0ac91066478a09f1643a97543ab5cf6c2d98523c319decd8ad097385aeb54de5705d9061813566f36e2cbd4e75
6
+ metadata.gz: 61af3804724a6138e21a5233c25712213860b4e2939331f1087e728c36a6cf5fefb31c6e23b77fc219df75d84abf2ecb1675892e60663e787cd6932884be3dec
7
+ data.tar.gz: f73188bf7eb0a4b58944022c715fdcb65718e3d8debe3215a6a82437781f544ff78cc1012a169ffd8deb2a762650da9d0970030a2e8eeaab461abe1dc4233d3b
data/README.md CHANGED
@@ -32,7 +32,7 @@ You can initialize a directory client as follows:
32
32
  ```ruby
33
33
  require 'aserto/directory/client'
34
34
 
35
- directory_client = Aserto::Directory::Client.new(
35
+ directory_client =Aserto::Directory::V3::Client.new(
36
36
  url: "directory.eng.aserto.com:8443",
37
37
  tenant_id: "aserto-tenant-id",
38
38
  api_key: "basic directory api key",
@@ -44,85 +44,7 @@ directory_client = Aserto::Directory::Client.new(
44
44
  - `tenant_id`: Aserto tenant ID (_required_ if using hosted directory)
45
45
  - `cert_path`: Path to the grpc service certificate when connecting to local topaz instance.
46
46
 
47
- ### Getting objects and relations
48
- Get an object instance with the type `type-name` and the key `object-key`. For example:
49
-
50
- ```ruby
51
- user = directory_client.object(type: 'user', key: 'euang@acmecorp.com')
52
- ```
53
-
54
- Get an array of relations of a certain type for an object instance. For example:
55
-
56
- ```ruby
57
- identity = 'euang@acmecorp.com';
58
- relations = directory_client.relation(
59
- {
60
- subject: {
61
- type: 'user',
62
- },
63
- object: {
64
- type: 'identity',
65
- key: identity
66
- },
67
- relation: {
68
- name: 'identifier',
69
- objectType: 'identity'
70
- }
71
- }
72
- )
73
- ```
74
-
75
- ### Setting objects and relations
76
-
77
- Create a new object
78
- ```ruby
79
- user = directory_client.set_object(object: { type: "user", key: "test-object", display_name: "test object" })
80
- identity = directory_client.set_object(object: { type: "identity", key: "test-identity" })
81
- ```
82
-
83
- Update an existing object
84
- ```ruby
85
- user = directory_client.set_object(object: { type: "user", key: "test-object", display_name: "test object" })
86
- user.display_name = 'test object edit'
87
- updated_user = directory_client.set_object(object: user)
88
- ```
89
-
90
- Create a new relation
91
- ```ruby
92
- directory_client.set_relation(
93
- subject: { type: "user", "test-object" },
94
- relation: "identifier",
95
- object: { type: "identity", key: "test-identity" }
96
- )
97
- ```
98
-
99
- Delete a relation
100
- ```ruby
101
- pp client.delete_relation(
102
- subject: { type: "user", key: "test-object" },
103
- relation: { name: "identifier", object_type: "identity" },
104
- object: { type: "identity", key: "test-identity" }
105
- )
106
- ```
107
-
108
- ### Checking permissions and relations
109
- Check permission
110
- ```ruby
111
- directory_client.check_permission(
112
- subject: { type: "user", key: "011a88bc-7df9-4d92-ba1f-2ff319e101e1" },
113
- permission: { name: "read" },
114
- object: { type: "group", key: "executive" }
115
- )
116
- ```
117
-
118
- Check relation
119
- ```ruby
120
- directory_client.check_relation(
121
- subject: { type: "user", key: "dfdadc39-7335-404d-af66-c77cf13a15f8" },
122
- relation: { name: "identifier", object_type: "identity" },
123
- object: { type: "identity", key: "euang@acmecorp.com" }
124
- )
125
- ```
47
+ See https://rubydoc.info/gems/aserto/docs/Aserto/Directory/V3/Client for full documentation
126
48
 
127
49
  ## Authorizer
128
50
  `Aserto::Authorization` is a middleware that allows Ruby applications to use Aserto as the Authorization provider.
@@ -150,7 +72,7 @@ The middleware accepts the following optional parameters:
150
72
  | cert_path | `""` | Path to the grpc service certificate when connecting to local topaz instance. |
151
73
  | decision | `"allowed"` | The decision that will be used by the middleware when creating an authorizer request. |
152
74
  | logger | `STDOUT` | The logger to be used by the middleware. |
153
- | identity_mapping | `{ type: :none }` | The strategy for retrieving the identity, possible values: `:jwt, :sub, :none` |
75
+ | identity_mapping | `{ type: :none }` | The strategy for retrieving the identity, possible values: `:jwt, :sub, :manual, :none` |
154
76
  | disabled_for | `[{}]` | Which path and actions to skip the authorization for. |
155
77
  | on_unauthorized | `-> { return [403, {}, ["Forbidden"]] }`| A lambda that is executed when the authorization fails. |
156
78
 
@@ -172,6 +94,14 @@ config.identity_mapping = {
172
94
  }
173
95
  ```
174
96
 
97
+ ```ruby
98
+ # configure the middleware to use a manual identity.
99
+ config.identity_mapping = {
100
+ type: :manual,
101
+ value: "my-identity",
102
+ }
103
+ ```
104
+
175
105
  The whole identity resolution can be overwritten by providing a custom function.
176
106
  ```ruby
177
107
  # config/initializers/aserto.rb
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.20.5
1
+ 0.30.0
@@ -13,6 +13,7 @@ module Aserto
13
13
  INTERNAL_MAPPING = {
14
14
  unknown: Aserto::Authorizer::V2::Api::IdentityType::IDENTITY_TYPE_UNKNOWN,
15
15
  none: Aserto::Authorizer::V2::Api::IdentityType::IDENTITY_TYPE_NONE,
16
+ manual: Aserto::Authorizer::V2::Api::IdentityType::IDENTITY_TYPE_MANUAL,
16
17
  sub: Aserto::Authorizer::V2::Api::IdentityType::IDENTITY_TYPE_SUB,
17
18
  jwt: Aserto::Authorizer::V2::Api::IdentityType::IDENTITY_TYPE_JWT
18
19
  }.freeze
@@ -22,26 +23,52 @@ module Aserto
22
23
  def initialize(request)
23
24
  @request = request
24
25
  @config = Aserto.config
25
- @client = Aserto::Authorizer::V2::Authorizer::Stub.new(
26
+ @client = @config.client || Aserto::Authorizer::V2::Authorizer::Stub.new(
26
27
  config.service_url,
27
28
  load_creds
28
29
  )
29
30
  end
30
31
 
31
32
  def is
32
- exec_is(config.decision)
33
+ exec_is(request_is(config.decision))
34
+ end
35
+
36
+ def check(object_id:, object_type:, relation:)
37
+ resource_context_fields = {
38
+ object_id: object_id,
39
+ object_type: object_type,
40
+ relation: relation
41
+ }.merge!(resource_context.to_h)
42
+
43
+ check_resource_context = Google::Protobuf::Struct
44
+ .from_hash(resource_context_fields.transform_keys!(&:to_s))
45
+
46
+ request = Aserto::Authorizer::V2::IsRequest.new(
47
+ {
48
+ policy_context: Aserto::Authorizer::V2::Api::PolicyContext.new(
49
+ {
50
+ path: config.policy_root ? "#{config.policy_root}.check" : "rebac.check",
51
+ decisions: [config.decision]
52
+ }
53
+ ),
54
+ policy_instance: policy_instance,
55
+ identity_context: identity_context,
56
+ resource_context: check_resource_context
57
+ }
58
+ )
59
+ exec_is(request)
33
60
  end
34
61
 
35
62
  def allowed?
36
- exec_is("allowed")
63
+ exec_is(request_is("allowed"))
37
64
  end
38
65
 
39
66
  def visible?
40
- exec_is("visible")
67
+ exec_is(request_is("visible"))
41
68
  end
42
69
 
43
70
  def enabled?
44
- exec_is("enabled")
71
+ exec_is(request_is("enabled"))
45
72
  end
46
73
 
47
74
  private
@@ -55,15 +82,15 @@ module Aserto
55
82
  end
56
83
  end
57
84
 
58
- def exec_is(decision)
85
+ def exec_is(request)
59
86
  begin
60
- response = client.is(request_is(decision), headers)
87
+ response = client.is(request, headers)
61
88
  rescue GRPC::BadStatus => e
62
89
  Aserto.logger.error(e.inspect)
63
90
  return false
64
91
  end
65
92
 
66
- decision = response.decisions.find { |el| el.decision == decision }
93
+ decision = response.decisions.find { |el| el.decision == request.policy_context.decisions[0] }
67
94
  return false unless decision
68
95
 
69
96
  decision.is
data/lib/aserto/config.rb CHANGED
@@ -26,6 +26,7 @@ module Aserto
26
26
  DEFAULT_ATTRS = {
27
27
  authorizer_api_key: "",
28
28
  tenant_id: "",
29
+ client: nil,
29
30
  service_url: "localhost:8282",
30
31
  decision: "allowed",
31
32
  disabled_for: [{}],
@@ -10,11 +10,31 @@ module Aserto
10
10
  super()
11
11
  end
12
12
 
13
- def request_response(method:, request:, call:, metadata:)
13
+ def request_response(request: nil, call: nil, method: nil, metadata: nil)
14
+ update_metadata(metadata)
15
+ yield(request, call, method, metadata)
16
+ end
17
+
18
+ def bidi_streamer(requests: nil, call: nil, method: nil, metadata: nil)
19
+ update_metadata(metadata)
20
+ yield(requests, call, method, metadata)
21
+ end
22
+
23
+ def client_streamer(requests: nil, call: nil, method: nil, metadata: nil)
24
+ update_metadata(metadata)
25
+ yield(requests, call, method, metadata)
26
+ end
27
+
28
+ def server_streamer(request: nil, call: nil, method: nil, metadata: nil)
29
+ update_metadata(metadata)
30
+ yield(request, call, method, metadata)
31
+ end
32
+
33
+ private
34
+
35
+ def update_metadata(metadata)
14
36
  metadata["aserto-tenant-id"] = @tenant_id
15
37
  metadata["authorization"] = @api_key
16
-
17
- yield(method, request, call, metadata)
18
38
  end
19
39
  end
20
40
  end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aserto/directory"
4
+ require_relative "../interceptors/headers"
5
+ require_relative "config"
6
+ require_relative "reader"
7
+ require_relative "writer"
8
+ require_relative "model"
9
+ require_relative "importer"
10
+ require_relative "exporter"
11
+
12
+ module Aserto
13
+ module Directory
14
+ module V3
15
+ class Client
16
+ extend Forwardable
17
+ include ::Aserto::Directory::V3::Reader
18
+ # @!parse include ::Aserto::Directory::V3::Reader
19
+
20
+ include ::Aserto::Directory::V3::Writer
21
+ # @!parse include ::Aserto::Directory::V3::Writer
22
+
23
+ include ::Aserto::Directory::V3::Model
24
+ # @!parse include ::Aserto::Directory::V3::Model
25
+
26
+ include ::Aserto::Directory::V3::Importer
27
+ # @!parse include ::Aserto::Directory::V3::Importer
28
+
29
+ include ::Aserto::Directory::V3::Exporter
30
+ # @!parse include ::Aserto::Directory::V3::Exporter
31
+
32
+ # Creates a new Directory V3 Client
33
+ #
34
+ # @param config [Aserto::Directory::V3::Config] the service configuration
35
+ # Base configuration
36
+ # If non-nil, this configuration is used for any client that doesn't have its own configuration.
37
+ # If nil, only clients that have their own configuration will be created.
38
+ #
39
+ # @example Create a new Directory V3 Client with all the services
40
+ # client = Aserto::Directory::V3::Client.new(
41
+ # {
42
+ # url: "directory.eng.aserto.com:8443",
43
+ # tenant_id: "tenant-id",
44
+ # api_key: "basic api-key",
45
+ # }
46
+ # )
47
+ #
48
+ # @example Create a new Directory V3 Client with reader only
49
+ # client = Aserto::Directory::V3::Client.new(
50
+ # {
51
+ # reader: {
52
+ # url: "directory.eng.aserto.com:8443",
53
+ # tenant_id: "tenant-id",
54
+ # api_key: "basic api-key",
55
+ # }
56
+ # }
57
+ # )
58
+ #
59
+ # @return [Aserto::Directory::V3::Client] the new Directory V3 Client
60
+ def initialize(config)
61
+ base_config = ::Aserto::Directory::V3::Config.new(config)
62
+
63
+ @reader = create_client(:reader, base_config.reader)
64
+ @writer = create_client(:writer, base_config.writer)
65
+ @importer = create_client(:importer, base_config.importer)
66
+ @exporter = create_client(:exporter, base_config.exporter)
67
+ @model = create_client(:model, base_config.model)
68
+ end
69
+
70
+ private
71
+
72
+ attr_reader :reader, :writer, :model, :importer, :exporter
73
+
74
+ class NullClient
75
+ def initialize(name)
76
+ @name = name
77
+ end
78
+
79
+ def method_missing(method, *_args)
80
+ puts "Cannot call '#{method}': '#{@name.to_s.capitalize}' client is not initialized."
81
+ end
82
+
83
+ def respond_to_missing?(_name, _include_private)
84
+ true
85
+ end
86
+ end
87
+
88
+ SERVICE_MAP = {
89
+ reader: ::Aserto::Directory::Reader::V3::Reader::Stub,
90
+ writer: ::Aserto::Directory::Writer::V3::Writer::Stub,
91
+ importer: ::Aserto::Directory::Importer::V3::Importer::Stub,
92
+ exporter: ::Aserto::Directory::Exporter::V3::Exporter::Stub,
93
+ model: ::Aserto::Directory::Model::V3::Model::Stub
94
+ }.freeze
95
+
96
+ def create_client(type, config)
97
+ return NullClient.new(type) unless config
98
+
99
+ SERVICE_MAP[type].new(
100
+ config.url,
101
+ config.credentials,
102
+ interceptors: config.interceptors
103
+ )
104
+ end
105
+ end
106
+
107
+ remove_const(:Reader)
108
+ remove_const(:Writer)
109
+ remove_const(:Model)
110
+ remove_const(:Importer)
111
+ remove_const(:Exporter)
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../interceptors/headers"
4
+
5
+ module Aserto
6
+ module Directory
7
+ module V3
8
+ class Config
9
+ attr_reader :reader, :writer, :importer, :exporter, :model
10
+
11
+ def initialize(config)
12
+ @base = {
13
+ url: config[:url] || "directory.prod.aserto.com:8443",
14
+ api_key: config[:api_key],
15
+ tenant_id: config[:tenant_id],
16
+ cert_path: config[:cert_path]
17
+ }
18
+
19
+ @reader = build(**(config[:reader] || {}))
20
+ @writer = build(**(config[:writer] || {}))
21
+ @importer = build(**(config[:importer] || {}))
22
+ @exporter = build(**(config[:exporter] || {}))
23
+ @model = build(**(config[:model] || {}))
24
+ end
25
+
26
+ private
27
+
28
+ class BaseConfig
29
+ attr_reader :url, :credentials, :interceptors
30
+
31
+ def initialize(url, credentials, interceptors)
32
+ @url = url
33
+ @credentials = credentials
34
+ @interceptors = interceptors
35
+ end
36
+ end
37
+
38
+ def build(
39
+ url: @base[:url],
40
+ api_key: @base[:api_key],
41
+ tenant_id: @base[:tenant_id],
42
+ cert_path: @base[:cert_path]
43
+ )
44
+
45
+ interceptors = []
46
+ interceptors = [Interceptors::Headers.new(api_key, tenant_id)] if !api_key.nil? && !tenant_id.nil?
47
+ BaseConfig.new(url, load_creds(cert_path), interceptors)
48
+ end
49
+
50
+ def load_creds(cert_path)
51
+ if cert_path && File.file?(cert_path)
52
+ GRPC::Core::ChannelCredentials.new(File.read(cert_path))
53
+ else
54
+ GRPC::Core::ChannelCredentials.new
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aserto
4
+ module Directory
5
+ module V3
6
+ module Exporter
7
+ DATA_TYPE = {
8
+ unknown: ::Aserto::Directory::Exporter::V3::Option::OPTION_UNKNOWN,
9
+ objects: ::Aserto::Directory::Exporter::V3::Option::OPTION_DATA_OBJECTS,
10
+ relations: ::Aserto::Directory::Exporter::V3::Option::OPTION_DATA_RELATIONS,
11
+ all: ::Aserto::Directory::Exporter::V3::Option::OPTION_DATA
12
+ }.freeze
13
+
14
+ #
15
+ # Exports directory data
16
+ #
17
+ # @param [String] data_type one of [:unknown, :objects, :relations, :all]
18
+ #
19
+ def export(data_type: :unknown)
20
+ data = []
21
+ operation = exporter.export(
22
+ Aserto::Directory::Exporter::V3::ExportRequest.new(options: DATA_TYPE[data_type]),
23
+ return_op: true
24
+ )
25
+
26
+ response = operation.execute
27
+ response.each { |r| data.push(r) }
28
+ operation.wait
29
+
30
+ data
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aserto
4
+ module Directory
5
+ module V3
6
+ module Importer
7
+ #
8
+ # Imports objects and relations
9
+ #
10
+ # @param Array[Hash] data to be imported
11
+ #
12
+ # @example
13
+ # directory.import(
14
+ # [
15
+ # { object: { id: "import-user", type: "user" } },
16
+ # { object: { id: "import-group", type: "group" } },
17
+ # {
18
+ # relation: {
19
+ # object_id: "import-user",
20
+ # object_type: "user",
21
+ # relation: "member",
22
+ # subject_id: "import-group",
23
+ # subject_type: "group"
24
+ # }
25
+ # }
26
+ # ]
27
+ # )
28
+ def import(data)
29
+ data.map! do |value|
30
+ Aserto::Directory::Importer::V3::ImportRequest.new(value)
31
+ end
32
+ operation = importer.import(data, return_op: true)
33
+ response = operation.execute
34
+ response.each { |r| } # ensures that the server sends trailing data
35
+ operation.wait
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aserto
4
+ module Directory
5
+ module V3
6
+ module Model
7
+ # rubocop:disable Naming/AccessorMethodName
8
+
9
+ # Get the content of a manifest
10
+ # @return [Hash] { body: String, updated_at: Timestap, etag: String }
11
+ def get_manifest
12
+ response = {}
13
+ manifest_enum = @model.get_manifest(Aserto::Directory::Model::V3::GetManifestRequest.new)
14
+ manifest_enum.each do |resp|
15
+ response[:body] = resp.body.data if resp.respond_to?(:body) && !resp.body.nil?
16
+ if resp.respond_to?(:metadata)
17
+ response[:updated_at] ||= resp.metadata&.updated_at&.to_time
18
+ response[:etag] ||= resp.metadata&.etag
19
+ end
20
+ end
21
+
22
+ response
23
+ end
24
+
25
+ # Set the content of a manifest
26
+ # @param body [String]
27
+ # @return [Aserto::Directory::Model::V3::SetManifestResponse]
28
+ def set_manifest(body)
29
+ @model.set_manifest([Aserto::Directory::Model::V3::SetManifestRequest.new(body: { data: body })])
30
+ end
31
+
32
+ # rubocop:enable Naming/AccessorMethodName
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,266 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aserto
4
+ module Directory
5
+ module V3
6
+ module Reader
7
+ #
8
+ # find an object by id and type
9
+ #
10
+ # @param object_id [String]
11
+ # @param object_type [String]
12
+ #
13
+ # @return [Aserto::Directory::Reader::V3::GetObjectResponse]
14
+ #
15
+ # @example
16
+ # client.get_object(
17
+ # object_type: "user",
18
+ # object_id: "rick@the-citadel.com"
19
+ # )
20
+ def get_object(object_id:, object_type:)
21
+ reader.get_object(
22
+ Aserto::Directory::Reader::V3::GetObjectRequest.new(
23
+ object_id: object_id,
24
+ object_type: object_type
25
+ )
26
+ )
27
+ end
28
+
29
+ #
30
+ # list objects by type
31
+ #
32
+ # @param object_type [String]
33
+ # @param page [Hash]
34
+ # @option page [Integer] :size
35
+ # @option page [String] :token
36
+ #
37
+ # @return [Aserto::Directory::V3::GetObjectsResponse]
38
+ #
39
+ # @example
40
+ # client.get_objects(
41
+ # object_type: "user",
42
+ # page: { size: 2 }
43
+ # )
44
+ def get_objects(object_type:, page: { size: 100 })
45
+ reader.get_objects(
46
+ Aserto::Directory::Reader::V3::GetObjectsRequest.new(
47
+ object_type: object_type,
48
+ page: Aserto::Directory::Common::V3::PaginationRequest.new(page)
49
+ )
50
+ )
51
+ end
52
+
53
+ #
54
+ # find a relation between two objects
55
+ #
56
+ # @param [String] object_type
57
+ # @param [String] object_id
58
+ # @param [String] relation
59
+ # @param [String] subject_type
60
+ # @param [String] subject_id
61
+ # @param [String] subject_relation
62
+ # @param [Boolean] with_objects
63
+ #
64
+ # @return [Aserto::Directory::Reader::V3::GetRelationResponse]
65
+ #
66
+ # @example
67
+ # client.get_relation(
68
+ # object_type: "user",
69
+ # object_id: "rick@the-citadel.com",
70
+ # relation: "member",
71
+ # object_type: "group",
72
+ # object_id: "evil_genius"
73
+ # )
74
+ def get_relation(object_type:, object_id:, relation:, subject_type:, subject_id:, subject_relation: "",
75
+ with_objects: false)
76
+ reader.get_relation(
77
+ Aserto::Directory::Reader::V3::GetRelationRequest.new(
78
+ object_type: object_type,
79
+ object_id: object_id,
80
+ relation: relation,
81
+ subject_type: subject_type,
82
+ subject_id: subject_id,
83
+ subject_relation: subject_relation,
84
+ with_objects: with_objects
85
+ )
86
+ )
87
+ end
88
+
89
+ #
90
+ # List relations between two objects
91
+ #
92
+ # @param [String] object_type
93
+ # @param [String] object_id
94
+ # @param [String] relation
95
+ # @param [String] subject_type
96
+ # @param [String] subject_id
97
+ # @param [String] subject_relation
98
+ # @param [Boolean] with_objects
99
+ # @param page [Hash]
100
+ # @option page [Integer] :size
101
+ # @option page [String] :token
102
+ #
103
+ # @return [Aserto::Directory::Reader::V3::GetRelationsResponse]
104
+ #
105
+ # @example
106
+ # client.get_relations(
107
+ # object_type: "user",
108
+ # object_id: "rick@the-citadel.com",
109
+ # relation: "member",
110
+ # page: { size: 10 }
111
+ # )
112
+ def get_relations(object_type: "", object_id: "", relation: "", subject_type: "", subject_id: "",
113
+ subject_relation: "", with_objects: false, page: { size: 100 })
114
+ reader.get_relations(
115
+ Aserto::Directory::Reader::V3::GetRelationsRequest.new(
116
+ object_type: object_type,
117
+ object_id: object_id,
118
+ relation: relation,
119
+ subject_type: subject_type,
120
+ subject_id: subject_id,
121
+ subject_relation: subject_relation,
122
+ with_objects: with_objects,
123
+ page: Aserto::Directory::Common::V3::PaginationRequest.new(page)
124
+ )
125
+ )
126
+ end
127
+
128
+ #
129
+ # Check relation between two objects
130
+ #
131
+ # @param [String] object_type
132
+ # @param [String] object_id
133
+ # @param [String] relation
134
+ # @param [String] subject_type
135
+ # @param [String] subject_id
136
+ # @param [Boolean] trace
137
+ #
138
+ # @return [Aserto::Directory::Reader::V3::CheckRelationResponse]
139
+ #
140
+ # @example
141
+ # client.check_relation(
142
+ # object_type: "user",
143
+ # object_id: "rick@the-citadel.com",
144
+ # relation: "member",
145
+ # object_type: "group",
146
+ # object_id: "evil_genius"
147
+ # )
148
+ def check_relation(object_type:, object_id:, relation:, subject_type:, subject_id:, trace: false)
149
+ reader.check_relation(
150
+ Aserto::Directory::Reader::V3::CheckRelationRequest.new(
151
+ object_type: object_type,
152
+ object_id: object_id,
153
+ relation: relation,
154
+ subject_type: subject_type,
155
+ subject_id: subject_id,
156
+ trace: trace
157
+ )
158
+ )
159
+ end
160
+
161
+ #
162
+ # Check relation between two objects
163
+ #
164
+ # @param [String] object_type
165
+ # @param [String] object_id
166
+ # @param [String] relation
167
+ # @param [String] subject_type
168
+ # @param [String] subject_id
169
+ # @param [Boolean] trace
170
+ #
171
+ # @return [Aserto::Directory::Reader::V3::CheckResponse]
172
+ #
173
+ # @example
174
+ # client.check(
175
+ # object_type: "user",
176
+ # object_id: "rick@the-citadel.com",
177
+ # relation: "member",
178
+ # object_type: "group",
179
+ # object_id: "evil_genius"
180
+ # )
181
+ def check(object_type:, object_id:, relation:, subject_type:, subject_id:, trace: false)
182
+ reader.check(
183
+ Aserto::Directory::Reader::V3::CheckRequest.new(
184
+ object_type: object_type,
185
+ object_id: object_id,
186
+ relation: relation,
187
+ subject_type: subject_type,
188
+ subject_id: subject_id,
189
+ trace: trace
190
+ )
191
+ )
192
+ end
193
+
194
+ #
195
+ # Check permission between two objects
196
+ #
197
+ # @param [String] object_type
198
+ # @param [String] object_id
199
+ # @param [String] permission
200
+ # @param [String] subject_type
201
+ # @param [String] subject_id
202
+ # @param [Boolean] trace
203
+ #
204
+ # @return [Aserto::Directory::Reader::V3::CheckPermissionResponse]
205
+ #
206
+ # @example
207
+ # client.check_permission(
208
+ # object_type: "user",
209
+ # object_id: "rick@the-citadel.com",
210
+ # permission: "read",
211
+ # object_type: "group",
212
+ # object_id: "evil_genius"
213
+ # )
214
+ def check_permission(object_type:, object_id:, permission:, subject_type:, subject_id:, trace: false)
215
+ reader.check_permission(
216
+ Aserto::Directory::Reader::V3::CheckPermissionRequest.new(
217
+ object_type: object_type,
218
+ object_id: object_id,
219
+ permission: permission,
220
+ subject_type: subject_type,
221
+ subject_id: subject_id,
222
+ trace: trace
223
+ )
224
+ )
225
+ end
226
+
227
+ #
228
+ # Returns object graph from anchor to subject or object.
229
+ #
230
+ # @param [String] anchor_type <description>
231
+ # @param [String] anchor_id <description>
232
+ # @param [String] object_type <description>
233
+ # @param [String] object_id <description>
234
+ # @param [String] relation <description>
235
+ # @param [String] subject_type <description>
236
+ # @param [String] <description>
237
+ #
238
+ # @return [Aserto::Directory::Reader::V3::GetGraphResponse]
239
+ #
240
+ # @example
241
+ # directory.get_graph(
242
+ # anchor_type: "user",
243
+ # anchor_id: "rick@the-citadel.com",
244
+ # subject_id: "rick@the-citadel.com",
245
+ # subject_type: "user",
246
+ # relation: "member"
247
+ # )
248
+ def get_graph(anchor_type:, anchor_id:, object_type: "", object_id: "", relation: "", subject_type: "",
249
+ subject_id: "", subject_relation: "")
250
+ reader.get_graph(
251
+ Aserto::Directory::Reader::V3::GetGraphRequest.new(
252
+ anchor_type: anchor_type,
253
+ anchor_id: anchor_id,
254
+ object_type: object_type,
255
+ object_id: object_id,
256
+ relation: relation,
257
+ subject_type: subject_type,
258
+ subject_id: subject_id,
259
+ subject_relation: subject_relation
260
+ )
261
+ )
262
+ end
263
+ end
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aserto
4
+ module Directory
5
+ module V3
6
+ module Writer
7
+ require "google/protobuf/well_known_types"
8
+
9
+ #
10
+ # Create a new object
11
+ #
12
+ # @param [String] object_id
13
+ # @param [String] object_type
14
+ # @param [String] display_name
15
+ # @param [Hash] properties
16
+ # @param [String] etag
17
+ #
18
+ # @return [Aserto::Directory::Writer::V3::SetObjectResponse]
19
+ #
20
+ # @example
21
+ # client.set_object(object_id: "1234", object_type: "user", properties: { email: "test" })
22
+ def set_object(object_id:, object_type:, display_name: "", properties: {}, etag: nil)
23
+ writer.set_object(
24
+ Aserto::Directory::Writer::V3::SetObjectRequest.new(
25
+ object: {
26
+ id: object_id,
27
+ type: object_type,
28
+ display_name: display_name,
29
+ properties: Google::Protobuf::Struct.from_hash(properties.transform_keys!(&:to_s)),
30
+ etag: etag
31
+ }
32
+ )
33
+ )
34
+ end
35
+
36
+ #
37
+ # Delete an object
38
+ #
39
+ # @param [String] object_id
40
+ # @param [String] object_type
41
+ # @param [Boolean] with_relations
42
+ #
43
+ # @return [ Aserto::Directory::Writer::V3::DeleteObjectResponse]
44
+ #
45
+ # @example
46
+ # client.delete_object(object_id: "1234", object_type: "user")
47
+ def delete_object(object_id:, object_type:, with_relations: false)
48
+ writer.delete_object(
49
+ Aserto::Directory::Writer::V3::DeleteObjectRequest.new(
50
+ object_id: object_id,
51
+ object_type: object_type,
52
+ with_relations: with_relations
53
+ )
54
+ )
55
+ end
56
+
57
+ #
58
+ # Creates a relation between two objects
59
+ #
60
+ # @param [String] object_type
61
+ # @param [String] object_id
62
+ # @param [String] relation
63
+ # @param [String] subject_type
64
+ # @param [String] subject_id
65
+ #
66
+ # @return [Aserto::Directory::Writer::V3::SetRelationResponse]
67
+ #
68
+ # @example
69
+ # client.set_relation(
70
+ # object_type: "user",
71
+ # object_id: "rick@the-citadel.com",
72
+ # relation: "member",
73
+ # object_type: "group",
74
+ # object_id: "evil_genius"
75
+ # )
76
+ def set_relation(object_type:, object_id:, relation:, subject_type:, subject_id:)
77
+ writer.set_relation(
78
+ Aserto::Directory::Writer::V3::SetRelationRequest.new(
79
+ relation: {
80
+ object_type: object_type,
81
+ object_id: object_id,
82
+ relation: relation,
83
+ subject_type: subject_type,
84
+ subject_id: subject_id
85
+ }
86
+ )
87
+ )
88
+ end
89
+
90
+ #
91
+ # Delete a relation between two objects
92
+ #
93
+ # @param [String] object_type
94
+ # @param [String] object_id
95
+ # @param [String] relation
96
+ # @param [String] subject_type
97
+ # @param [String] subject_id
98
+ # @param [String] subject_relation
99
+ #
100
+ # @return [Aserto::Directory::Writer::V3::DeleteRelationRequest]
101
+ #
102
+ # @example
103
+ # client.get_relation(
104
+ # object_type: "user",
105
+ # object_id: "rick@the-citadel.com",
106
+ # relation: "member",
107
+ # object_type: "group",
108
+ # object_id: "evil_genius"
109
+ # )
110
+ def delete_relation(object_type:, object_id:, relation:, subject_type:, subject_id:, subject_relation: "")
111
+ writer.delete_relation(
112
+ Aserto::Directory::Writer::V3::DeleteRelationRequest.new(
113
+ object_type: object_type,
114
+ object_id: object_id,
115
+ relation: relation,
116
+ subject_type: subject_type,
117
+ subject_id: subject_id,
118
+ subject_relation: subject_relation
119
+ )
120
+ )
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
data/lib/aserto/errors.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  module Aserto
4
4
  class Error < StandardError; end
5
5
  class InvalidResourceMapping < Error; end
6
+ class InvalidIdentityType < Error; end
6
7
 
7
8
  class AccessDenied < Error
8
9
  attr_reader :action, :conditions
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aserto
4
+ module IdentityMapper
5
+ module Manual
6
+ class << self
7
+ def execute(_request)
8
+ {
9
+ type: :manual,
10
+ identity: ::Aserto.config.identity_mapping[:value].to_s
11
+ }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -4,20 +4,23 @@ require_relative "identity_mapper/base"
4
4
  require_relative "identity_mapper/none"
5
5
  require_relative "identity_mapper/sub"
6
6
  require_relative "identity_mapper/jwt"
7
+ require_relative "identity_mapper/manual"
7
8
 
8
9
  module Aserto
9
10
  module IdentityMapper
10
11
  STRATEGY = {
11
12
  none: Aserto::IdentityMapper::None,
13
+ manual: Aserto::IdentityMapper::Manual,
12
14
  sub: Aserto::IdentityMapper::Sub,
13
15
  jwt: Aserto::IdentityMapper::Jwt
14
16
  }.freeze
15
17
 
16
18
  class << self
17
19
  def execute(request)
18
- STRATEGY[
19
- Aserto.config.identity_mapping[:type].to_sym || :none
20
- ].execute(request)
20
+ STRATEGY.fetch(
21
+ Aserto.config.identity_mapping[:type].to_sym || :none,
22
+ Aserto::IdentityMapper::None
23
+ ).execute(request)
21
24
  end
22
25
  end
23
26
  end
data/lib/aserto.rb CHANGED
@@ -12,6 +12,7 @@ require_relative "aserto/resource_mapper"
12
12
  require_relative "aserto/auth_client"
13
13
  require_relative "aserto/errors"
14
14
  require_relative "aserto/directory/client"
15
+ require_relative "aserto/directory/v3/client"
15
16
 
16
17
  module Aserto
17
18
  class << self
@@ -52,17 +53,17 @@ module Aserto
52
53
  def with_resource_mapper
53
54
  Aserto::ResourceMapper.class_eval do |klass|
54
55
  klass.define_singleton_method(:execute) do |request|
55
- if block_given?
56
- result = yield(request)
57
- unless result.is_a?(Hash)
58
- raise Aserto::InvalidResourceMapping, "block must return a hash, got: #{result.class}"
59
- end
56
+ return unless block_given?
60
57
 
61
- require "google/protobuf/well_known_types"
62
-
63
- result.transform_keys!(&:to_s)
64
- Google::Protobuf::Struct.from_hash(result)
58
+ result = yield(request)
59
+ unless result.is_a?(Hash)
60
+ raise Aserto::InvalidResourceMapping, "block must return a hash, got: #{result.class}"
65
61
  end
62
+
63
+ require "google/protobuf/well_known_types"
64
+
65
+ result.transform_keys!(&:to_s)
66
+ Google::Protobuf::Struct.from_hash(result)
66
67
  end
67
68
  end
68
69
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aserto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.5
4
+ version: 0.30.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aserto
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-23 00:00:00.000000000 Z
11
+ date: 2023-11-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aserto-authorizer
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.5
19
+ version: 0.20.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.0.5
26
+ version: 0.20.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: aserto-directory
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.0.3
33
+ version: 0.30.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.0.3
40
+ version: 0.30.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: jwt
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -83,10 +83,18 @@ files:
83
83
  - lib/aserto/directory/client.rb
84
84
  - lib/aserto/directory/interceptors/headers.rb
85
85
  - lib/aserto/directory/requests.rb
86
+ - lib/aserto/directory/v3/client.rb
87
+ - lib/aserto/directory/v3/config.rb
88
+ - lib/aserto/directory/v3/exporter.rb
89
+ - lib/aserto/directory/v3/importer.rb
90
+ - lib/aserto/directory/v3/model.rb
91
+ - lib/aserto/directory/v3/reader.rb
92
+ - lib/aserto/directory/v3/writer.rb
86
93
  - lib/aserto/errors.rb
87
94
  - lib/aserto/identity_mapper.rb
88
95
  - lib/aserto/identity_mapper/base.rb
89
96
  - lib/aserto/identity_mapper/jwt.rb
97
+ - lib/aserto/identity_mapper/manual.rb
90
98
  - lib/aserto/identity_mapper/none.rb
91
99
  - lib/aserto/identity_mapper/sub.rb
92
100
  - lib/aserto/policy_path_mapper.rb