Skip to content

Commit

Permalink
Add directory v3 client (#13)
Browse files Browse the repository at this point in the history
* Add Directory v3 Client
  • Loading branch information
gimmyxd authored Nov 27, 2023
1 parent 1579e83 commit 7308ecd
Show file tree
Hide file tree
Showing 20 changed files with 1,215 additions and 90 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,14 @@ jobs:
- name: Run rubocop
run: bundle exec rubocop --parallel

- name: Set up Homebrew
uses: Homebrew/actions/setup-homebrew@master

- name: Install topaz
run: brew tap aserto-dev/tap && brew install aserto-dev/tap/topaz && topaz install

- name: run RSpec
run: bundle exec rspec
run: bundle exec rake spec:all

release:
runs-on: ubuntu-latest
Expand All @@ -47,7 +53,7 @@ jobs:
name: Release to rubygems
steps:
- name: Read Configuration
uses: hashicorp/vault-action@v2.4.1
uses: hashicorp/vault-action@v2.7.2
id: vault
with:
url: ${{ env.VAULT_ADDR }}
Expand Down
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ AllCops:
require:
- rubocop-rspec
- rubocop-performance
- rubocop-rake

Style/Documentation:
Enabled: false
Expand Down Expand Up @@ -34,3 +35,6 @@ RSpec/ExampleLength:

RSpec/NestedGroups:
Max: 4

Metrics/ParameterLists:
Enabled: false
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cSpell.words": [
"creds"
"creds",
"etag"
]
}
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ group :development do
gem "bundler", ">= 1.15.0", "< 3.0"
gem "codecov", "~> 0.6"
gem "grpc_mock", "~> 0.4"
gem "pry-byebug", "~> 3.10"
gem "rspec", "~> 3.0"
gem "rubocop-performance", "~> 1.14"
gem "rubocop-rspec", "~> 2.11"

gem "rake", "~> 13.1"

