Skip to content

Commit

Permalink
Merge pull request #6 from nuts-foundation/changes-for-apisix-pep
Browse files Browse the repository at this point in the history
Add separate endpoint for APISIX
  • Loading branch information
gerardsn authored Jul 17, 2024
2 parents 6f16888 + 86dd850 commit 51183bf
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 97 deletions.
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# golang alpine
FROM golang:1.22.5-alpine as builder
FROM golang:1.22.5-alpine AS builder

ARG TARGETARCH
ARG TARGETOS
Expand All @@ -12,8 +12,8 @@ RUN apk update \
musl-dev \
&& update-ca-certificates

ENV GO111MODULE on
ENV GOPATH /
ENV GO111MODULE=on
ENV GOPATH=/

RUN mkdir /opt/nuts-pxp && cd /opt/nuts-pxp
COPY go.mod .
Expand Down
106 changes: 87 additions & 19 deletions api/opa/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package opa

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

var _ StrictServerInterface = (*Wrapper)(nil)
Expand All @@ -13,32 +15,98 @@ type Wrapper struct {
DecisionMaker policy.DecisionMaker
}

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
// e.g. "GET /api/v1/resource HTTP/1.1"
// we are only interested in the method and path
method, path, err := parseRequestLine(request.Params.Request)
func (w Wrapper) EvaluateDocumentApisix(ctx context.Context, request EvaluateDocumentApisixRequestObject) (EvaluateDocumentApisixResponseObject, error) {
if request.Body == nil {
return nil, errors.New("missing body")
}
// 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
// }
// }
//}
outcome, err := w.handleEvaluate(ctx, *request.Body)
if err != nil {
return nil, err
}
httpRequest := map[string]interface{}{}
httpRequest["method"] = method
httpRequest["path"] = path

descision, err := w.DecisionMaker.Query(ctx, httpRequest, request.Params.XUserinfo)
// Expected response by APISIX is of the form:
//{
// "result": {
// "allow": true
// }
//}
return EvaluateDocumentApisix200JSONResponse(*outcome), nil
}

func (w Wrapper) EvaluateDocument(ctx context.Context, request EvaluateDocumentRequestObject) (EvaluateDocumentResponseObject, error) {
if request.Body == nil {
return nil, errors.New("missing body")
}
//fmt.Printf("%v\n", *request.Body)

outcome, err := w.handleEvaluate(ctx, *request.Body)
if err != nil {
return nil, err
}
return EvaluateDocument200JSONResponse{Allow: descision}, nil

return EvaluateDocument200JSONResponse(*outcome), nil
}

// parseRequestLine parses the request line and extracts the method and path
// e.g. "GET /api/v1/resource HTTP/1.1" -> "GET", "/api/v1/resource"
func parseRequestLine(requestLine string) (method, path string, err error) {
parts := strings.Split(requestLine, " ")
if len(parts) != 3 {
return "", "", fmt.Errorf("invalid request line: %s", requestLine)
func (w Wrapper) handleEvaluate(ctx context.Context, input Input) (*Outcome, error) {

httpRequest, ok := input.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)
}

decision, err := w.DecisionMaker.Query(ctx, httpRequest, xUserinfo)
if err != nil {
return nil, err
}
return parts[0], parts[1], nil
return &Outcome{Result: map[string]interface{}{"allow": decision}}, nil
}
137 changes: 83 additions & 54 deletions 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
Loading

0 comments on commit 51183bf

Please sign in to comment.