Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Added JWT for definitions. #262

Merged
merged 6 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions integration/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,16 @@ func CreateCredentialApplicationJWT(credApplication credApplicationParams, crede
return signed.String(), nil
}

func CreatePresentationDefinition() (string, error) {
type definitionParams struct {
Author string
}

func CreatePresentationDefinition(params definitionParams) (string, error) {
logrus.Println("\n\nCreate our Presentation Definition:")
definitionJSON := getJSONFromFile("presentation-definition-input.json")
definitionJSON, err := resolveTemplate(params, "presentation-definition-input.json")
if err != nil {
return "", err
}
output, err := put(endpoint+version+"presentations/definitions", definitionJSON)
if err != nil {
return "", errors.Wrapf(err, "presentation definition endpoint with output: %s", output)
Expand Down
13 changes: 12 additions & 1 deletion integration/presentation_exchange_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,16 @@ func TestCreateParticipants(t *testing.T) {
holderPrivateKey, err := getJSONElement(holderOutput, "$.privateKeyBase58")
assert.NoError(t, err)

verifierOutput, err := CreateDIDKey()
assert.NoError(t, err)

verifierDID, err := getJSONElement(verifierOutput, "$.did.id")
assert.NoError(t, err)
assert.Contains(t, holderDID, "did:key")

SetValue(presentationExchangeContext, "issuerDID", issuerDID)
SetValue(presentationExchangeContext, "holderDID", holderDID)
SetValue(presentationExchangeContext, "verifierDID", verifierDID)
SetValue(presentationExchangeContext, "holderPrivateKey", holderPrivateKey)
}

Expand All @@ -42,7 +50,10 @@ func TestCreatePresentationDefinition(t *testing.T) {
t.Skip("skipping integration test")
}

definition, err := CreatePresentationDefinition()
verifierDID, err := GetValue(presentationExchangeContext, "verifierDID")
assert.NoError(t, err)

definition, err := CreatePresentationDefinition(definitionParams{Author: verifierDID.(string)})
assert.NoError(t, err)

definitionID, err := getJSONElement(definition, "$.presentation_definition.id")
Expand Down
3 changes: 2 additions & 1 deletion integration/testdata/presentation-definition-input.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
]
}
}
]
],
"author": "{{.Author}}"
}
24 changes: 21 additions & 3 deletions pkg/server/router/presentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,19 @@ type CreatePresentationDefinitionRequest struct {
Format *exchange.ClaimFormat `json:"format,omitempty" validate:"omitempty,dive"`
InputDescriptors []exchange.InputDescriptor `json:"inputDescriptors" validate:"required,dive"`
SubmissionRequirements []exchange.SubmissionRequirement `json:"submissionRequirements,omitempty" validate:"omitempty,dive"`

// DID of the author of this presentation definition. The DID must have been previously created with the DID API,
// or the PrivateKey must have been added independently. The privateKey associated to this DID will be used to
// sign an envelope that contains the created presentation definition.
Author string `json:"author" validate:"required"`
}

type CreatePresentationDefinitionResponse struct {
PresentationDefinition exchange.PresentationDefinition `json:"presentation_definition"`

// Signed envelope that contains the PresentationDefinition created using the privateKey of the author of the
// definition.
PresentationDefinitionJWT keyaccess.JWT `json:"presentationDefinitionJWT"`
}

// CreateDefinition godoc
Expand Down Expand Up @@ -77,14 +86,18 @@ func (pr PresentationRouter) CreateDefinition(ctx context.Context, w http.Respon
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
}
serviceResp, err := pr.service.CreatePresentationDefinition(ctx, model.CreatePresentationDefinitionRequest{PresentationDefinition: *def})
serviceResp, err := pr.service.CreatePresentationDefinition(
ctx,
model.CreatePresentationDefinitionRequest{PresentationDefinition: *def, Author: request.Author},
)
if err != nil {
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusInternalServerError)
}

