Skip to content

Commit

Permalink
fix up context
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Olivier <[email protected]>
  • Loading branch information
alexolivier committed Feb 7, 2025
1 parent 476b5f2 commit 09bf043
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,66 +8,80 @@ import (
"log"
"net/http"
"strings"
"time"

auth_pb "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
"github.com/golang-jwt/jwt/v5"
)

// PDP URLs
var pdps = map[string]string{
"Aserto": "http://authzen-gateway-proxy.demo.aserto.com",
"Aserto": "https://authzen-gateway-proxy.demo.aserto.com",
"Cerbos": "https://authzen-proxy-demo.cerbos.dev",
}

// AuthZENSubject represents the subject in the authorization request
type AuthZENSubject struct {
Type string `json:"type"`
ID string `json:"id"`
}

// AuthZENAction represents the action in the authorization request
type AuthZENAction struct {
Name string `json:"name"`
}

// AuthZENResource represents the resource in the authorization request
type AuthZENResource struct {
Type string `json:"type"`
ID string `json:"id"`
Properties map[string]any `json:"properties"`
}

// AuthZENRequest represents the authorization request payload
type AuthZENRequest struct {
Subject AuthZENSubject `json:"subject"`
Action AuthZENAction `json:"action"`
Resource AuthZENResource `json:"resource"`
Context map[string]any `json:"context"`
}

// AuthZENResponse represents the authorization response
type AuthZENResponse struct {
Decision bool `json:"decision"`
}

