Skip to content

Commit

Permalink
Directory Client (#7)
Browse files Browse the repository at this point in the history
* Add directory client

* update readme

* Move directory client to /v2

* Update linter

* move test files to _test package namespace

---------

Co-authored-by: Gert Drapers <gert.drapers@live.com>
  • Loading branch information
ronenh and gertd committed Oct 16, 2023
1 parent 628bb2b commit 11d6408
Show file tree
Hide file tree
Showing 36 changed files with 881 additions and 266 deletions.
22 changes: 8 additions & 14 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,17 @@ jobs:
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Install Tools
run: |
mkdir -p $HOME/.ssh
umask 0077 && echo -e "${SSH_PRIVATE_KEY}" > $HOME/.ssh/id_rsa
ssh-keyscan github.com >> $HOME/.ssh/known_hosts
git config --global url."git@github.com:".insteadOf https://github.com/
git config --global user.email "github-bot@aserto.com"
git config --global user.name "Aserto Bot"
eval `ssh-agent`
ssh-add $HOME/.ssh/id_rsa
go run mage.go deps
- name: Lint
run: |
go run mage.go lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.53.2
- name: Test Setup
uses: autero1/action-gotestsum@v2.0.0
with:
gotestsum_version: 1.10.0
- name: Test
run: |
go run mage.go test
gotestsum --format short-verbose -- -count=1 -v -timeout=240s -coverprofile=cover.out -coverpkg=./... ./...
- name: Upload code coverage
uses: shogo82148/actions-goveralls@v1
continue-on-error: true
Expand Down
14 changes: 5 additions & 9 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@

linters-settings:
depguard:
list-type: blacklist
packages:
# logging is allowed only by zerolog
- github.com/sirupsen/logrus
packages-with-error-message:
- github.com/sirupsen/logrus: "logging is allowed only by zerolog"
rules:
Main:
deny:
- pkg: github.com/sirupsen/logrus
desc: "logging is allowed only by zerolog"
dupl:
threshold: 100
funlen:
Expand Down Expand Up @@ -69,7 +68,6 @@ linters:
enable:
- asciicheck
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
Expand Down Expand Up @@ -104,14 +102,12 @@ linters:
- revive
- rowserrcheck
- staticcheck
- structcheck
- stylecheck
- testpackage
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
- wsl

Expand Down
6 changes: 3 additions & 3 deletions Depfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ bin:
linux-arm64: "e57e719e1eec9bce9057751e2583907210d3ac99c0a01897479506fbb2af828d"
darwin-amd64: "b398481bf33ebf9563cf69d7639014f0d652a2d5e26c0a9a424e2a39bb853354"
darwin-arm64: "20aead134ef8e77cb70efcfe047fc2e381793004fba103e7692b7dab00fe5131"

go:
gotestsum:
importPath: "gotest.tools/gotestsum"
version: "v1.7.0"
version: "v1.10.1"
golangci-lint:
importPath: "github.com/golangci/golangci-lint/cmd/golangci-lint"
version: "v1.46.2"
version: "v1.53.2"
147 changes: 138 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/aserto-dev/go-aserto.svg)](https://pkg.go.dev/github.com/aserto-dev/go-aserto)
[![Go Report Card](https://goreportcard.com/badge/github.com/aserto-dev/go-aserto)](https://goreportcard.com/report/github.com/aserto-dev/go-aserto)

Package `go-aserto` implements clients and middleware for the [Aserto](http://aserto.com) authorizer and supporting services.

Authorization requests are performed using an AuthorizerClient.
A client can be used on its own to make authorization calls or, more commonly, it can be used to create server middleware.
Package `go-aserto` implements clients and middleware for [Aserto](http://aserto.com) services.

* Docs: https://docs.aserto.com/docs/
* API Reference: https://aserto.readme.io/
Expand All @@ -19,10 +16,17 @@ A client can be used on its own to make authorization calls or, more commonly, i
go get -u github.com/aserto-dev/go-aserto
```

## AuthorizerClient
## Authorizer

The [Authorizer](https://docs.aserto.com/docs/overview/authorizer) service is is an [open source authorization engine](https://www.topaz.sh)
which uses the [Open Policy Agent](https://www.openpolicyagent.org) (OPA) to make decisions by computing authorization
policies.


### AuthorizerClient

The `AuthorizerClient` interface, defined in
[`"github.com/aserto-dev/go-authorizer/aserto/authorizer/v2"`](https://github.com/aserto-dev/go-authorizer/blob/main/aserto/authorizer/v2/authorizer_grpc.pb.go#L24),
[`github.com/aserto-dev/go-authorizer/aserto/authorizer/v2`](https://github.com/aserto-dev/go-authorizer/blob/main/aserto/authorizer/v2/authorizer_grpc.pb.go#L34),
describes the operations exposed by the Aserto authorizer service.

Two implementation of `AuthorizerClient` are available:
Expand Down Expand Up @@ -81,7 +85,7 @@ authorizer, err := grpc.New(
```


### Make Authorization Calls
### Making Authorization Calls

Use the client's `Is()` method to request authorization decisions from the Aserto authorizer service.

Expand All @@ -103,6 +107,131 @@ resp, err := authorizer.Is(c.Context, &authz.IsRequest{
})
```

## Directory

The [Directory](https://docs.aserto.com/docs/overview/directory) stores information required to make authorization
decisions.


### Directory Client

The directory client provides access to the directory services:

1. Reader - provides functions to query the directory.
2. Writer - provides functions to mutate or delete directory data.
3. Exporter - provides bulk export of data from the directory.
4. Importer - provides bulk import of data into the directory.


To create a directory client:

```go

import (
"context"
"github.com/aserto-dev/go-aserto/client"
"github.com/aserto-dev/go-aserto/client/directory/v2"
)

...

dir, err := directory.New(context.Background(), client.WithAPIKeyAuth('<api key>'))
```

[Connection options](#connection-options) are the same as those for the authorizer client.
If `WithAddr()` is not provided, the default address is `directory.prod.aserto.com:8443`.


### Configuration

The hosted Aserto directory exposes all services on the same address (`directory.prod.aserto.com:8443`).
However, with Topaz or in self-hosted environments, it is possible to configure the services individually and to
disable selected services entirely.

The `directory.Config` structs allows for customization of connection options for directory services.

```go
// Config provides configuration for connecting to the Aserto Directory service.
type Config struct {
// 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.
*client.Config

// Reader configuration.
Reader *client.Config `json:"reader"`

// Writer configuration.
Writer *client.Config `json:"writer"`

// Importer configuration.
Importer *client.Config `json:"importer"`

// Exporter configuration.
Exporter *client.Config `json:"exporter"`
}
```

The embedded `*client.Config` acts as a fallback. If no configuration is provided for a specific service, the fallback
configuration is used. If no fallback is provided, the client for that service is nil.

To create a directory client from configuration, call `Connect(context.Context)` on the config struct:

```go
import (
"context"

"github.com/aserto-dev/go-aserto/client/directory/v2"
"github.com/aserto-dev/go-directory/aserto/directory/common/v2"
"github.com/aserto-dev/go-directory/aserto/directory/reader/v2"
)

...

// Use the same address for all services.
cfg := &directory.Config{Address: "localhost:9292"}

dir, err := cfg.Connect(context.Background())
if err != nil {
panic(err)
}

resp, err := dir.Reader.GetObjects(&reader.GetObjectsRequest{})
```

**Examples**

All services use the same configuration:
```json
{
"address": "directory.prod.aserto.com:8443",
"api_key": "<API-KEY>",
"tenant_id": "<TENANT-ID>"
}
```


All services use the same configuration except for the writer, that uses a different address:
```json
{
"address": "localhost:9292",
"writer": {
"address": "localhost:9293"
}
}
```

Only a reader and writer are configured. `Client.Importer` and `Client.Exporter` are nil:
```json
{
"reader": {
"address": "localhost:9292"
},
"writer": {
"address": "localhost:9293"
}
}
```


## Middleware

Expand Down Expand Up @@ -132,7 +261,7 @@ type Policy struct {
// Decision is the authorization rule to use.
Decision string

// Label name of the aserto policy's instance being queried for authorization.
// Label name of the aserto policy's instance being queried for authorization.
InstanceLabel string
}
```
Expand Down Expand Up @@ -373,4 +502,4 @@ type Client struct {
// Authorizer provides methods for performing authorization requests.
Authorizer authorizer.AuthorizerClient
}
```
```
2 changes: 1 addition & 1 deletion authorizer/http/authorizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func (a *authorizer) ListPolicies(

func (a *authorizer) Info(
ctx context.Context,
in *authz.InfoRequest,
_ *authz.InfoRequest,
opts ...grpc.CallOption,
) (*authz.InfoResponse, error) {
var paths []string
Expand Down
6 changes: 3 additions & 3 deletions client/authorizer/authorizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/aserto-dev/go-aserto/client"
"google.golang.org/grpc"

"github.com/aserto-dev/go-authorizer/aserto/authorizer/v2"
authz "github.com/aserto-dev/go-authorizer/aserto/authorizer/v2"

"github.com/pkg/errors"
)
Expand All @@ -16,7 +16,7 @@ type Client struct {
conn *client.Connection

// Authorizer provides methods for performing authorization requests.
Authorizer authorizer.AuthorizerClient
Authorizer authz.AuthorizerClient
}

// NewClient creates a Client with the specified connection options.
Expand All @@ -28,7 +28,7 @@ func New(ctx context.Context, opts ...client.ConnectionOption) (*Client, error)

return &Client{
conn: connection,
Authorizer: authorizer.NewAuthorizerClient(connection.Conn),
Authorizer: authz.NewAuthorizerClient(connection.Conn),
}, err
}

Expand Down
41 changes: 21 additions & 20 deletions client/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,21 @@ context, the default connection timeout is 5 seconds. For example, to increase t
)
*/
func NewConnection(ctx context.Context, opts ...ConnectionOption) (*Connection, error) {
return newConnection(ctx, dialContext, opts...)
options, err := NewConnectionOptions(opts...)
if err != nil {
return nil, err
}

if options.ServerAddress() == "" {
// Backward compatibility: default to authorizer service.
options.Address = hosted.HostedAuthorizerHostname + hosted.HostedAuthorizerGRPCPort
}

return Connect(ctx, options)
}

func Connect(ctx context.Context, options *ConnectionOptions) (*Connection, error) {
return newConnection(ctx, dialContext, options)
}

// dialer is introduced in order to test the logic responsible for configuring the underlying gRPC connection
Expand All @@ -96,6 +110,10 @@ func dialContext(
connection *Connection,
options []grpc.DialOption,
) (grpc.ClientConnInterface, error) {
if address == "" {
return nil, errors.Wrap(ErrInvalidOptions, "address not specified")
}

dialOptions := []grpc.DialOption{
grpc.WithTransportCredentials(credentials.NewTLS(tlsConf)),
grpc.WithBlock(),
Expand All @@ -115,12 +133,7 @@ func dialContext(
)
}

func newConnection(ctx context.Context, dialContext dialer, opts ...ConnectionOption) (*Connection, error) {
options, err := NewConnectionOptions(opts...)
if err != nil {
return nil, err
}

func newConnection(ctx context.Context, dialContext dialer, options *ConnectionOptions) (*Connection, error) {
tlsConf, err := tlsconf.TLSConfig(options.Insecure, options.CACertPath)
if err != nil {
return nil, errors.Wrap(err, "failed to setup tls configuration")
Expand Down Expand Up @@ -148,7 +161,7 @@ func newConnection(ctx context.Context, dialContext dialer, opts ...ConnectionOp

conn, err := dialContext(
ctx,
serverAddress(options),
options.ServerAddress(),
tlsConf,
options.Creds,
connection,
Expand Down Expand Up @@ -202,15 +215,3 @@ func SetSessionContext(ctx context.Context, sessionID string) context.Context {

return metadata.AppendToOutgoingContext(ctx, string(header.HeaderAsertoSessionID), sessionID)
}

func serverAddress(opts *ConnectionOptions) string {
if opts.URL != nil {
return opts.URL.String()
}

if opts.Address != "" {
return opts.Address
}

return hosted.HostedAuthorizerHostname + hosted.HostedAuthorizerGRPCPort
}
Loading

0 comments on commit 11d6408

Please sign in to comment.