Skip to content

Commit ce1e94a

Browse files
authored
Merge pull request #885 from Permify/next
Next
2 parents 8933ab6 + d769163 commit ce1e94a

File tree

4 files changed

+123
-32
lines changed

4 files changed

+123
-32
lines changed

internal/authn/preshared/authn.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,3 @@ func (a *KeyAuthn) Authenticate(ctx context.Context) error {
4848
}
4949
return status.Error(codes.Unauthenticated, base.ErrorCode_ERROR_CODE_INVALID_KEY.String())
5050
}
51-
52-
// Get Request Metadata - gets the current request metadata, refreshing tokens
53-
// if required
54-
func (a *KeyAuthn) GetRequestMetadata(_ context.Context, uri ...string) (map[string]string, error) {
55-
return map[string]string{
56-
"Authorization": "Bearer " + "test",
57-
}, nil
58-
}
59-
60-
// RequireTransportSecurity indicates whether the credentials requires
61-
// transport security.
62-
func (a *KeyAuthn) RequireTransportSecurity() bool {
63-
return true
64-
}

internal/engines/balancer/balancer.go

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"google.golang.org/grpc/credentials"
1313
"google.golang.org/grpc/credentials/insecure"
1414

15-
"github.com/Permify/permify/internal/authn/preshared"
1615
"github.com/Permify/permify/internal/config"
1716
"github.com/Permify/permify/internal/engines"
1817
"github.com/Permify/permify/internal/invoke"
@@ -34,22 +33,27 @@ type Balancer struct {
3433
options []grpc.DialOption
3534
}
3635

