Skip to content
Open
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
49 changes: 46 additions & 3 deletions core/client/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,62 @@
package client

import (
"context"
"crypto/tls"

"github.com/Permify/permify-cli/core/config"
permify "github.com/Permify/permify-go/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
)

// New initializes a new permify client
// tokenAuth attaches a bearer token, retrieved from storage, to outgoing requests.
type tokenAuth struct {
token string
}

// GetRequestMetadata returns the authorization metadata for each request.
func (t tokenAuth) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
return map[string]string{"authorization": "Bearer " + t.token}, nil
}

// RequireTransportSecurity reports whether the token requires transport security.
func (tokenAuth) RequireTransportSecurity() bool {
return false
}

// transportCredentials builds the gRPC transport credentials from the stored
// certificate path and key. An insecure connection is used when no certificate
// is configured.
func transportCredentials(certPath, certKey string) (credentials.TransportCredentials, error) {
if certPath == "" || certKey == "" {
return insecure.NewCredentials(), nil
}
cert, err := tls.LoadX509KeyPair(certPath, certKey)
if err != nil {
return nil, err
}
return credentials.NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil
}

// New initializes a new permify client using the credentials stored in config.
func New(endpoint string) (*permify.Client, error) {
transportCreds, err := transportCredentials(config.CliConfig.CertPath, config.CliConfig.CertKey)
if err != nil {
return nil, err
}

opts := []grpc.DialOption{grpc.WithTransportCredentials(transportCreds)}
if config.CliConfig.Token != "" {
opts = append(opts, grpc.WithPerRPCCredentials(tokenAuth{token: config.CliConfig.Token}))
}

client, err := permify.NewClient(
permify.Config{
Endpoint: endpoint,
},
// Todo: Implement secure call with tls certificate
grpc.WithTransportCredentials(insecure.NewCredentials()),
opts...,
)
return client, err
}
42 changes: 42 additions & 0 deletions core/client/grpc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package client

import (
"context"
"path/filepath"
"testing"
)

func TestTransportCredentialsInsecureWhenNoCert(t *testing.T) {
creds, err := transportCredentials("", "")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if creds == nil {
t.Fatal("expected non-nil credentials")
}
if got := creds.Info().SecurityProtocol; got != "insecure" {
t.Fatalf("expected insecure security protocol, got %q", got)
}
}

func TestTransportCredentialsErrorsOnMissingCert(t *testing.T) {
dir := t.TempDir()
_, err := transportCredentials(filepath.Join(dir, "missing.crt"), filepath.Join(dir, "missing.key"))
if err == nil {
t.Fatal("expected error for missing certificate files")
}
}

func TestTokenAuthMetadata(t *testing.T) {
auth := tokenAuth{token: "secret"}
md, err := auth.GetRequestMetadata(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if md["authorization"] != "Bearer secret" {
t.Fatalf("unexpected authorization header: %q", md["authorization"])
}
if auth.RequireTransportSecurity() {
t.Fatal("expected RequireTransportSecurity to be false")
}
}
9 changes: 6 additions & 3 deletions core/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ type ProfileConfigs struct {

// CoreConfig is the config struct
type CoreConfig struct {
PermifyURL string `yaml:"permify_url"`
Tenant string `yaml:"tenant"`
SslEnabled bool `yaml:"-"`
PermifyURL string `yaml:"permify_url"`
Tenant string `yaml:"tenant"`
Token string `yaml:"token"`
CertPath string `yaml:"cert_path"`
CertKey string `yaml:"cert_key"`
SslEnabled bool `yaml:"-"`
}

// IsConfigured checks if permctl cli has been configured
Expand Down