resp := CreatePresentationDefinitionResponse{
PresentationDefinition: serviceResp.PresentationDefinition,
PresentationDefinition: serviceResp.PresentationDefinition,
PresentationDefinitionJWT: serviceResp.PresentationDefinitionJWT,
}
return framework.Respond(ctx, w, resp, http.StatusCreated)
}
Expand Down Expand Up @@ -122,6 +135,10 @@ func definitionFromRequest(request CreatePresentationDefinitionRequest) (*exchan

type GetPresentationDefinitionResponse struct {
PresentationDefinition exchange.PresentationDefinition `json:"presentation_definition"`

// Signed envelope that contains the PresentationDefinition created using the privateKey of the author of the
// definition.
PresentationDefinitionJWT keyaccess.JWT `json:"presentationDefinitionJWT"`
}

// GetDefinition godoc
Expand Down Expand Up @@ -151,7 +168,8 @@ func (pr PresentationRouter) GetDefinition(ctx context.Context, w http.ResponseW
}

resp := GetPresentationDefinitionResponse{
PresentationDefinition: def.PresentationDefinition,
PresentationDefinition: def.PresentationDefinition,
PresentationDefinitionJWT: def.PresentationDefinitionJWT,
}
return framework.Respond(ctx, w, resp, http.StatusOK)
}
Expand Down
34 changes: 29 additions & 5 deletions pkg/server/router/presentation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ package router

import (
"context"
gocrypto "crypto"
"testing"

"github.com/TBD54566975/ssi-sdk/credential/exchange"
"github.com/TBD54566975/ssi-sdk/crypto"
didsdk "github.com/TBD54566975/ssi-sdk/did"
"github.com/mr-tron/base58"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tbd54566975/ssi-service/config"
"github.com/tbd54566975/ssi-service/internal/keyaccess"
"github.com/tbd54566975/ssi-service/pkg/service/did"
"github.com/tbd54566975/ssi-service/pkg/service/presentation"
"github.com/tbd54566975/ssi-service/pkg/service/presentation/model"
)
Expand All @@ -28,6 +34,10 @@ func TestPresentationDefinitionRouter(t *testing.T) {
})
}

type Public interface {
Public() gocrypto.PublicKey
}

