Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setup directory v3 client #13

Merged
merged 22 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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