gem "rubocop-rake", "~> 0.6.0"
end
82 changes: 2 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ You can initialize a directory client as follows:
```ruby
require 'aserto/directory/client'

directory_client = Aserto::Directory::Client.new(
directory_client =Aserto::Directory::V3::Client.new(
url: "directory.eng.aserto.com:8443",
tenant_id: "aserto-tenant-id",
api_key: "basic directory api key",
Expand All @@ -44,85 +44,7 @@ directory_client = Aserto::Directory::Client.new(
- `tenant_id`: Aserto tenant ID (_required_ if using hosted directory)
- `cert_path`: Path to the grpc service certificate when connecting to local topaz instance.

### Getting objects and relations
Get an object instance with the type `type-name` and the key `object-key`. For example:

```ruby
user = directory_client.object(type: 'user', key: '[email protected]')
```

Get an array of relations of a certain type for an object instance. For example:

```ruby
identity = '[email protected]';
relations = directory_client.relation(
{
subject: {
type: 'user',
},
object: {
type: 'identity',
key: identity
},
relation: {
name: 'identifier',
objectType: 'identity'
}
}
)
```

### Setting objects and relations

Create a new object
```ruby
user = directory_client.set_object(object: { type: "user", key: "test-object", display_name: "test object" })
identity = directory_client.set_object(object: { type: "identity", key: "test-identity" })
```

Update an existing object
```ruby
user = directory_client.set_object(object: { type: "user", key: "test-object", display_name: "test object" })
user.display_name = 'test object edit'
updated_user = directory_client.set_object(object: user)
```

Create a new relation
```ruby
directory_client.set_relation(
subject: { type: "user", "test-object" },
relation: "identifier",
object: { type: "identity", key: "test-identity" }
)
```

Delete a relation
```ruby
pp client.delete_relation(
subject: { type: "user", key: "test-object" },
relation: { name: "identifier", object_type: "identity" },
object: { type: "identity", key: "test-identity" }
)
```

### Checking permissions and relations
Check permission
```ruby
directory_client.check_permission(
subject: { type: "user", key: "011a88bc-7df9-4d92-ba1f-2ff319e101e1" },
permission: { name: "read" },
object: { type: "group", key: "executive" }
)
```

Check relation
```ruby
directory_client.check_relation(
subject: { type: "user", key: "dfdadc39-7335-404d-af66-c77cf13a15f8" },
relation: { name: "identifier", object_type: "identity" },
object: { type: "identity", key: "[email protected]" }
)
```
See https://rubydoc.info/gems/aserto/docs/Aserto/Directory/V3/Client for full documentation

## Authorizer
`Aserto::Authorization` is a middleware that allows Ruby applications to use Aserto as the Authorization provider.
Expand Down
24 changes: 24 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

require "rake"
require "rspec/core/rake_task"
namespace :spec do
RSpec::Core::RakeTask.new(:unit) do |t|
t.pattern = Dir.glob("spec/aserto/**/*_spec.rb")
t.rspec_opts = "--format documentation"
end

RSpec::Core::RakeTask.new(:integration) do |t|
t.pattern = Dir.glob("spec/integration/**/*_spec.rb")
t.rspec_opts = "--format documentation"
end

desc "Run all tests"
task :all do
["spec:unit", "spec:integration"].each do |t|
Rake::Task[t].execute
end
end
end

task default: "spec:unit"
2 changes: 1 addition & 1 deletion aserto.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Gem::Specification.new do |spec|

# runtime dependencies
spec.add_runtime_dependency "aserto-authorizer", ">= 0.20.1"
spec.add_runtime_dependency "aserto-directory", ">= 0.30.0"
spec.add_runtime_dependency "aserto-directory", ">= 0.30.1"
spec.add_runtime_dependency "jwt", "~> 2.4"
spec.add_runtime_dependency "rack", "~> 2.0"
end
1 change: 1 addition & 0 deletions lib/aserto.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
require_relative "aserto/auth_client"
require_relative "aserto/errors"
require_relative "aserto/directory/client"
require_relative "aserto/directory/v3/client"

module Aserto
class << self
Expand Down
26 changes: 23 additions & 3 deletions lib/aserto/directory/interceptors/headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,31 @@ def initialize(api_key, tenant_id)
super()
end

def request_response(method:, request:, call:, metadata:)
def request_response(request: nil, call: nil, method: nil, metadata: nil)
update_metadata(metadata)
yield(request, call, method, metadata)
end

def bidi_streamer(requests: nil, call: nil, method: nil, metadata: nil)
update_metadata(metadata)
yield(requests, call, method, metadata)
end

def client_streamer(requests: nil, call: nil, method: nil, metadata: nil)
update_metadata(metadata)
yield(requests, call, method, metadata)
end

def server_streamer(request: nil, call: nil, method: nil, metadata: nil)
update_metadata(metadata)
yield(request, call, method, metadata)
end

private

def update_metadata(metadata)
metadata["aserto-tenant-id"] = @tenant_id
metadata["authorization"] = @api_key

yield(method, request, call, metadata)
end
end
end
Expand Down
114 changes: 114 additions & 0 deletions lib/aserto/directory/v3/client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# frozen_string_literal: true

require "aserto/directory"
require_relative "../interceptors/headers"
require_relative "config"
require_relative "reader"
require_relative "writer"
require_relative "model"
require_relative "importer"
require_relative "exporter"

module Aserto
module Directory
module V3
class Client
extend Forwardable
include ::Aserto::Directory::V3::Reader
# @!parse include ::Aserto::Directory::V3::Reader

include ::Aserto::Directory::V3::Writer
# @!parse include ::Aserto::Directory::V3::Writer

include ::Aserto::Directory::V3::Model
# @!parse include ::Aserto::Directory::V3::Model

include ::Aserto::Directory::V3::Importer
# @!parse include ::Aserto::Directory::V3::Importer

include ::Aserto::Directory::V3::Exporter
# @!parse include ::Aserto::Directory::V3::Exporter

# Creates a new Directory V3 Client
#
# @param config [Aserto::Directory::V3::Config] the service configuration
# Base configuration
# If non-nil, this configuration is used for any client that doesn't have its own configuration.
# If nil, only clients that have their own configuration will be created.
#
# @example Create a new Directory V3 Client with all the services
# client = Aserto::Directory::V3::Client.new(
# {
# url: "directory.eng.aserto.com:8443",
# tenant_id: "tenant-id",
# api_key: "basic api-key",
# }
# )
#
# @example Create a new Directory V3 Client with reader only
# client = Aserto::Directory::V3::Client.new(
# {
# reader: {
# url: "directory.eng.aserto.com:8443",
# tenant_id: "tenant-id",
# api_key: "basic api-key",
# }
# }
# )
#
# @return [Aserto::Directory::V3::Client] the new Directory V3 Client
def initialize(config)
base_config = ::Aserto::Directory::V3::Config.new(config)

@reader = create_client(:reader, base_config.reader)
@writer = create_client(:writer, base_config.writer)
@importer = create_client(:importer, base_config.importer)
@exporter = create_client(:exporter, base_config.exporter)
@model = create_client(:model, base_config.model)
end

private

attr_reader :reader, :writer, :model, :importer, :exporter

class NullClient
def initialize(name)
@name = name
end

def method_missing(method, *_args)
puts "Cannot call '#{method}': '#{@name.to_s.capitalize}' client is not initialized."
end

def respond_to_missing?(_name, _include_private)
true
end
end

SERVICE_MAP = {
reader: ::Aserto::Directory::Reader::V3::Reader::Stub,
writer: ::Aserto::Directory::Writer::V3::Writer::Stub,
importer: ::Aserto::Directory::Importer::V3::Importer::Stub,
exporter: ::Aserto::Directory::Exporter::V3::Exporter::Stub,
model: ::Aserto::Directory::Model::V3::Model::Stub
}.freeze

def create_client(type, config)
return NullClient.new(type) unless config

SERVICE_MAP[type].new(
config.url,
config.credentials,
interceptors: config.interceptors
)
end
end

remove_const(:Reader)
remove_const(:Writer)
remove_const(:Model)
remove_const(:Importer)
remove_const(:Exporter)
end
end
end
Loading

0 comments on commit 7308ecd

Please sign in to comment.