func TestPresentationDefinitionService(t *testing.T) {

s := setupTestDB(t)
Expand All @@ -36,32 +46,46 @@ func TestPresentationDefinitionService(t *testing.T) {
keyStoreService := testKeyStoreService(t, s)
didService := testDIDService(t, s, keyStoreService)
schemaService := testSchemaService(t, s, keyStoreService, didService)
authorDID, err := didService.CreateDIDByMethod(context.Background(), did.CreateDIDRequest{
Method: didsdk.KeyMethod,
KeyType: crypto.Ed25519,
})
require.NoError(t, err)
privKeyBytes, err := base58.Decode(authorDID.PrivateKeyBase58)
require.NoError(t, err)
privKey, err := crypto.BytesToPrivKey(privKeyBytes, authorDID.KeyType)
require.NoError(t, err)
ka, err := keyaccess.NewJWKKeyAccessVerifier(authorDID.DID.ID, privKey.(Public).Public())
require.NoError(t, err)

service, err := presentation.NewPresentationService(config.PresentationServiceConfig{}, s, didService.GetResolver(), schemaService)
assert.NoError(t, err)
service, err := presentation.NewPresentationService(config.PresentationServiceConfig{}, s, didService.GetResolver(), schemaService, keyStoreService)
require.NoError(t, err)

t.Run("Create returns the created definition", func(t *testing.T) {
pd := createPresentationDefinition(t)
created, err := service.CreatePresentationDefinition(context.Background(), model.CreatePresentationDefinitionRequest{PresentationDefinition: *pd})
created, err := service.CreatePresentationDefinition(context.Background(), model.CreatePresentationDefinitionRequest{PresentationDefinition: *pd, Author: authorDID.DID.ID})

assert.NoError(t, err)
assert.Equal(t, pd, &created.PresentationDefinition)
assert.NoError(t, ka.Verify(created.PresentationDefinitionJWT))
})

t.Run("Get returns the created definition", func(t *testing.T) {
pd := createPresentationDefinition(t)
_, err := service.CreatePresentationDefinition(context.Background(), model.CreatePresentationDefinitionRequest{PresentationDefinition: *pd})
_, err := service.CreatePresentationDefinition(context.Background(), model.CreatePresentationDefinitionRequest{PresentationDefinition: *pd, Author: authorDID.DID.ID})
assert.NoError(t, err)

getPd, err := service.GetPresentationDefinition(context.Background(), model.GetPresentationDefinitionRequest{ID: pd.ID})

assert.NoError(t, err)
assert.Equal(t, pd.ID, getPd.ID)
assert.Equal(t, pd, &getPd.PresentationDefinition)
assert.NoError(t, ka.Verify(getPd.PresentationDefinitionJWT))
})

t.Run("Get does not return after deletion", func(t *testing.T) {
pd := createPresentationDefinition(t)
_, err := service.CreatePresentationDefinition(context.Background(), model.CreatePresentationDefinitionRequest{PresentationDefinition: *pd})
_, err := service.CreatePresentationDefinition(context.Background(), model.CreatePresentationDefinitionRequest{PresentationDefinition: *pd, Author: authorDID.DID.ID})
assert.NoError(t, err)

assert.NoError(t, service.DeletePresentationDefinition(context.Background(), model.DeletePresentationDefinitionRequest{ID: pd.ID}))
Expand Down
40 changes: 24 additions & 16 deletions pkg/server/server_operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import (
func TestOperationsAPI(t *testing.T) {
t.Run("Marks operation as done after reviewing submission", func(tt *testing.T) {
s := setupTestDB(tt)
pRouter := setupPresentationRouter(t, s)
pRouter, didService := setupPresentationRouter(t, s)
authorDID := createDID(t, didService)
opRouter := setupOperationsRouter(t, s)

holderSigner, holderDID := getSigner(t)
definition := createPresentationDefinition(t, pRouter)
definition := createPresentationDefinition(t, pRouter, authorDID.DID.ID)
submissionOp := createSubmission(t, pRouter, definition.PresentationDefinition.ID, VerifiableCredential(), holderDID, holderSigner)
sub := reviewSubmission(t, pRouter, opstorage.StatusObjectID(submissionOp.ID))

Expand Down Expand Up @@ -54,11 +55,12 @@ func TestOperationsAPI(t *testing.T) {
t.Run("GetOperation", func(t *testing.T) {
t.Run("Returns operation after submission", func(tt *testing.T) {
s := setupTestDB(tt)
pRouter := setupPresentationRouter(t, s)
pRouter, didService := setupPresentationRouter(t, s)
authorDID := createDID(t, didService)
opRouter := setupOperationsRouter(t, s)

holderSigner, holderDID := getSigner(t)
definition := createPresentationDefinition(t, pRouter)
definition := createPresentationDefinition(t, pRouter, authorDID.DID.ID)
submissionOp := createSubmission(t, pRouter, definition.PresentationDefinition.ID, VerifiableCredential(), holderDID, holderSigner)

createdID := submissionOp.ID
Expand Down Expand Up @@ -115,10 +117,11 @@ func TestOperationsAPI(t *testing.T) {

t.Run("Returns one operation for every submission", func(tt *testing.T) {
s := setupTestDB(tt)
pRouter := setupPresentationRouter(t, s)
pRouter, didService := setupPresentationRouter(t, s)
authorDID := createDID(t, didService)
opRouter := setupOperationsRouter(t, s)

def := createPresentationDefinition(t, pRouter)
def := createPresentationDefinition(t, pRouter, authorDID.DID.ID)
holderSigner, holderDID := getSigner(t)
submissionOp := createSubmission(t, pRouter, def.PresentationDefinition.ID, VerifiableCredential(), holderDID, holderSigner)

Expand Down Expand Up @@ -150,10 +153,11 @@ func TestOperationsAPI(t *testing.T) {

t.Run("Returns operation when filtering to include", func(tt *testing.T) {
s := setupTestDB(tt)
pRouter := setupPresentationRouter(t, s)
pRouter, didService := setupPresentationRouter(t, s)
authorDID := createDID(t, didService)
opRouter := setupOperationsRouter(t, s)

def := createPresentationDefinition(t, pRouter)
def := createPresentationDefinition(t, pRouter, authorDID.DID.ID)
holderSigner, holderDID := getSigner(t)
_ = createSubmission(t, pRouter, def.PresentationDefinition.ID, VerifiableCredential(), holderDID, holderSigner)

Expand All @@ -175,10 +179,11 @@ func TestOperationsAPI(t *testing.T) {

t.Run("Returns zero operations when filtering to exclude", func(tt *testing.T) {
s := setupTestDB(tt)
pRouter := setupPresentationRouter(t, s)
pRouter, didService := setupPresentationRouter(t, s)
authorDID := createDID(t, didService)
opRouter := setupOperationsRouter(t, s)

def := createPresentationDefinition(t, pRouter)
def := createPresentationDefinition(t, pRouter, authorDID.DID.ID)
holderSigner, holderDID := getSigner(t)
_ = createSubmission(t, pRouter, def.PresentationDefinition.ID, VerifiableCredential(), holderDID, holderSigner)

Expand All @@ -199,10 +204,11 @@ func TestOperationsAPI(t *testing.T) {

t.Run("Returns zero operations when wrong parent is specified", func(tt *testing.T) {
s := setupTestDB(tt)
pRouter := setupPresentationRouter(t, s)
pRouter, didService := setupPresentationRouter(t, s)
authorDID := createDID(t, didService)
opRouter := setupOperationsRouter(t, s)

def := createPresentationDefinition(t, pRouter)
def := createPresentationDefinition(t, pRouter, authorDID.DID.ID)
holderSigner, holderDID := getSigner(t)
_ = createSubmission(t, pRouter, def.PresentationDefinition.ID, VerifiableCredential(), holderDID, holderSigner)

Expand All @@ -224,11 +230,12 @@ func TestOperationsAPI(t *testing.T) {
t.Run("CancelOperation", func(t *testing.T) {
t.Run("Marks an operation as done", func(t *testing.T) {
s := setupTestDB(t)
pRouter := setupPresentationRouter(t, s)
pRouter, didService := setupPresentationRouter(t, s)
authorDID := createDID(t, didService)
opRouter := setupOperationsRouter(t, s)

holderSigner, holderDID := getSigner(t)
definition := createPresentationDefinition(t, pRouter)
definition := createPresentationDefinition(t, pRouter, authorDID.DID.ID)
submissionOp := createSubmission(t, pRouter, definition.PresentationDefinition.ID, VerifiableCredential(), holderDID, holderSigner)

createdID := submissionOp.ID
Expand All @@ -250,11 +257,12 @@ func TestOperationsAPI(t *testing.T) {

t.Run("Returns error when operation is done already", func(t *testing.T) {
s := setupTestDB(t)
pRouter := setupPresentationRouter(t, s)
pRouter, didService := setupPresentationRouter(t, s)
authorDID := createDID(t, didService)
opRouter := setupOperationsRouter(t, s)

holderSigner, holderDID := getSigner(t)
definition := createPresentationDefinition(t, pRouter)
definition := createPresentationDefinition(t, pRouter, authorDID.DID.ID)
submissionOp := createSubmission(t, pRouter, definition.PresentationDefinition.ID, VerifiableCredential(), holderDID, holderSigner)
_ = reviewSubmission(t, pRouter, opstorage.StatusObjectID(submissionOp.ID))

Expand Down
Loading