Skip to content

Commit

Permalink
VCR: Fix validator allowing localParameters (#1677) (#1737)
Browse files Browse the repository at this point in the history
  • Loading branch information
reinkrul authored Dec 6, 2022
1 parent 3265ca6 commit e2847c8
Show file tree
Hide file tree
Showing 15 changed files with 334 additions and 172 deletions.
122 changes: 61 additions & 61 deletions README.rst

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/pages/deployment/server_options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
http.default.auth.type Whether to enable authentication for the default interface, specify 'token' for bearer token authentication.
http.default.cors.origin [] When set, enables CORS from the specified origins on the default HTTP interface.
**JSONLD**
jsonld.contexts.localmapping [https://schema.org=assets/contexts/schema-org-v13.ldjson,https://nuts.nl/credentials/v1=assets/contexts/nuts.ldjson,https://www.w3.org/2018/credentials/v1=assets/contexts/w3c-credentials-v1.ldjson,https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json=assets/contexts/lds-jws2020-v1.ldjson] This setting allows mapping external URLs to local files for e.g. preventing external dependencies. These mappings have precedence over those in remoteallowlist.
jsonld.contexts.localmapping [https://nuts.nl/credentials/v1=assets/contexts/nuts.ldjson,https://www.w3.org/2018/credentials/v1=assets/contexts/w3c-credentials-v1.ldjson,https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json=assets/contexts/lds-jws2020-v1.ldjson,https://schema.org=assets/contexts/schema-org-v13.ldjson] This setting allows mapping external URLs to local files for e.g. preventing external dependencies. These mappings have precedence over those in remoteallowlist.
jsonld.contexts.remoteallowlist [https://schema.org,https://www.w3.org/2018/credentials/v1,https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json] In strict mode, fetching external JSON-LD contexts is not allowed except for context-URLs listed here.
**Network**
network.bootstrapnodes [] List of bootstrap nodes ('<host>:<port>') which the node initially connect to.
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/technology/jsonld.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ Within Verifiable Credentials, JSON-LD is used to convert it to a normalized doc
Nuts Context V1
***************

https://raw.githubusercontent.com/nuts-foundation/nuts-node/master/vcr/assets/assets/contexts/nuts.ldjson
https://nuts.nl/credentials/v1
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ require (
github.com/nuts-foundation/go-did v0.3.0
github.com/nuts-foundation/go-leia/v3 v3.3.0
github.com/nuts-foundation/go-stoabs v1.4.0
github.com/piprate/json-gold v0.4.2
github.com/piprate/json-gold v0.5.1-0.20221121142341-01873264bae4
github.com/privacybydesign/irmago v0.10.0
github.com/prometheus/client_golang v1.13.1
github.com/prometheus/client_model v0.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,8 @@ github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI=
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/piprate/json-gold v0.4.2 h1:Rq8V+637HOFcj20KdTqW/g/llCwX2qtau0g5d1pD79o=
github.com/piprate/json-gold v0.4.2/go.mod h1:OK1z7UgtBZk06n2cDE2OSq1kffmjFFp5/2yhLLCz9UM=
github.com/piprate/json-gold v0.5.1-0.20221121142341-01873264bae4 h1:fnJ3Tf9WZpggydknuvrB9rHs9uHQGi6J4EbbGifSz/g=
github.com/piprate/json-gold v0.5.1-0.20221121142341-01873264bae4/go.mod h1:WZ501QQMbZZ+3pXFPhQKzNwS1+jls0oqov3uQ2WasLs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down
140 changes: 140 additions & 0 deletions jsonld/testsuite/compat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package testsuite

import (
"crypto/x509"
"encoding/json"
"encoding/pem"
"github.com/nuts-foundation/nuts-node/crypto"
"github.com/nuts-foundation/nuts-node/jsonld"
"github.com/nuts-foundation/nuts-node/vcr/signature"
"github.com/nuts-foundation/nuts-node/vcr/signature/proof"
"github.com/piprate/json-gold/ld"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"os"
"strings"
"testing"
"time"
)

type testCase struct {
name string
file string
}

var testCases = []testCase{
// Note: there is no test for an NutsAuthorizationCredential with localParameters,
// because localParameters in v1.1 aren't compatible with v1.0 since its type changed from @graph to @json.
// This is not a problem, because nobody actually used it in v1.0.
{
name: "NutsAuthorizationCredential",
file: "authcred_001.ldjson",
},
{
name: "NutsOrganizationCredential",
file: "orgcred_001.ldjson",
},
}

// TestCompatibility tests backwards compatibility of the Nuts JSON-LD context.
// It uses the test cases found in ./fixtures and checks the signature against every Nuts JSON-LD context version.
func TestCompatibility(t *testing.T) {
key := readSigningKey(t)
type context struct {
version string
loader ld.DocumentLoader
}
contexts := []context{
{
version: "1.0",
loader: jsonld.NewMappedDocumentLoader(map[string]string{
"https://nuts.nl/credentials/v1": "../../vcr/assets/assets/contexts/nuts.ldjson",
jsonld.W3cVcContext: "../../vcr/assets/assets/contexts/w3c-credentials-v1.ldjson",
jsonld.Jws2020Context: "../../vcr/assets/assets/contexts/lds-jws2020-v1.ldjson",
}, ld.NewDefaultDocumentLoader(nil)),
},
}

for _, ctx := range contexts {
t.Run(ctx.version, func(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.file, func(t *testing.T) {
data, err := os.ReadFile("./fixtures/" + tc.file)
require.NoError(t, err)
var document proof.SignedDocument
err = json.Unmarshal(data, &document)
require.NoError(t, err)

ldProof := proof.LDProof{}
err = document.UnmarshalProofValue(&ldProof)
require.NoError(t, err)
err = ldProof.Verify(document.DocumentWithoutProof(), signature.JSONWebSignature2020{ContextLoader: ctx.loader}, key.Public())
assert.NoError(t, err)
})
}
})
}
}

// TestGenerateSignedFixtures is used to generate signed test fixtures of the unsigned test cases.
// It's only there as runnable unit test to assert it keeps working.
func TestGenerateSignedFixtures(t *testing.T) {
const saveSigned = false

loader := jsonld.NewMappedDocumentLoader(map[string]string{
"https://nuts.nl/credentials/v1": "../../vcr/assets/assets/contexts/nuts.ldjson",
jsonld.W3cVcContext: "../../vcr/assets/assets/contexts/w3c-credentials-v1.ldjson",
jsonld.Jws2020Context: "../../vcr/assets/assets/contexts/lds-jws2020-v1.ldjson",
}, ld.NewDefaultDocumentLoader(nil))

privateKey := readSigningKey(t)

for _, testCase := range testCases {
t.Run(testCase.file, func(t *testing.T) {
unsignedFile := "./fixtures/" + strings.ReplaceAll(testCase.file, ".ldjson", "_unsigned.ldjson")
data, err := os.ReadFile(unsignedFile)
require.NoError(t, err)

var tbs proof.Document
err = json.Unmarshal(data, &tbs)
require.NoError(t, err)

signed, err := proof.NewLDProof(proof.ProofOptions{
Created: time.Now(),
}).Sign(tbs, signature.JSONWebSignature2020{ContextLoader: loader}, privateKey)
require.NoError(t, err)

var targetFile = "./fixtures/" + testCase.file
// If not saving, still save it (although to temp dir) to it keeps working
if !saveSigned {
tempFile, err := os.CreateTemp("", testCase.file)
defer func() {
_ = os.Remove(tempFile.Name())
}()
require.NoError(t, err)
_ = tempFile.Close()
targetFile = tempFile.Name()
}
signedBytes, err := json.MarshalIndent(signed, "", " ")
require.NoError(t, err)
// Copy file mode from unsigned file
fileInfo, err := os.Stat(unsignedFile)
require.NoError(t, err)
err = os.WriteFile(targetFile, signedBytes, fileInfo.Mode())
require.NoError(t, err)
println("Written to", targetFile)
})
}
}

func readSigningKey(t *testing.T) crypto.Key {
pkPEMBytes, err := os.ReadFile("private_key.pem")
require.NoError(t, err)
pkDerBytes, _ := pem.Decode(pkPEMBytes)
privateKey, err := x509.ParseECPrivateKey(pkDerBytes.Bytes)
require.NoError(t, err)
return crypto.TestKey{
PrivateKey: privateKey,
Kid: "key-id",
}
}
34 changes: 34 additions & 0 deletions jsonld/testsuite/fixtures/authcred_001.ldjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://nuts.nl/credentials/v1",
"https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json"
],
"credentialSubject": {
"id": "did:nuts:B8PUHs2AUHbFF1xLLK4eZjgErEcMXHxs68FteY7NDtCY",
"purposeOfUse": "eTransfer",
"resources": [
{
"operations": [
"read"
],
"path": "/composition/1",
"userContext": true
}
]
},
"id": "did:nuts:GvkzxsezHvEc8nGhgz6Xo3jbqkHwswLmWw3CYtCm7hAW#1",
"issuanceDate": "2022-11-25T09:44:16.972576+01:00",
"issuer": "did:nuts:GvkzxsezHvEc8nGhgz6Xo3jbqkHwswLmWw3CYtCm7hAW",
"proof": {
"created": "2022-12-05T13:47:24.714488+01:00",
"jws": "eyJhbGciOiJFUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..8fD_JGQiYLvryd3EPUR7ft41piyqm0rs8_3jYVLZjgld4q9YIjPus-nAE1f4473oo4xh9PW_khbRJaiU-twBMw",
"proofPurpose": "assertionMethod",
"type": "JsonWebSignature2020",
"verificationMethod": "key-id"
},
"type": [
"NutsAuthorizationCredential",
"VerifiableCredential"
]
}
27 changes: 27 additions & 0 deletions jsonld/testsuite/fixtures/authcred_001_unsigned.ldjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://nuts.nl/credentials/v1",
"https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json"
],
"credentialSubject": {
"id": "did:nuts:B8PUHs2AUHbFF1xLLK4eZjgErEcMXHxs68FteY7NDtCY",
"purposeOfUse": "eTransfer",
"resources": [
{
"operations": [
"read"
],
"path": "/composition/1",
"userContext": true
}
]
},
"id": "did:nuts:GvkzxsezHvEc8nGhgz6Xo3jbqkHwswLmWw3CYtCm7hAW#1",
"issuanceDate": "2022-11-25T09:44:16.972576+01:00",
"issuer": "did:nuts:GvkzxsezHvEc8nGhgz6Xo3jbqkHwswLmWw3CYtCm7hAW",
"type": [
"NutsAuthorizationCredential",
"VerifiableCredential"
]
}
28 changes: 28 additions & 0 deletions jsonld/testsuite/fixtures/orgcred_001.ldjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"@context": [
"https://nuts.nl/credentials/v1",
"https://www.w3.org/2018/credentials/v1",
"https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json"
],
"credentialSubject": {
"id": "did:nuts:CuE3qeFGGLhEAS3gKzhMCeqd1dGa9at5JCbmCfyMU2Ey",
"organization": {
"city": "IJbergen",
"name": "Because we care B.V."
}
},
"id": "did:nuts:CuE3qeFGGLhEAS3gKzhMCeqd1dGa9at5JCbmCfyMU2Ey#ec8af8cf-67d4-4b54-9bd6-8a861e729e11",
"issuanceDate": "2022-06-01T15:34:40.65319+02:00",
"issuer": "did:nuts:CuE3qeFGGLhEAS3gKzhMCeqd1dGa9at5JCbmCfyMU2Ey",
"proof": {
"created": "2022-12-05T13:47:24.717922+01:00",
"jws": "eyJhbGciOiJFUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..WyQ-9rd323hXQLgceVAA4eRf1PHwK58dMu_Ugsl63i4WPCj6gNsZQ173qneetZYzNl5IMZWgtuZMGkB5tg-lag",
"proofPurpose": "assertionMethod",
"type": "JsonWebSignature2020",
"verificationMethod": "key-id"
},
"type": [
"NutsOrganizationCredential",
"VerifiableCredential"
]
}
21 changes: 21 additions & 0 deletions jsonld/testsuite/fixtures/orgcred_001_unsigned.ldjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"@context": [
"https://nuts.nl/credentials/v1",
"https://www.w3.org/2018/credentials/v1",
"https://w3c-ccg.github.io/lds-jws2020/contexts/lds-jws2020-v1.json"
],
"credentialSubject": {
"id": "did:nuts:CuE3qeFGGLhEAS3gKzhMCeqd1dGa9at5JCbmCfyMU2Ey",
"organization": {
"city": "IJbergen",
"name": "Because we care B.V."
}
},
"id": "did:nuts:CuE3qeFGGLhEAS3gKzhMCeqd1dGa9at5JCbmCfyMU2Ey#ec8af8cf-67d4-4b54-9bd6-8a861e729e11",
"issuanceDate": "2022-06-01T15:34:40.65319+02:00",
"issuer": "did:nuts:CuE3qeFGGLhEAS3gKzhMCeqd1dGa9at5JCbmCfyMU2Ey",
"type": [
"NutsOrganizationCredential",
"VerifiableCredential"
]
}
5 changes: 5 additions & 0 deletions jsonld/testsuite/private_key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICWw5A5U8aPEiu/QJyIMP4mUqFwx62CZgjr1xdxgcoZYoAoGCCqGSM49
AwEHoUQDQgAEZoS/Grh0lkKnW3ZO/NOEzq3kfIP6TYzsq3ldvJPEoK3mipaGUiYd
tSsNzlnEd4g8ecj06XlVpRGSZXOz6fLFpQ==
-----END EC PRIVATE KEY-----
3 changes: 1 addition & 2 deletions vcr/assets/assets/contexts/nuts.ldjson
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"@version": 1.1,
"@protected": true,
"@base": "https://nuts.nl/credentials/v1",
"@vocab": "#",

"id": "@id",
"type": "@type",
Expand Down Expand Up @@ -74,7 +73,7 @@
"userContext": "nuts:userContext"
}
},
"localParameters": {"@id": "nuts:localParameters", "@container": "@graph"}
"localParameters": {"@id": "nuts:localParameters", "@type": "@json"}
}
}
}
Expand Down
Loading

0 comments on commit e2847c8

Please sign in to comment.