Skip to content

Commit

Permalink
add separate endpoint for APISIX
Browse files Browse the repository at this point in the history
  • Loading branch information
gerardsn committed Jun 13, 2024
1 parent 2176c63 commit bbfc356
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# golang alpine
FROM golang:1.22.3-alpine as builder
FROM golang:1.22.4-alpine as builder

ARG TARGETARCH
ARG TARGETOS
Expand Down
81 changes: 80 additions & 1 deletion api/opa/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package opa

import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/nuts-foundation/nuts-pxp/policy"
"strings"

"github.com/nuts-foundation/nuts-pxp/policy"
)

var _ StrictServerInterface = (*Wrapper)(nil)
Expand All @@ -13,6 +17,81 @@ type Wrapper struct {
DecisionMaker policy.DecisionMaker
}

func (w Wrapper) EvaluateDocumentApisix(ctx context.Context, request EvaluateDocumentApisixRequestObject) (EvaluateDocumentApisixResponseObject, error) {
// APISIX combines the 'openid-connect' and 'opa' plugin results into the following body:
//{
// "input": {
// "var": {
// "server_port": "9080",
// "remote_addr": "172.90.10.2",
// "timestamp": 1718289289,
// "remote_port": "54228",
// "server_addr": "172.90.10.12"
// },
// "type": "http",
// "request": {
// "scheme": "http",
// "method": "POST",
// "host": "pep-right",
// "query": {},
// "path": "/web/external/transfer/notify/21189b43-04d5-4f4f-86ed-e5ae21a87f84",
// "headers": {
// "X-Userinfo": "eyJvcmdhbml6YXRpb25fbmFtZSI6IkxlZnQiLCJzY29wZSI6ImVPdmVyZHJhY2h0LXJlY2VpdmVyIiwic3ViIjoiZGlkOndlYjpub2RlLnJpZ2h0LmxvY2FsOmlhbTpyaWdodCIsImV4cCI6MTcxODI5MDE4NiwiaWF0IjoxNzE4Mjg5Mjg2LCJpc3MiOiJkaWQ6d2ViOm5vZGUucmlnaHQubG9jYWw6aWFtOnJpZ2h0IiwiYWN0aXZlIjp0cnVlLCJjbGllbnRfaWQiOiJkaWQ6d2ViOm5vZGUubGVmdC5sb2NhbDppYW06bGVmdCIsIm9yZ2FuaXphdGlvbl9jaXR5IjoiR3JvZW5sbyJ9",
// "host": "pep-right:9080",
// "authorization": "Bearer TonUNXLwVn2UgJgVfpVDNa7WaXAlE2W-mS6CfqDzeP0",
// "content-length": "0",
// "user-agent": "go-resty/2.13.1 (https://github.com/go-resty/resty)",
// "X-Access-Token": "TonUNXLwVn2UgJgVfpVDNa7WaXAlE2W-mS6CfqDzeP0",
// "accept-encoding": "gzip",
// "content-type": "text/plain; charset=utf-8",
// "connection": "close"
// },
// "port": 9080
// }
// }
//}

input, ok := (*request.Body)["input"].(map[string]interface{})
if !ok {
return nil, errors.New("invalid request, missing 'input'")
}
httpRequest, ok := input["request"].(map[string]interface{})
if !ok {
return nil, errors.New("invalid request, missing 'input.request'")
}
httpHeaders, ok := httpRequest["headers"].(map[string]interface{})
if !ok {
return nil, errors.New("invalid request, missing 'input.request.headers'")
}
xUserinfoBase64, ok := httpHeaders["X-Userinfo"].(string)
if !ok {
return nil, errors.New("invalid request, missing 'input.request.headers.X-Userinfo is not a string'")
}
xUserinfoJSON, err := base64.URLEncoding.DecodeString(xUserinfoBase64)
if err != nil {
return nil, fmt.Errorf("invalid request, failed to base64 decode X-Userinfo: %w", err)
}
xUserinfo := map[string]interface{}{}
err = json.Unmarshal(xUserinfoJSON, &xUserinfo)
if err != nil {
return nil, fmt.Errorf("invalid request, failed to unmarshal X-Userinfo: %w", err)
}

descision, err := w.DecisionMaker.Query(ctx, httpRequest, xUserinfo)
if err != nil {
return nil, err
}

// Expected response by APISIX is of the form:
//{
// "result": {
// "allow": true
// }
//}
result := map[string]interface{}{"allow": descision}
return EvaluateDocumentApisix200JSONResponse{Result: result}, nil
}

func (w Wrapper) EvaluateDocument(ctx context.Context, request EvaluateDocumentRequestObject) (EvaluateDocumentResponseObject, error) {
// parse the requestLine and extract the method and path
// the requestLine is formatted as an HTTP request line
Expand Down
75 changes: 74 additions & 1 deletion api/opa/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/pip/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"context"
"errors"
"fmt"
"github.com/nuts-foundation/nuts-pxp/policy"
"net/http"
"os"
"os/signal"
Expand All @@ -35,6 +34,7 @@ import (
"github.com/nuts-foundation/nuts-pxp/api/pip"
"github.com/nuts-foundation/nuts-pxp/config"
"github.com/nuts-foundation/nuts-pxp/db"
"github.com/nuts-foundation/nuts-pxp/policy"
)

func main() {
Expand Down
2 changes: 1 addition & 1 deletion makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
run-generators: api

install-tools:
go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.1.0
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.3.0
go install go.uber.org/mock/[email protected]
go install github.com/golangci/golangci-lint/cmd/[email protected]

Expand Down
29 changes: 28 additions & 1 deletion oas/opa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Outcome'
/v1/data/apisix:
post:
operationId: evaluateDocumentApisix
summary: calls https://www.openpolicyagent.org/docs/latest/rest-api/#get-a-document-with-input internally
description: |
The given request and X-Userinfo headers are used to create the input document for the OPA policy.
tags:
- opa
requestBody:
content:
application/json:
schema:
type: object
responses:
'200':
description: Successful request. Returns the result of the OPA policy evaluation
content:
application/json:
schema:
$ref: '#/components/schemas/ApisixOutcome'
components:
schemas:
Outcome:
Expand All @@ -48,4 +68,11 @@ components:
allow:
type: boolean
description: The result of the OPA policy evaluation
example: true
example: true
ApisixOutcome:
type: object
required:
- result
properties:
result:
type: object

0 comments on commit bbfc356

Please sign in to comment.