// AuthorizeRequest handles the authorization request to the PDP
func (server *AuthServer) AuthorizeRequest(ctx context.Context, request *auth_pb.CheckRequest) (bool, error) {

// Get PDP URL from request headers
pdpUrl := pdps[request.Attributes.Request.Http.Headers["x_authzen_gateway_pdp"]]
if pdpUrl == "" {
return false, fmt.Errorf("PDP not found: %s", request.Attributes.Request.Http.Headers["x_authzen_gateway_pdp"])
}
log.Printf("PDP URL: %s\n", pdpUrl)
log.Printf("Starting request to PDP: %s\n", pdpUrl)

// Extract user ID from authorization header
userId, err := extractSubFromBearer(request.Attributes.Request.Http.Headers["authorization"])
if err != nil {
log.Printf("Failed to extract user ID: %v\n", err)
return false, err
}

// Construct URL from request attributes
url := fmt.Sprint(request.Attributes.Request.Http.Scheme, "://", request.Attributes.Request.Http.Host, request.Attributes.Request.Http.Path)

// Match URL to path in OpenAPI spec
route, params, err := MatchURLToPath(server.openApiSpec, url)
if err != nil {
log.Printf("Failed to match URL to path: %v\n", err)
return false, err
}

log.Printf("Route: %s\n", route)
log.Printf("Params: %v\n", params)

// Create authorization request payload
authZENPayload := &AuthZENRequest{
Subject: AuthZENSubject{
Type: "user",
Expand All @@ -92,34 +106,57 @@ func (server *AuthServer) AuthorizeRequest(ctx context.Context, request *auth_pb
}

log.Printf("Sending request to %s", pdpUrl)
log.Printf("%+v\n", authZENPayload)

// Encode payload to JSON
payloadBuf := new(bytes.Buffer)
json.NewEncoder(payloadBuf).Encode(authZENPayload)
req, _ := http.NewRequestWithContext(ctx, "POST", fmt.Sprint(pdpUrl, "/access/v1/evaluation"), payloadBuf)
if err := json.NewEncoder(payloadBuf).Encode(authZENPayload); err != nil {
log.Printf("Failed to encode payload: %v\n", err)
return false, err
}
log.Printf("Payload: %+v\n", authZENPayload)

// Create HTTP request with context
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprint(pdpUrl, "/access/v1/evaluation"), payloadBuf)
if err != nil {
log.Printf("Failed to create request: %v\n", err)
return false, err
}
req.Header.Set("Content-Type", "application/json")

res, e := server.httpClient.Do(req)
if e != nil {
return false, e
// Send HTTP request with better error handling
startTime := time.Now()
res, err := server.httpClient.Do(req)
if err != nil {
if ctxErr := ctx.Err(); ctxErr != nil {
log.Printf("Context error during request: %v (request duration: %v)\n", ctxErr, time.Since(startTime))
return false, fmt.Errorf("context error during request: %v", ctxErr)
}
log.Printf("Failed to send request to PDP: %v (request duration: %v)\n", err, time.Since(startTime))
return false, fmt.Errorf("failed to send request to PDP: %v", err)
}
requestDuration := time.Since(startTime)
log.Printf("Request duration: %v\n", requestDuration)

if requestDuration > 5*time.Second {
log.Printf("Warning: Request took longer than 5 seconds")
}

defer res.Body.Close()

// Decode response with timeout
var authZENResponse AuthZENResponse
err = json.NewDecoder(res.Body).Decode(&authZENResponse)
if err != nil {
return false, err
if err := json.NewDecoder(res.Body).Decode(&authZENResponse); err != nil {
log.Printf("Failed to decode response: %v\n", err)
return false, fmt.Errorf("failed to decode response: %v", err)
}

log.Println("PDP response")
log.Printf("PDP response received and decoded in %v\n", time.Since(startTime))
log.Printf("%+v\n", authZENResponse)

return authZENResponse.Decision, nil

}

// extractSubFromBearer extracts the subject (sub) claim from the Bearer token
func extractSubFromBearer(authHeader string) (string, error) {
if authHeader == "" {
return "", fmt.Errorf("authorization header missing")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,71 @@ package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net"
"net/http"
"os"
"time"

auth_pb "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
envoy_type "github.com/envoyproxy/go-control-plane/envoy/type/v3"

"github.com/getkin/kin-openapi/openapi3"
"google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
)

type AuthServer struct {
httpClient *http.Client
openApiSpec openapi3.T
}

func denied(code int32, body string) *auth_pb.CheckResponse {
return &auth_pb.CheckResponse{
Status: &status.Status{Code: code},
HttpResponse: &auth_pb.CheckResponse_DeniedResponse{
DeniedResponse: &auth_pb.DeniedHttpResponse{
Status: &envoy_type.HttpStatus{
Code: envoy_type.StatusCode(code),
},
Body: body,
},
},
}
}

func allowed() *auth_pb.CheckResponse {
return &auth_pb.CheckResponse{
Status: &status.Status{Code: int32(codes.OK)},
HttpResponse: &auth_pb.CheckResponse_OkResponse{
OkResponse: &auth_pb.OkHttpResponse{},
},
}
}

func (server *AuthServer) Check(ctx context.Context, request *auth_pb.CheckRequest) (*auth_pb.CheckResponse, error) {
// Skip /pdps and OPTIONS requests

// Skip authorization for /pdps and OPTIONS
if request.Attributes.Request.Http.Path == "/pdps" || request.Attributes.Request.Http.Method == "OPTIONS" {
return &auth_pb.CheckResponse{
HttpResponse: &auth_pb.CheckResponse_OkResponse{
OkResponse: &auth_pb.OkHttpResponse{},
},
}, nil
return allowed(), nil
}

ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()

response, err := server.AuthorizeRequest(ctx, request)
if err != nil {
return nil, err
log.Printf("Authorization error: %v\n", err)
return denied(http.StatusUnauthorized, "unauthorized"), nil
}
log.Printf("Response: %v\n", response)

if response {
return &auth_pb.CheckResponse{}, nil
} else {
return nil, fmt.Errorf("Not allowed")
if !response {
return denied(http.StatusUnauthorized, "unauthorized"), nil
}

return allowed(), nil
}

func main() {
Expand Down Expand Up @@ -74,7 +102,7 @@ func main() {

server := &AuthServer{
httpClient: &http.Client{
Timeout: time.Second,
Timeout: time.Second * 10,
},
openApiSpec: openApiSpec,
}
Expand Down
17 changes: 12 additions & 5 deletions interop/authzen-api-gateways/envoy-gateway/envoy/envoy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ static_resources:
envoy.filters.http.cors:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy
allow_origin_string_match:
- safe_regex:
regex: \*
- prefix: "*"
allow_methods: "GET,POST,PUT,PATCH,DELETE,OPTIONS"
allow_headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,Access-Control-Allow-Origin,x_authzen_gateway_pdp,x_authzen_pdp,x_authzen_spec_version"
allow_headers: "*"
allow_credentials: true
max_age: "1728000"
routes:
Expand All @@ -46,13 +45,21 @@ static_resources:
grpc_service:
envoy_grpc:
cluster_name: go_grpc_cluster
timeout: 10s
failure_mode_allow: false
with_request_body:
max_request_bytes: 8192
allow_partial_message: true
pack_as_bytes: true
status_on_error:
code: 503
include_peer_certificate: true
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: go_grpc_cluster
connect_timeout: 1s
connect_timeout: 5s
type: LOGICAL_DNS
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
Expand All @@ -66,7 +73,7 @@ static_resources:
- endpoint:
address:
socket_address:
address: 0.0.0.0
address: 127.0.0.1
port_value: 3001
- name: backend_cluster
type: LOGICAL_DNS
Expand Down

0 comments on commit 09bf043

Please sign in to comment.