Skip to content

Commit

Permalink
added authorized client API and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
woutslakhorst committed Nov 20, 2023
1 parent b878710 commit 6008f49
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 8 deletions.
48 changes: 40 additions & 8 deletions policy/api/v1/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/nuts-foundation/go-did/did"
"io"
"net/http"
"net/url"
"time"

"github.com/nuts-foundation/nuts-node/core"
Expand All @@ -48,20 +47,21 @@ func NewHTTPClient(strictMode bool, timeout time.Duration, tlsConfig *tls.Config
}

// PresentationDefinition retrieves the presentation definition from the presentation definition endpoint for the given scope and .
func (hb HTTPClient) PresentationDefinition(ctx context.Context, policyEndpoint string, authorizer did.DID, scopes string) (*pe.PresentationDefinition, error) {
presentationDefinitionURL, err := core.ParsePublicURL(policyEndpoint, hb.strictMode)
func (hb HTTPClient) PresentationDefinition(ctx context.Context, serverAddress string, authorizer did.DID, scopes string) (*pe.PresentationDefinition, error) {
_, err := core.ParsePublicURL(serverAddress, hb.strictMode)
if err != nil {
return nil, err
}
presentationDefinitionURL.Path = fmt.Sprintf("%s/presentation_definition", presentationDefinitionURL.Path)
presentationDefinitionURL.RawQuery = url.Values{"scope": []string{scopes}, "authorizer": []string{authorizer.String()}}.Encode()

// create a GET request with query params
request, err := http.NewRequestWithContext(ctx, http.MethodGet, presentationDefinitionURL.String(), nil)
client, err := NewClient(serverAddress, WithHTTPClient(hb.httpClient))
if err != nil {
return nil, err
}
response, err := hb.httpClient.Do(request.WithContext(ctx))
params := &PresentationDefinitionParams{
Scope: scopes,
Authorizer: authorizer.String(),
}
response, err := client.PresentationDefinition(ctx, params)
if err != nil {
return nil, fmt.Errorf("failed to call endpoint: %w", err)
}
Expand All @@ -81,3 +81,35 @@ func (hb HTTPClient) PresentationDefinition(ctx context.Context, policyEndpoint

return &presentationDefinition, nil
}

func (hb HTTPClient) Authorized(ctx context.Context, serverAddress string, request AuthorizedRequest) (bool, error) {
_, err := core.ParsePublicURL(serverAddress, hb.strictMode)
if err != nil {
return false, err
}

client, err := NewClient(serverAddress, WithHTTPClient(hb.httpClient))
if err != nil {
return false, err
}

response, err := client.CheckAuthorized(ctx, request)
if err != nil {
return false, fmt.Errorf("failed to call endpoint: %w", err)
}
if httpErr := core.TestResponseCode(http.StatusOK, response); httpErr != nil {
return false, httpErr
}

var authorized bool
var data []byte

if data, err = io.ReadAll(response.Body); err != nil {
return false, fmt.Errorf("unable to read response: %w", err)
}
if err = json.Unmarshal(data, &authorized); err != nil {
return false, fmt.Errorf("unable to unmarshal response: %w", err)
}

return authorized, nil
}
85 changes: 85 additions & 0 deletions policy/api/v1/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/nuts-foundation/nuts-node/vcr/pe"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"io"
"net/http"
"net/http/httptest"
"testing"
Expand Down Expand Up @@ -98,6 +99,90 @@ func TestHTTPClient_PresentationDefinition(t *testing.T) {
})
}

func TestHTTPClient_Authorized(t *testing.T) {
ctx := context.Background()
audience := did.MustParseDID("did:web:example.com:audience")
request := AuthorizedRequest{
Audience: audience.String(),
ClientId: "did:web:example.com:client",
PresentationSubmission: PresentationSubmission{},
RequestMethod: "GET",
RequestUrl: "/resource",
Scope: "test 1 2 3",
Vps: nil,
}

t.Run("ok", func(t *testing.T) {
var capturedRequest *http.Request
var capturedRequestBody []byte
handler := func(writer http.ResponseWriter, request *http.Request) {
switch request.URL.Path {
case "/authorized":
capturedRequest = request
capturedRequestBody, _ = io.ReadAll(request.Body)
writer.WriteHeader(http.StatusOK)
writer.Write([]byte("true"))
}
writer.WriteHeader(http.StatusNotFound)
}
tlsServer, client := testServerAndClient(t, http.HandlerFunc(handler))

response, err := client.Authorized(ctx, tlsServer.URL, request)

require.NoError(t, err)
assert.True(t, response)
require.NotNil(t, capturedRequest)
assert.Equal(t, "POST", capturedRequest.Method)
assert.Equal(t, "/authorized", capturedRequest.URL.Path)
// check body
require.NotNil(t, capturedRequest.Body)
var capturedRequestData AuthorizedRequest
err = json.Unmarshal(capturedRequestBody, &capturedRequestData)
require.NoError(t, err)
assert.Equal(t, request, capturedRequestData)
})
t.Run("error - not found", func(t *testing.T) {
handler := http2.Handler{StatusCode: http.StatusNotFound}
tlsServer, client := testServerAndClient(t, &handler)

response, err := client.Authorized(ctx, tlsServer.URL, request)

require.Error(t, err)
assert.EqualError(t, err, "server returned HTTP 404 (expected: 200)")
assert.False(t, response)
})
t.Run("error - invalid URL", func(t *testing.T) {
handler := http2.Handler{StatusCode: http.StatusNotFound}
_, client := testServerAndClient(t, &handler)

response, err := client.Authorized(ctx, ":", request)

require.Error(t, err)
assert.EqualError(t, err, "parse \":\": missing protocol scheme")
assert.False(t, response)
})
t.Run("error - invalid response", func(t *testing.T) {
handler := http2.Handler{StatusCode: http.StatusOK, ResponseData: "}"}
tlsServer, client := testServerAndClient(t, &handler)

response, err := client.Authorized(ctx, tlsServer.URL, request)

require.Error(t, err)
assert.EqualError(t, err, "unable to unmarshal response: invalid character '}' looking for beginning of value")
assert.False(t, response)
})
t.Run("error - invalid endpoint", func(t *testing.T) {
handler := http2.Handler{StatusCode: http.StatusOK}
_, client := testServerAndClient(t, &handler)

response, err := client.Authorized(ctx, "http://::1:1", request)

require.Error(t, err)
assert.EqualError(t, err, "failed to call endpoint: Post \"http://::1:1/authorized\": dial tcp [::1]:1: connect: connection refused")
assert.False(t, response)
})
}

func testServerAndClient(t *testing.T, handler http.Handler) (*httptest.Server, *HTTPClient) {
tlsServer := http2.TestTLSServer(t, handler)
return tlsServer, &HTTPClient{
Expand Down

0 comments on commit 6008f49

Please sign in to comment.