Skip to content
This repository has been archived by the owner on Apr 5, 2023. It is now read-only.

Commit

Permalink
feat: [WACI-Issuance] Support to read credential manifest
Browse files Browse the repository at this point in the history
closes #561

Signed-off-by: talwinder50 <[email protected]>
  • Loading branch information
talwinder50 committed Jan 26, 2022
1 parent 837ffab commit 9ff8c67
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 17 deletions.
7 changes: 4 additions & 3 deletions cmd/adapter-rest/startcmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -868,8 +868,8 @@ func addIssuerHandlers(parameters *adapterRestParameters, framework *aries.Aries
if err != nil {
return fmt.Errorf("aries-framework - failed to get aries context : %w", err)
}
// TODO #572 Pass the output descriptors to issuer
_, err = readCMOutputDescriptorFile(parameters.cmOutputDescriptorsFilePath)

cmOutputDescriptor, err := readCMOutputDescriptorFile(parameters.cmOutputDescriptorsFilePath)
if err != nil {
return fmt.Errorf("failed to read and validate manifest output descriptors : %w", err)
}
Expand All @@ -892,7 +892,7 @@ func addIssuerHandlers(parameters *adapterRestParameters, framework *aries.Aries
if err != nil {
return fmt.Errorf("failed to init trustbloc did creator: %w", err)
}
// TODO #572 Pass the output descriptors to issuer
// TODO #579 Persist the manifest output descriptor in local file based or in-memory cache.
// add issuer endpoints
issuerService, err := issuer.New(&issuerops.Config{
AriesCtx: ariesCtx,
Expand All @@ -907,6 +907,7 @@ func addIssuerHandlers(parameters *adapterRestParameters, framework *aries.Aries
ExternalURL: parameters.externalURL,
DidDomain: parameters.trustblocDomain,
JSONLDDocumentLoader: ariesCtx.JSONLDDocumentLoader(),
CmOutputDescriptor: cmOutputDescriptor,
})
if err != nil {
return fmt.Errorf("failed to init issuer ops: %w", err)
Expand Down
6 changes: 5 additions & 1 deletion pkg/profile/issuer/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"fmt"
"time"

"github.com/hyperledger/aries-framework-go/pkg/doc/cm"
"github.com/hyperledger/aries-framework-go/spi/storage"

"github.com/trustbloc/edge-adapter/pkg/internal/common/adapterutil"
Expand All @@ -30,6 +31,8 @@ type Profile struct {
}

// ProfileData struct for profile.
// Issuer ID identifies who is the issuer of the credential manifests being issued.
// CMStyle represents an entity styles object as defined in credential manifest spec.
type ProfileData struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Expand All @@ -45,7 +48,8 @@ type ProfileData struct {
OIDCClientParams *OIDCClientParams `json:"oidcParams,omitempty"`
CredentialScopes []string `json:"credScopes,omitempty"`
LinkedWalletURL string `json:"linkedWallet,omitempty"`
// Todo #issue Add credential manifest issuer object
IssuerID string `json:"issuerID,omitempty"`
CMStyle cm.Styles `json:"styles,omitempty"`
}

// OIDCClientParams optional set of oidc client parameters that the issuer may set, for static client registration.
Expand Down
3 changes: 3 additions & 0 deletions pkg/restapi/issuer/operation/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"encoding/json"

"github.com/hyperledger/aries-framework-go/pkg/client/outofband"
"github.com/hyperledger/aries-framework-go/pkg/doc/cm"

adaptervc "github.com/trustbloc/edge-adapter/pkg/vc"
)
Expand All @@ -27,6 +28,8 @@ type ProfileDataRequest struct {
OIDCClientParams *OIDCClientParams `json:"oidcParams,omitempty"`
CredentialScopes []string `json:"scopes,omitempty"`
LinkedWalletURL string `json:"linkedWallet,omitempty"`
IssuerID string `json:"issuerID,omitempty"`
CMStyle cm.Styles `json:"styles,omitempty"`
}

// OIDCClientParams optional parameters for setting the adapter's oidc client parameters statically.
Expand Down
43 changes: 38 additions & 5 deletions pkg/restapi/issuer/operation/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ const (

// WACI interaction constants
credentialManifestFormat = "dif/credential-manifest/[email protected]"
credentialManifestVersion = "0.1.0"
credentialFulfillmentFormat = "dif/credential-manifest/[email protected]"
offerCredentialAttachMediaType = "application/json"
redirectStatusOK = "OK"
Expand Down Expand Up @@ -141,6 +142,7 @@ type didExClient interface {
}

// Config defines configuration for issuer operations.
// TODO #580 Create helper function for cmOutputDescriptor
type Config struct {
AriesCtx aries.CtxProvider
AriesMessenger service.Messenger
Expand All @@ -155,6 +157,7 @@ type Config struct {
ExternalURL string
DidDomain string
JSONLDDocumentLoader ld.DocumentLoader
CmOutputDescriptor map[string][]*cm.OutputDescriptor
}

// New returns issuer rest instance.
Expand Down Expand Up @@ -342,6 +345,7 @@ type Operation struct {
getOIDCClientFunc func(string, string) (oidcClient, error)
didDomain string
jsonldDocLoader ld.DocumentLoader
cmOutputDescriptor map[string][]*cm.OutputDescriptor
}

// GetRESTHandlers get all controller API handler available for this service.
Expand All @@ -360,6 +364,7 @@ func (o *Operation) GetRESTHandlers() []restapi.Handler {
}, o.walletBridge.GetRESTHandlers()...)
}

// TODO #581 Validate and check Waci profile creation that each scope has output descriptors configured.
func (o *Operation) createIssuerProfileHandler(rw http.ResponseWriter, req *http.Request) {
data := &ProfileDataRequest{}

Expand Down Expand Up @@ -1290,8 +1295,15 @@ func (o *Operation) handleProposeCredential(msg service.DIDCommAction) (issuecre
}
}

// get manifest
manifest := o.readCredentialManifest()
txn, err := o.getTxn(userInvMap.TxID)
if err != nil {
return nil, fmt.Errorf("failed to get trasaction data: %w", err)
}

// read credential manifest
manifest := o.readCredentialManifest(profile, txn.CredScope)

// TODO #581 validate read credential manifest object

// get unsigned credential
vc, err := o.createCredential(getUserDataURL(profile.URL), userInvMap.TxToken, oauthToken,
Expand Down Expand Up @@ -1728,11 +1740,30 @@ func (o *Operation) hanlDIDExStateMsg(msg service.StateMsg) error {
return nil
}

// read credential manifest from profile URL endpoints
// TODO for now returning empty manifest, TO BE IMPLEMENTED [issue##561 & issue#563]
func (o *Operation) readCredentialManifest() *cm.CredentialManifest {
// Read credential manifest issuer detail from persisted profile data and scope from persisted transaction cred scope.
// cm.Issuer's ID will be used as issuer ID which identifies who the issuer of the credential(s) will be.
// Credential Manifest Styles represents an Entity Styles object as defined in credential manifest spec.
// TODO issue#561 Add credential manifest presentation definition
func (o *Operation) readCredentialManifest(profileData *issuer.ProfileData,
txnCredScope string) *cm.CredentialManifest {
if cmDescriptor, ok := o.cmOutputDescriptor[txnCredScope]; ok {
return &cm.CredentialManifest{
ID: uuid.NewString(),
Version: credentialManifestVersion,
Issuer: cm.Issuer{
ID: profileData.IssuerID,
Name: profileData.Name,
Styles: profileData.CMStyle,
},
OutputDescriptors: cmDescriptor,
}
}

return &cm.CredentialManifest{
ID: uuid.NewString(),
Issuer: cm.Issuer{
ID: profileData.IssuerID,
},
}
}

Expand Down Expand Up @@ -2068,5 +2099,7 @@ func mapProfileReqToData(data *ProfileDataRequest, didDoc *did.Doc) (*issuer.Pro
OIDCClientParams: clientParams,
CredentialScopes: data.CredentialScopes,
LinkedWalletURL: data.LinkedWalletURL,
IssuerID: data.IssuerID,
CMStyle: data.CMStyle,
}, nil
}
67 changes: 59 additions & 8 deletions pkg/restapi/issuer/operation/operations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const (
inviteeDID = "did:example:0d76fa4e1386"
inviterDID = "did:example:e6025bfdbb8f"
mockOIDCProvider = "mock.provider.local"
mockCredScope = "prc"
)

func TestNew(t *testing.T) {
Expand Down Expand Up @@ -513,6 +514,7 @@ func TestCreateProfile(t *testing.T) {
require.Equal(t, vReq.Name, profileRes.Name)
require.Equal(t, vReq.URL, profileRes.URL)
require.Equal(t, vReq.SupportsAssuranceCredential, profileRes.SupportsAssuranceCredential)
require.Equal(t, vReq.IssuerID, profileRes.IssuerID)
require.Equal(t, vReq.SupportsWACI, profileRes.SupportsWACI)
})

Expand Down Expand Up @@ -3454,6 +3456,15 @@ func TestWACIIssuanceHandler(t *testing.T) {
ConnIDByDIDs: connID,
}

c.cmOutputDescriptor = map[string][]*cm.OutputDescriptor{
mockCredScope: {
&cm.OutputDescriptor{
ID: uuid.New().String(),
Schema: "https://www.w3.org/2018/credentials/examples/v1",
},
},
}

invitationID := uuid.New().String()
issuerID := uuid.New().String()

Expand All @@ -3463,11 +3474,25 @@ func TestWACIIssuanceHandler(t *testing.T) {
err = c.profileStore.SaveProfile(profile)
require.NoError(t, err)

err = c.storeUserInvitationMapping(&UserInvitationMapping{
usrInvitationMapping := &UserInvitationMapping{
InvitationID: invitationID,
IssuerID: issuerID,
TxID: uuid.New().String(),
TxToken: uuid.New().String(),
})
}

err = c.storeUserInvitationMapping(usrInvitationMapping)
require.NoError(t, err)

txDataSample := &txnData{
IssuerID: profile.ID,
CredScope: mockCredScope,
}

tdByte, err := json.Marshal(txDataSample)
require.NoError(t, err)

err = c.txnStore.Put(usrInvitationMapping.TxID, tdByte)
require.NoError(t, err)

go c.didCommActionListener(actionCh)
Expand Down Expand Up @@ -3502,23 +3527,48 @@ func TestWACIIssuanceHandler(t *testing.T) {

invitationID := uuid.New().String()
issuerID := uuid.New().String()

c.cmOutputDescriptor = map[string][]*cm.OutputDescriptor{
mockCredScope: {
&cm.OutputDescriptor{
ID: uuid.New().String(),
Schema: "https://www.w3.org/2018/credentials/examples/v1",
},
},
}
profile := createProfileData(issuerID)
profile.SupportsWACI = true

err = c.profileStore.SaveProfile(profile)
require.NoError(t, err)

err = c.storeUserInvitationMapping(&UserInvitationMapping{
usrInvitationMapping := &UserInvitationMapping{
InvitationID: invitationID,
IssuerID: issuerID,
TxID: uuid.New().String(),
TxToken: uuid.New().String(),
})
}

err = c.storeUserInvitationMapping(usrInvitationMapping)
require.NoError(t, err)

go c.didCommActionListener(actionCh)

testFailure(actionCh, service.NewDIDCommMsgMap(issuecredsvc.ProposeCredentialV2{
Type: issuecredsvc.ProposeCredentialMsgTypeV2,
InvitationID: invitationID,
}), "failed to fetch txn data")

// validate manifest data error
txDataSample := &txnData{
IssuerID: profile.ID,
}
// credential data error
txDataSample.CredScope = mockCredScope
tdCredByte, err := json.Marshal(txDataSample)
require.NoError(t, err)

err = c.txnStore.Put(usrInvitationMapping.TxID, tdCredByte)
require.NoError(t, err)
c.httpClient = &mockHTTPClient{
respValue: &http.Response{
StatusCode: http.StatusInternalServerError,
Expand Down Expand Up @@ -3603,14 +3653,15 @@ func TestWACIIssuanceHandler(t *testing.T) {
InvitationID: newInvitationID,
}), "failed to get OIDC access token for WACI transaction")

// token store put error
newInvitationID = uuid.New().String()
issuerID = uuid.New().String()
err = c.storeUserInvitationMapping(&UserInvitationMapping{
usrInvitationMapping = &UserInvitationMapping{
InvitationID: newInvitationID,
IssuerID: issuerID,
TxID: usrInvitationMapping.TxID,
TxToken: uuid.New().String(),
})
}
err = c.storeUserInvitationMapping(usrInvitationMapping)
require.NoError(t, err)

profile = createProfileData(issuerID)
Expand Down
1 change: 1 addition & 0 deletions pkg/restapi/issuer/operation/support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ func createProfileData(profileID string) *issuer.ProfileData {
URL: "http://issuer.example.com",
PresentationSigningKey: "did:example:123xyz#key-1",
SupportsWACI: false,
IssuerID: "did:example:123?linked-domains=3",
}
}

Expand Down

0 comments on commit 9ff8c67

Please sign in to comment.