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

Commit

Permalink
Added JWT for definitions. (#262)
Browse files Browse the repository at this point in the history
* Added JWT for definitions.

* Documentation

* Test verification of JWTs

* Documentation

* PR comments
  • Loading branch information
andresuribe87 authored Jan 23, 2023
1 parent 68da36f commit 66fcff5
Show file tree
Hide file tree
Showing 12 changed files with 210 additions and 78 deletions.
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

0 comments on commit 66fcff5

Please sign in to comment.