37-
// NewCheckEngineWithBalancer
38-
// struct with the provided cache.Cache instance.
36+
// NewCheckEngineWithBalancer creates a new check engine with a load balancer.
37+
// It takes a Check interface, SchemaReader, distributed config, gRPC config, and authn config as input.
38+
// It returns a Check interface and an error if any.
3939
func NewCheckEngineWithBalancer(
40+
ctx context.Context,
4041
checker invoke.Check,
4142
schemaReader storage.SchemaReader,
4243
dst *config.Distributed,
4344
srv *config.GRPC,
4445
authn *config.Authn,
4546
) (invoke.Check, error) {
46-
var err error
47-
48-
var options []grpc.DialOption
49-
50-
var creds credentials.TransportCredentials
47+
var (
48+
creds credentials.TransportCredentials
49+
options []grpc.DialOption
50+
isSecure bool
51+
err error
52+
)
5153

54+
// Set up TLS credentials if paths are provided
5255
if srv.TLSConfig.CertPath != "" && srv.TLSConfig.KeyPath != "" {
56+
isSecure = true
5357
creds, err = credentials.NewClientTLSFromFile(srv.TLSConfig.CertPath, srv.TLSConfig.KeyPath)
5458
if err != nil {
5559
return nil, fmt.Errorf("could not load TLS certificate: %s", err)
@@ -58,22 +62,26 @@ func NewCheckEngineWithBalancer(
5862
creds = insecure.NewCredentials()
5963
}
6064

61-
// TODO: Add client-side authentication using a key from KeyAuthn.
62-
// 1. Initialize the KeyAuthn structure using the provided configuration.
63-
// 2. Convert the KeyAuthn instance into PerRPCCredentials.
64-
// 3. Append grpc.WithPerRPCCredentials() to the options slice.
65-
createPresharedKeyAuthN, err := preshared.NewKeyAuthn(context.Background(), authn.Preshared)
66-
if err != nil {
67-
return nil, fmt.Errorf("could not create authentication key: %s", err)
68-
}
69-
65+
// Append common options
7066
options = append(
7167
options,
7268
grpc.WithDefaultServiceConfig(grpcServicePolicy),
7369
grpc.WithTransportCredentials(creds),
74-
grpc.WithPerRPCCredentials(createPresharedKeyAuthN),
7570
)
7671

72+
// Handle authentication if enabled
73+
if authn != nil && authn.Enabled {
74+
token, err := setupAuthn(ctx, authn)
75+
if err != nil {
76+
return nil, err
77+
}
78+
if isSecure {
79+
options = append(options, grpc.WithPerRPCCredentials(secureTokenCredentials{"authorization": "Bearer " + token}))
80+
} else {
81+
options = append(options, grpc.WithPerRPCCredentials(nonSecureTokenCredentials{"authorization": "Bearer " + token}))
82+
}
83+
}
84+
7785
conn, err := grpc.Dial(dst.Address, options...)
7886
if err != nil {
7987
return nil, err

internal/engines/balancer/utils.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package balancer
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"net/http"
8+
"net/url"
9+
"strings"
10+
11+
"github.com/Permify/permify/internal/config"
12+
)
13+
14+
// secureTokenCredentials represents a map used for storing secure tokens.
15+
// These tokens require transport security.
16+
type secureTokenCredentials map[string]string
17+
18+
// RequireTransportSecurity indicates that transport security is required for these credentials.
19+
func (c secureTokenCredentials) RequireTransportSecurity() bool {
20+
return true // Transport security is required for secure tokens.
21+
}
22+
23+
// GetRequestMetadata retrieves the current metadata (secure tokens) for a request.
24+
func (c secureTokenCredentials) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
25+
return c, nil // Returns the secure tokens as metadata with no error.
26+
}
27+
28+
// nonSecureTokenCredentials represents a map used for storing non-secure tokens.
29+
// These tokens do not require transport security.
30+
type nonSecureTokenCredentials map[string]string
31+
32+
// RequireTransportSecurity indicates that transport security is not required for these credentials.
33+
func (c nonSecureTokenCredentials) RequireTransportSecurity() bool {
34+
return false // Transport security is not required for non-secure tokens.
35+
}
36+
37+
// GetRequestMetadata retrieves the current metadata (non-secure tokens) for a request.
38+
func (c nonSecureTokenCredentials) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
39+
return c, nil // Returns the non-secure tokens as metadata with no error.
40+
}
41+
42+
// OIDCTokenResponse represents the response from the OIDC token endpoint
43+
type OIDCTokenResponse struct {
44+
AccessToken string `json:"access_token"`
45+
}
46+
47+
func getOIDCToken(ctx context.Context, issuer, clientID string) (string, error) {
48+
// Prepare the request data
49+
data := url.Values{}
50+
data.Set("client_id", clientID)
51+
data.Set("grant_type", "client_credentials")
52+
53+
// Create the request
54+
req, err := http.NewRequestWithContext(ctx, "POST", issuer+"/token", strings.NewReader(data.Encode()))
55+
if err != nil {
56+
return "", fmt.Errorf("error creating token request: %v", err)
57+
}
58+
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
59+
60+
// Send the request
61+
client := &http.Client{}
62+
resp, err := client.Do(req)
63+
if err != nil {
64+
return "", fmt.Errorf("error sending token request: %v", err)
65+
}
66+
defer resp.Body.Close()
67+
68+
// Decode the response
69+
var tokenResponse OIDCTokenResponse
70+
if err := json.NewDecoder(resp.Body).Decode(&tokenResponse); err != nil {
71+
return "", fmt.Errorf("error decoding token response: %v", err)
72+
}
73+
74+
return tokenResponse.AccessToken, nil
75+
}
76+
77+
// setupAuthn configures the authentication token based on the provided authentication method.
78+
// It returns the token string and an error if any.
79+
func setupAuthn(ctx context.Context, authn *config.Authn) (string, error) {
80+
var token string
81+
var err error
82+
83+
switch authn.Method {
84+
case "preshared":
85+
token = authn.Preshared.Keys[0]
86+
case "oidc":
87+
token, err = getOIDCToken(ctx, authn.Oidc.Issuer, authn.Oidc.ClientID)
88+
if err != nil {
89+
return "", fmt.Errorf("failed to get OIDC token: %s", err)
90+
}
91+
default:
92+
return "", fmt.Errorf("unknown authentication method: '%s'", authn.Method)
93+
}
94+
95+
return token, nil
96+
}

pkg/cmd/serve.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ func serve() func(cmd *cobra.Command, args []string) error {
236236
// Create the checker either with load balancing or caching capabilities.
237237
if cfg.Distributed.Enabled {
238238
checker, err = balancer.NewCheckEngineWithBalancer(
239+
context.Background(),
239240
checkEngine,
240241
schemaReader,
241242
&cfg.Distributed,

0 commit comments

Comments
 (0)