diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5e6dad5f33fd39afc4dbfe83889d4a6624e48f31..221d47c44d88f5a12af980ba118da0cd4018df41 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,7 +16,7 @@ include: - template: 'Workflows/Branch-Pipelines.gitlab-ci.yml' lint: - image: golangci/golangci-lint:v1.49.0 + image: golangci/golangci-lint:v1.50.0 stage: test tags: - amd64-docker @@ -28,15 +28,16 @@ lint: - cd /go/src/gitlab.com/${CI_PROJECT_PATH} unit tests: - image: golang:1.19 + image: golang:1.19.2 extends: .gotest stage: test tags: - amd64-docker before_script: [] + coverage: '/total:\s+\(statements\)\s+(\d+.\d+\%)/' govulncheck: - image: golang:1.19 + image: golang:1.19.2 stage: test tags: - amd64-docker diff --git a/cmd/policy/main.go b/cmd/policy/main.go index b3c9ff27db77622eb6dabdc4b4054f1349d3acab..f2ef29e843635446311110f7dbd4bc31dc3857aa 100644 --- a/cmd/policy/main.go +++ b/cmd/policy/main.go @@ -87,21 +87,21 @@ func main() { taskFuncs := regofunc.NewTaskFuncs(cfg.Task.Addr, httpClient) ocmFuncs := regofunc.NewOcmFuncs(cfg.OCM.Addr, httpClient) signerFuncs := regofunc.NewSignerFuncs(cfg.Signer.Addr, httpClient) - didTransformerFuncs := regofunc.NewDIDWebFuncs() + didWebFuncs := regofunc.NewDIDWebFuncs() regofunc.Register("cacheGet", rego.Function3(cacheFuncs.CacheGetFunc())) regofunc.Register("cacheSet", rego.Function4(cacheFuncs.CacheSetFunc())) regofunc.Register("didResolve", rego.Function1(didResolverFuncs.ResolveFunc())) regofunc.Register("taskCreate", rego.Function2(taskFuncs.CreateTaskFunc())) regofunc.Register("taskListCreate", rego.Function2(taskFuncs.CreateTaskListFunc())) - regofunc.Register("getKey", rego.Function1(signerFuncs.GetKeyFunc())) - regofunc.Register("getAllKeys", rego.FunctionDyn(signerFuncs.GetAllKeysFunc())) - regofunc.Register("issuer", rego.FunctionDyn(signerFuncs.IssuerDID())) - regofunc.Register("createProof", rego.Function1(signerFuncs.CreateProof())) - regofunc.Register("verifyProof", rego.Function1(signerFuncs.VerifyProof())) + regofunc.Register("getKey", rego.Function3(signerFuncs.GetKeyFunc())) + regofunc.Register("getAllKeys", rego.Function2(signerFuncs.GetAllKeysFunc())) + regofunc.Register("addVCProof", rego.Function3(signerFuncs.AddVCProofFunc())) + regofunc.Register("addVPProof", rego.Function4(signerFuncs.AddVPProofFunc())) + regofunc.Register("verifyProof", rego.Function1(signerFuncs.VerifyProofFunc())) regofunc.Register("ocmLoginProofInvitation", rego.Function2(ocmFuncs.GetLoginProofInvitation())) regofunc.Register("ocmLoginProofResult", rego.Function1(ocmFuncs.GetLoginProofResult())) - regofunc.Register("didToURL", rego.Function1(didTransformerFuncs.DIDToURLFunc())) - regofunc.Register("urlToDID", rego.Function1(didTransformerFuncs.URLToDIDFunc())) + regofunc.Register("didToURL", rego.Function1(didWebFuncs.DIDToURLFunc())) + regofunc.Register("urlToDID", rego.Function1(didWebFuncs.URLToDIDFunc())) } // subscribe the cache for policy data changes diff --git a/deployment/ci/Dockerfile b/deployment/ci/Dockerfile index b22df4e78981551a350da9c2f62eaf5408805ea7..81a5368b219523506e9b44b42585c99e15d28486 100644 --- a/deployment/ci/Dockerfile +++ b/deployment/ci/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19-alpine3.15 as builder +FROM golang:1.19.2-alpine3.15 as builder RUN apk add git diff --git a/deployment/compose/Dockerfile b/deployment/compose/Dockerfile index 618924d546fbbde02d193a33a97652488cdddf9f..49788678f33240ebf5385e792dc2872a08d9560c 100644 --- a/deployment/compose/Dockerfile +++ b/deployment/compose/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19 +FROM golang:1.19.2 RUN go install github.com/canthefason/go-watcher/cmd/watcher@v0.2.4 diff --git a/doc/policy_development.md b/doc/policy_development.md index b78189aeafc16b90acac9b1cec91949c7adcf7d6..04a10bb70df79c36f4e4e25be646cf200f49cb55 100644 --- a/doc/policy_development.md +++ b/doc/policy_development.md @@ -21,7 +21,7 @@ If the following policy is evaluated, the returned result will be ``` package example.createProof -credential := proof.create(input) +credential := add_vc_proof("transit", "key1", input) ``` Result: @@ -43,7 +43,7 @@ of the policy evaluation won't be embedded in an attribute named ``` package example.createProof -_ := proof.create(input) +_ = add_vc_proof("transit", "key1", input) ``` Result: @@ -133,94 +133,89 @@ result := tasklist.create("task-list-name", input.data) #### keys.get -Retrieve a specific public key from the signer service. The function accepts one -argument which is the name of the key. The key is returned in JWK format -wrapped in a DID verification method envelope. +Retrieve a specific public key from the signer service. The function accepts +three arguments which specify the DID, key namespace and key name. The key +is returned in JWK format wrapped in a DID verification method envelope. Example: ``` package example.getkey -_ := keys.get("key1") +_ := keys.get("did:web:example.com", "transit", "key1") ``` Result: ```json -{ - "id": "key1", + { + "id": "did:web:example.com#key1", + "type": "JsonWebKey2020", + "controller": "did:web:example.com", "publicKeyJwk": { - "crv": "P-256", + "kty": "OKP", "kid": "key1", - "kty": "EC", - "x": "RTx_2cyYcGVSIRP_826S32BiZxSgnzyXgRYmKP8N2l0", - "y": "unnPzMAnbByBMq2l9WWKsDFE-MDvX6hYhrESsjAaT50" - }, - "type": "JsonWebKey2020" + "crv": "Ed25519", + "x": "djRlRCtKdWFxcjJwMjlGTjAwa0w2ZHpHWVZURGN1eVJydDdrN1p5eEo5Yz0" + } } ``` #### keys.getAll -Retrieve all public keys from the signer service. The result is JSON array of +Retrieve all public keys from the signer service. The function accepts +two arguments specifying DID and key namespace. The result is JSON array of keys in JWK format wrapped in a DID verification method envelope. Example: ``` package example.getAllKeys -_ := keys.getAll() +_ := keys.getAll("did:web:example.com", "transit") ``` Result: ```json [ { - "id": "key1", + "id": "did:web:example.com#key1", + "type": "JsonWebKey2020", + "controller": "did:web:example.com", "publicKeyJwk": { - "crv": "P-256", + "kty": "OKP", "kid": "key1", - "kty": "EC", - "x": "RTx_2cyYcGVSIRP_826S32BiZxSgnzyXgRYmKP8N2l0", - "y": "unnPzMAnbByBMq2l9WWKsDFE-MDvX6hYhrESsjAaT50" - }, - "type": "JsonWebKey2020" + "crv": "Ed25519", + "x": "djRlRCtKdWFxcjJwMjlGTjAwa0w2ZHpHWVZURGN1eVJydDdrN1p5eEo5Yz0" + } }, { - ... + "id": "did:web:example.com#key2", + "type": "JsonWebKey2020", + "controller": "did:web:example.com", + "publicKeyJwk": { + "kty": "EC", + "kid": "key2", + "crv": "P-256", + "x": "8Kfl7wsUWeNOTgMR2wFWRhnU6o8jLnPuRcXQvJBu-Is", + "y": "_yVgBlJiWsquGWJPhuxrp_gy1x5g6fhhbDP9oyGWph4" + } } ] ``` -#### issuer - -Retrieve DID issuer value configured in the signer service. - -Example: -``` -package example.getIssuer - -did := issuer().did -``` +#### add_vc_proof -Result: -```json -{ - "did": "did:key:z6Mkfriq1MqLBoPWecGoDLjguo1sB9brj6wT3qZ5BxkKpuP6" -} -``` - -#### proof.create - -Create a proof for Verifiable Credential or Verifiable Presentation. -The function accepts one argument which represents a VC or VP in JSON format. +Add a proof to Verifiable Credential. +The function accepts three arguments: +* Key namespace where the signing key must be present. +* Key name of the signing key to be used. +* A Verifiable Credential document in JSON format. It calls the signer service to generate a proof and returns the response, -which is the same VC/VP but with proof section. +which is the same VC but with the generated proof section by the signer. Example Policy: ``` -package example.createProof +package example.addProof -_ := proof.create(input) +_ := add_vc_proof("transit", "key1", input) ``` Example VC given to policy evaluation: @@ -266,6 +261,24 @@ Example Response: } ``` +#### add_vp_proof + +Add a proof to Verifiable Presentation. +The function accepts four arguments: +* Issuer DID used for identifying the verification method to verify the proof. +* Key namespace where the signing key must be present. +* Key name of the signing key to be used. +* A Verifiable Presentation document in JSON format. +It calls the signer service to generate a proof and returns the response, +which is the same VC but with the generated proof section by the signer. + +Example Policy: +``` +package example.addProof + +_ := add_vp_proof("did: web:example.com", "transit", "key1", input) +``` + #### proof.verify Verify a proof for Verifiable Credential or Verifiable Presentation. diff --git a/go.mod b/go.mod index b202e2309936057d3f5e77aa0d824502829721be..b68b64a28de7e0ba8250c9cbf2e06665993d7d6b 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/open-policy-agent/opa v0.44.0 github.com/prometheus/client_golang v1.13.0 github.com/stretchr/testify v1.8.0 - gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib v0.0.0-20220914094252-e40da1dc603b + gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib v1.1.1 go.mongodb.org/mongo-driver v1.10.2 go.uber.org/zap v1.23.0 goa.design/goa/v3 v3.8.5 diff --git a/go.sum b/go.sum index b86296427cc4ef6bee1e78c0d778c77c36f6d3ba..2b0e4905c543e70c437d493bb7a4954aa25817ac 100644 --- a/go.sum +++ b/go.sum @@ -290,8 +290,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea h1:CyhwejzVGvZ3Q2PSbQ4NRRYn+ZWv5eS1vlaEusT+bAI= github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea/go.mod h1:eNr558nEUjP8acGw8FFjTeWvSgU1stO7FAO6eknhHe4= -gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib v0.0.0-20220914094252-e40da1dc603b h1:H6PS64kBP+oNZbYFUQYpLGyek3cC9hwWL+rrwhx+0lM= -gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib v0.0.0-20220914094252-e40da1dc603b/go.mod h1:5BPRkziGjdCI9xVfJBGY+7Ea51gtiEEs7+rbYeC8lnY= +gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib v1.1.1 h1:VdHDHXko2Z+YplWDliA1M0tcyCMDLp2qPPYx0C8fviI= +gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib v1.1.1/go.mod h1:0y0nhsIVlNFwyIopCi4FLZZuJK+aTP80p4KFRS4MlHA= go.mongodb.org/mongo-driver v1.10.2 h1:4Wk3cnqOrQCn0P92L3/mmurMxzdvWWs5J9jinAVKD+k= go.mongodb.org/mongo-driver v1.10.2/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= diff --git a/internal/regofunc/signer.go b/internal/regofunc/signer.go index 734585723aeb17ffaf8015ccef2a2b342fa87ad0..86cc62508edeb8a0a2fc4fa1830d4349587ef606 100644 --- a/internal/regofunc/signer.go +++ b/internal/regofunc/signer.go @@ -13,6 +13,11 @@ import ( "github.com/open-policy-agent/opa/types" ) +const ( + createVCProofPath = "/v1/credential/proof" + createVPProofPath = "/v1/presentation/proof" +) + type SignerFuncs struct { signerAddr string httpClient *http.Client @@ -25,33 +30,44 @@ func NewSignerFuncs(signerAddr string, httpClient *http.Client) *SignerFuncs { } } -func (sf *SignerFuncs) GetKeyFunc() (*rego.Function, rego.Builtin1) { +func (sf *SignerFuncs) GetKeyFunc() (*rego.Function, rego.Builtin3) { return ®o.Function{ Name: "keys.get", - Decl: types.NewFunction(types.Args(types.S), types.A), + Decl: types.NewFunction(types.Args(types.S, types.S, types.S), types.A), Memoize: true, }, - func(bctx rego.BuiltinContext, keyname *ast.Term) (*ast.Term, error) { - var key string - if err := ast.As(keyname.Value, &key); err != nil { - return nil, fmt.Errorf("invalid keyname: %s", err) + func(bctx rego.BuiltinContext, aDID, aNamespace, aKey *ast.Term) (*ast.Term, error) { + var did, namespace, key string + if err := ast.As(aDID.Value, &did); err != nil { + return nil, fmt.Errorf("invalid did: %s", err) + } else if err := ast.As(aNamespace.Value, &namespace); err != nil { + return nil, fmt.Errorf("invalid key namespace: %s", err) + } else if err := ast.As(aKey.Value, &key); err != nil { + return nil, fmt.Errorf("invalid key name: %s", err) } + if strings.TrimSpace(did) == "" { + return nil, fmt.Errorf("empty did") + } + if strings.TrimSpace(namespace) == "" { + return nil, fmt.Errorf("empty key namespace") + } if strings.TrimSpace(key) == "" { return nil, fmt.Errorf("empty keyname") } - uri, err := url.ParseRequestURI(sf.signerAddr + "/v1/keys/" + key) + path := fmt.Sprintf("/v1/keys/%s/%s/%s", did, namespace, key) + uri, err := url.ParseRequestURI(sf.signerAddr + path) if err != nil { return nil, err } - req, err := http.NewRequest("GET", uri.String(), nil) + req, err := http.NewRequestWithContext(bctx.Context, "GET", uri.String(), nil) if err != nil { return nil, err } - resp, err := sf.httpClient.Do(req.WithContext(bctx.Context)) + resp, err := sf.httpClient.Do(req) if err != nil { return nil, err } @@ -70,24 +86,39 @@ func (sf *SignerFuncs) GetKeyFunc() (*rego.Function, rego.Builtin1) { } } -func (sf *SignerFuncs) GetAllKeysFunc() (*rego.Function, rego.BuiltinDyn) { +func (sf *SignerFuncs) GetAllKeysFunc() (*rego.Function, rego.Builtin2) { return ®o.Function{ Name: "keys.getAll", - Decl: types.NewFunction(nil, types.A), + Decl: types.NewFunction(types.Args(types.S, types.S), types.A), Memoize: true, }, - func(bctx rego.BuiltinContext, terms []*ast.Term) (*ast.Term, error) { - uri, err := url.ParseRequestURI(sf.signerAddr + "/v1/keys") + func(bctx rego.BuiltinContext, aDID, aNamespace *ast.Term) (*ast.Term, error) { + var did, namespace string + if err := ast.As(aDID.Value, &did); err != nil { + return nil, fmt.Errorf("invalid did: %s", err) + } else if err := ast.As(aNamespace.Value, &namespace); err != nil { + return nil, fmt.Errorf("invalid key namespace: %s", err) + } + + if strings.TrimSpace(did) == "" { + return nil, fmt.Errorf("empty did") + } + if strings.TrimSpace(namespace) == "" { + return nil, fmt.Errorf("empty key namespace") + } + + path := fmt.Sprintf("/v1/keys/%s/%s", did, namespace) + uri, err := url.ParseRequestURI(sf.signerAddr + path) if err != nil { return nil, err } - req, err := http.NewRequest("GET", uri.String(), nil) + req, err := http.NewRequestWithContext(bctx.Context, "GET", uri.String(), nil) if err != nil { return nil, err } - resp, err := sf.httpClient.Do(req.WithContext(bctx.Context)) + resp, err := sf.httpClient.Do(req) if err != nil { return nil, err } @@ -106,24 +137,69 @@ func (sf *SignerFuncs) GetAllKeysFunc() (*rego.Function, rego.BuiltinDyn) { } } -func (sf *SignerFuncs) IssuerDID() (*rego.Function, rego.BuiltinDyn) { +// AddVCProofFunc calls the signer service to add a proof to a given +// Verifiable Credential. It accepts 3 arguments: +// 1. Namespace of cryptographic keys in the signer. +// 2. Key to be used for signing. +// 3. Verifiable Credential in JSON format. +func (sf *SignerFuncs) AddVCProofFunc() (*rego.Function, rego.Builtin3) { return ®o.Function{ - Name: "issuer", - Decl: types.NewFunction(nil, types.A), + Name: "add_vc_proof", + Decl: types.NewFunction(types.Args(types.S, types.S, types.A), types.A), Memoize: true, }, - func(bctx rego.BuiltinContext, terms []*ast.Term) (*ast.Term, error) { - uri, err := url.ParseRequestURI(sf.signerAddr + "/v1/issuerDID") + func(bctx rego.BuiltinContext, aNamespace, aKey, credential *ast.Term) (*ast.Term, error) { + var namespace, key string + if err := ast.As(aNamespace.Value, &namespace); err != nil { + return nil, fmt.Errorf("invalid key namespace: %s", err) + } else if err := ast.As(aKey.Value, &key); err != nil { + return nil, fmt.Errorf("invalid key name: %s", err) + } + + if strings.TrimSpace(namespace) == "" { + return nil, fmt.Errorf("empty key namespace") + } + if strings.TrimSpace(key) == "" { + return nil, fmt.Errorf("empty keyname") + } + + // cred represents verifiable credential or presentation + var cred map[string]interface{} + if err := ast.As(credential.Value, &cred); err != nil { + return nil, fmt.Errorf("invalid credential: %s", err) + } + + if cred["type"] == nil { + return nil, fmt.Errorf("credential data does not specify type: must be VerifiableCredential") + } + + credType, ok := cred["type"].(string) + if !ok { + return nil, fmt.Errorf("invalid credential type: string is expected") + } + + if credType != "VerifiableCredential" { //nolint:gosec + return nil, fmt.Errorf("unknown credential type: %q", credType) + } + + // create the payload for proof request + payload := map[string]interface{}{ + "namespace": namespace, + "key": key, + "credential": cred, + } + + payloadJSON, err := json.Marshal(payload) if err != nil { return nil, err } - req, err := http.NewRequest("GET", uri.String(), nil) + req, err := http.NewRequestWithContext(bctx.Context, "POST", sf.signerAddr+createVCProofPath, bytes.NewReader(payloadJSON)) if err != nil { return nil, err } - resp, err := sf.httpClient.Do(req.WithContext(bctx.Context)) + resp, err := sf.httpClient.Do(req) if err != nil { return nil, err } @@ -142,49 +218,75 @@ func (sf *SignerFuncs) IssuerDID() (*rego.Function, rego.BuiltinDyn) { } } -func (sf *SignerFuncs) CreateProof() (*rego.Function, rego.Builtin1) { +// AddVPProofFunc calls the signer service to add proof to +// a Verifiable Presentation. It accepts 4 arguments: +// 1. DID used in the proof verification method to find verification key by verifiers +// 2. Namespace of the cryptographic keys in the signer. +// 3. Key to be used for signing. +// 4. Verifiable Presentation in JSON format. +func (sf *SignerFuncs) AddVPProofFunc() (*rego.Function, rego.Builtin4) { return ®o.Function{ - Name: "proof.create", - Decl: types.NewFunction(types.Args(types.S), types.A), + Name: "add_vp_proof", + Decl: types.NewFunction(types.Args(types.S, types.S, types.S, types.A), types.A), Memoize: true, }, - func(bctx rego.BuiltinContext, credential *ast.Term) (*ast.Term, error) { - // cred represents verifiable credential or presentation - var cred map[string]interface{} - if err := ast.As(credential.Value, &cred); err != nil { - return nil, fmt.Errorf("invalid credential: %s", err) + func(bctx rego.BuiltinContext, aDID, aNamespace, aKey, presentation *ast.Term) (*ast.Term, error) { + var did, namespace, key string + if err := ast.As(aDID.Value, &did); err != nil { + return nil, fmt.Errorf("invalid did: %s", err) + } else if err := ast.As(aNamespace.Value, &namespace); err != nil { + return nil, fmt.Errorf("invalid key namespace: %s", err) + } else if err := ast.As(aKey.Value, &key); err != nil { + return nil, fmt.Errorf("invalid key name: %s", err) } - if cred["type"] == nil { - return nil, fmt.Errorf("credential data does not specify type: must be VerifiablePresentation or VerifiableCredential") + if strings.TrimSpace(did) == "" { + return nil, fmt.Errorf("empty did") + } + if strings.TrimSpace(namespace) == "" { + return nil, fmt.Errorf("empty key namespace") + } + if strings.TrimSpace(key) == "" { + return nil, fmt.Errorf("empty keyname") } - credType, ok := cred["type"].(string) + var pres map[string]interface{} + if err := ast.As(presentation.Value, &pres); err != nil { + return nil, fmt.Errorf("invalid presentation: %s", err) + } + + if pres["type"] == nil { + return nil, fmt.Errorf("presentation data does not specify type: must be VerifiablePresentation") + } + + presType, ok := pres["type"].(string) if !ok { - return nil, fmt.Errorf("invalid credential type, string is expected") + return nil, fmt.Errorf("invalid presentation type: string is expected") } - var createProofPath string - switch credType { - case "VerifiableCredential": - createProofPath = "/v1/credential/proof" - case "VerifiablePresentation": - createProofPath = "/v1/presentation/proof" - default: - return nil, fmt.Errorf("unknown credential type: %q", credType) + if presType != "VerifiablePresentation" { + return nil, fmt.Errorf("unknown presentation type: %q", presType) } - jsonCred, err := json.Marshal(cred) + // create the payload for proof request + payload := map[string]interface{}{ + "issuer": did, + "namespace": namespace, + "key": key, + "presentation": pres, + } + + payloadJSON, err := json.Marshal(payload) if err != nil { return nil, err } - req, err := http.NewRequest("POST", sf.signerAddr+createProofPath, bytes.NewReader(jsonCred)) + req, err := http.NewRequestWithContext(bctx.Context, "POST", sf.signerAddr+createVPProofPath, bytes.NewReader(payloadJSON)) if err != nil { return nil, err } - resp, err := sf.httpClient.Do(req.WithContext(bctx.Context)) + resp, err := sf.httpClient.Do(req) if err != nil { return nil, err } @@ -203,7 +305,7 @@ func (sf *SignerFuncs) CreateProof() (*rego.Function, rego.Builtin1) { } } -func (sf *SignerFuncs) VerifyProof() (*rego.Function, rego.Builtin1) { +func (sf *SignerFuncs) VerifyProofFunc() (*rego.Function, rego.Builtin1) { return ®o.Function{ Name: "proof.verify", Decl: types.NewFunction(types.Args(types.S), types.A), @@ -244,12 +346,12 @@ func (sf *SignerFuncs) VerifyProof() (*rego.Function, rego.Builtin1) { return nil, err } - req, err := http.NewRequest("POST", sf.signerAddr+verifyProofPath, bytes.NewReader(jsonCred)) + req, err := http.NewRequestWithContext(bctx.Context, "POST", sf.signerAddr+verifyProofPath, bytes.NewReader(jsonCred)) if err != nil { return nil, err } - resp, err := sf.httpClient.Do(req.WithContext(bctx.Context)) + resp, err := sf.httpClient.Do(req) if err != nil { return nil, err } diff --git a/internal/regofunc/signer_test.go b/internal/regofunc/signer_test.go index 0430e1fea05d9fb481b6347f3f5ded9ea995c961..2525dcd6e358df41e7bfaba9234e755d7e0ef5dd 100644 --- a/internal/regofunc/signer_test.go +++ b/internal/regofunc/signer_test.go @@ -23,8 +23,8 @@ func TestGetKeyFunc(t *testing.T) { keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) r := rego.New( - rego.Query(`keys.get("key1")`), - rego.Function1(keysFuncs.GetKeyFunc()), + rego.Query(`keys.get("did:web:example.com", "transit", "key1")`), + rego.Function3(keysFuncs.GetKeyFunc()), rego.StrictBuiltinErrors(true), ) resultSet, err := r.Eval(context.Background()) @@ -43,15 +43,15 @@ func TestGetKeyFuncError(t *testing.T) { keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) r := rego.New( - rego.Query(`keys.get("key1")`), - rego.Function1(keysFuncs.GetKeyFunc()), + rego.Query(`keys.get("did:web:example.com", "transit", "key1")`), + rego.Function3(keysFuncs.GetKeyFunc()), rego.StrictBuiltinErrors(true), ) resultSet, err := r.Eval(context.Background()) assert.Nil(t, resultSet) assert.Error(t, err) - expectedError := `keys.get("key1"): eval_builtin_error: keys.get: unexpected response from signer: 404 Not Found` + expectedError := `keys.get("did:web:example.com", "transit", "key1"): eval_builtin_error: keys.get: unexpected response from signer: 404 Not Found` assert.Equal(t, expectedError, err.Error()) } @@ -64,8 +64,8 @@ func TestGetAllKeysFunc(t *testing.T) { keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) r := rego.New( - rego.Query(`keys.getAll()`), - rego.FunctionDyn(keysFuncs.GetAllKeysFunc()), + rego.Query(`keys.getAll("did:web:example.com", "transit")`), + rego.Function2(keysFuncs.GetAllKeysFunc()), rego.StrictBuiltinErrors(true), ) resultSet, err := r.Eval(context.Background()) @@ -76,28 +76,7 @@ func TestGetAllKeysFunc(t *testing.T) { assert.Equal(t, expected, string(resultBytes)) } -func TestIssuerDID(t *testing.T) { - expected := `{"did":"did:web:123"}` - signerSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, _ = fmt.Fprint(w, expected) - })) - defer signerSrv.Close() - - keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) - r := rego.New( - rego.Query(`issuer()`), - rego.FunctionDyn(keysFuncs.IssuerDID()), - rego.StrictBuiltinErrors(true), - ) - resultSet, err := r.Eval(context.Background()) - assert.NoError(t, err) - - resultBytes, err := json.Marshal(resultSet[0].Expressions[0].Value) - assert.NoError(t, err) - assert.Equal(t, expected, string(resultBytes)) -} - -func TestCreateProof(t *testing.T) { +func TestAddVCProof(t *testing.T) { tests := []struct { name string input map[string]interface{} @@ -120,6 +99,61 @@ func TestCreateProof(t *testing.T) { signerResponseCode: http.StatusBadRequest, errtext: "400 Bad Request", }, + { + name: "signer returns successfully", + input: map[string]interface{}{"type": "VerifiableCredential"}, + signerResponseCode: http.StatusOK, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + expected := `{"vc":"data"}` + signerSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(test.signerResponseCode) + _, _ = fmt.Fprint(w, expected) + })) + defer signerSrv.Close() + + keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) + query, err := rego.New( + rego.Query(`add_vc_proof("transit", "key1", input)`), + rego.Function3(keysFuncs.AddVCProofFunc()), + rego.StrictBuiltinErrors(true), + ).PrepareForEval(context.Background()) + assert.NoError(t, err) + + resultSet, err := query.Eval(context.Background(), rego.EvalInput(test.input)) + if err != nil { + assert.Contains(t, err.Error(), test.errtext) + } else { + assert.NotEmpty(t, resultSet) + assert.NotEmpty(t, resultSet[0].Expressions) + resultBytes, err := json.Marshal(resultSet[0].Expressions[0].Value) + assert.NoError(t, err) + assert.Equal(t, expected, string(resultBytes)) + } + }) + } +} + +func TestAddVPProof(t *testing.T) { + tests := []struct { + name string + input map[string]interface{} + signerResponseCode int + errtext string + }{ + { + name: "missing presentation type", + input: map[string]interface{}{"vc": "data"}, + errtext: "presentation data does not specify type", + }, + { + name: "unknown presentation type", + input: map[string]interface{}{"type": "non-existing-type"}, + errtext: "unknown presentation type", + }, { name: "signer returns error for VP", input: map[string]interface{}{"type": "VerifiablePresentation"}, @@ -128,7 +162,7 @@ func TestCreateProof(t *testing.T) { }, { name: "signer returns successfully", - input: map[string]interface{}{"type": "VerifiableCredential"}, + input: map[string]interface{}{"type": "VerifiablePresentation"}, signerResponseCode: http.StatusOK, }, } @@ -144,8 +178,8 @@ func TestCreateProof(t *testing.T) { keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) query, err := rego.New( - rego.Query(`proof.create(input)`), - rego.Function1(keysFuncs.CreateProof()), + rego.Query(`add_vp_proof("did:web:example.com", "transit", "key1", input)`), + rego.Function4(keysFuncs.AddVPProofFunc()), rego.StrictBuiltinErrors(true), ).PrepareForEval(context.Background()) assert.NoError(t, err) @@ -228,7 +262,7 @@ func TestVerifyProof(t *testing.T) { keysFuncs := regofunc.NewSignerFuncs(signerSrv.URL, http.DefaultClient) query, err := rego.New( rego.Query(`proof.verify(input)`), - rego.Function1(keysFuncs.VerifyProof()), + rego.Function1(keysFuncs.VerifyProofFunc()), rego.StrictBuiltinErrors(true), ).PrepareForEval(context.Background()) assert.NoError(t, err) diff --git a/vendor/gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors/errors.go b/vendor/gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors/errors.go index 8c3afe9ce39b4e2cdc4b73b91862503df1b5df9e..2f1c0906a3da5f9b860c2587f9c5fdf9b18798b1 100644 Binary files a/vendor/gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors/errors.go and b/vendor/gitlab.com/gaia-x/data-infrastructure-federation-services/tsa/golib/errors/errors.go differ diff --git a/vendor/modules.txt b/vendor/modules.txt index ffa34e8242fb30107a3b9d3e451a8af7abb780b0..d58bdab8239f9d1d2ccd60064327256c889a2b07 100644 Binary files a/vendor/modules.txt and b/vendor/modules.txt differ