Skip to content

Commit

Permalink
chore: Add handler for did:orb in
Browse files Browse the repository at this point in the history
We are currently exposing two DID resolution endpoints:

protected endpoint /sidetree/v1/identifiers for did:orb

unprotected endpoint /1.0/identifiers for did:web and did:orb

Closes #1459

Signed-off-by: Sandra Vrtikapa <sandra.vrtikapa@securekey.com>
  • Loading branch information
sandrask committed Sep 1, 2022
1 parent 008fee0 commit 9ec67d7
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 7 deletions.
1 change: 1 addition & 0 deletions cmd/orb-server/startcmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,7 @@ func startOrbServices(parameters *orbParameters) error {
WebfingerClient: wfClient,
LogEndpointRetriever: logEndpoint,
WebResolver: webResolveHandler,
OrbResolver: orbDocResolveHandler,
})
if err != nil {
return fmt.Errorf("discovery rest: %w", err)
Expand Down
115 changes: 115 additions & 0 deletions pkg/discovery/endpoint/restapi/mocks/orbresolver.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions pkg/discovery/endpoint/restapi/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const (
nodeInfoEndpoint = "/.well-known/nodeinfo"

orbWebDIDResolverEndpoint = "/1.0/identifiers/did:web:%s:scid:{id}"
orbDIDResolverEndpoint = "/1.0/identifiers/did:orb:{id}"

selfRelation = "self"
alternateRelation = "alternate"
Expand Down Expand Up @@ -96,6 +97,10 @@ type webResolver interface {
ResolveDocument(id string) (*document.ResolutionResult, error)
}

type orbResolver interface {
ResolveDocument(id string, opts ...document.ResolutionOption) (*document.ResolutionResult, error)
}

// New returns discovery operations.
func New(c *Config, p *Providers) (*Operation, error) {
// If the WebCAS path is empty, it'll cause certain WebFinger queries to be matched incorrectly
Expand Down Expand Up @@ -128,6 +133,7 @@ func New(c *Config, p *Providers) (*Operation, error) {
anchorStore: p.AnchorLinkStore,
wfClient: p.WebfingerClient,
webResolver: p.WebResolver,
orbResolver: p.OrbResolver,
domainWithPort: domainWithPort,
}, nil
}
Expand All @@ -144,6 +150,7 @@ type Operation struct {
anchorInfoRetriever
logEndpointRetriever
webResolver
orbResolver

pubKeys, httpSignPubKeys []PublicKey
resolutionPath string
Expand Down Expand Up @@ -182,6 +189,7 @@ type Providers struct {
WebfingerClient webfingerClient
LogEndpointRetriever logEndpointRetriever
WebResolver webResolver
OrbResolver orbResolver
}

// GetRESTHandlers get all controller API handler available for this service.
Expand All @@ -195,6 +203,7 @@ func (o *Operation) GetRESTHandlers() []common.HTTPHandler {
newHTTPHandler(nodeInfoEndpoint, o.nodeInfoHandler),
newHTTPHandler(orbWebDIDFileEndpoint, o.orbWebDIDFileHandler),
newHTTPHandler(fmt.Sprintf(orbWebDIDResolverEndpoint, o.domainWithPort), o.orbWebDIDResolverHandler),
newHTTPHandler(orbDIDResolverEndpoint, o.orbDIDResolverHandler),
}

// Only expose a service DID endpoint if the service ID is configured to be a DID.
Expand Down Expand Up @@ -262,6 +271,27 @@ func (o *Operation) orbWebDIDResolverHandler(rw http.ResponseWriter, r *http.Req
writeResponse(rw, result)
}

func (o *Operation) orbDIDResolverHandler(rw http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]

result, err := o.orbResolver.ResolveDocument("did:orb:" + id)
if err != nil {
if errors.Is(err, orberrors.ErrContentNotFound) {
logger.Debugf("orb resource[%s] not found", id)

writeErrorResponse(rw, http.StatusNotFound, "resource not found")
} else {
logger.Warnf("error returning orb resource [%s]: %s", id, err)

writeErrorResponse(rw, http.StatusInternalServerError, "error retrieving resource")
}

return
}

writeResponse(rw, result)
}

// webDIDHandler swagger:route Get /.well-known/did.json discovery wellKnownDIDReq
//
// webDIDHandler.
Expand Down
84 changes: 82 additions & 2 deletions pkg/discovery/endpoint/restapi/operations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ SPDX-License-Identifier: Apache-2.0
package restapi_test

//go:generate counterfeiter -o ./mocks/webresolver.gen.go --fake-name WebResolver . webResolver
//go:generate counterfeiter -o ./mocks/orbresolver.gen.go --fake-name OrbResolver . orbResolver

import (
"bytes"
Expand Down Expand Up @@ -44,6 +45,7 @@ const (

orbWebDIDFileEndpoint = "/scid/{id}/did.json"
orbWebDIDResolverEndpoint = "/1.0/identifiers/did:web:base:scid:{id}"
orbDIDResolverEndpoint = "/1.0/identifiers/did:orb:{id}"

suffix = "suffix"
)
Expand Down Expand Up @@ -133,7 +135,7 @@ func TestGetRESTHandlers(t *testing.T) {
&restapi.Providers{},
)
require.NoError(t, err)
require.Equal(t, 8, len(c.GetRESTHandlers()))
require.Equal(t, 9, len(c.GetRESTHandlers()))
})

t.Run("HTTP service ID Success", func(t *testing.T) {
Expand All @@ -145,7 +147,7 @@ func TestGetRESTHandlers(t *testing.T) {

c, err := restapi.New(cfg, &restapi.Providers{})
require.NoError(t, err)
require.Equal(t, 9, len(c.GetRESTHandlers()),
require.Equal(t, 10, len(c.GetRESTHandlers()),
"Expecting 9 handlers, including the service did handler")
})
}
Expand Down Expand Up @@ -865,6 +867,84 @@ func TestOrbWebDIDResolver(t *testing.T) {
})
}

func TestOrbDIDResolver(t *testing.T) {
t.Run("success", func(t *testing.T) {
didDoc := make(document.Document)

or := &endpointmocks.OrbResolver{}
or.ResolveDocumentReturns(&document.ResolutionResult{Document: didDoc}, nil)

c, err := restapi.New(&restapi.Config{
OperationPath: "/op",
ResolutionPath: "/resolve",
WebCASPath: "/cas",
ServiceEndpointURL: testutil.MustParseURL("http://base/services/orb"),
},
&restapi.Providers{OrbResolver: or})
require.NoError(t, err)

handler := getHandler(t, c, orbDIDResolverEndpoint)

urlVars := make(map[string]string)
urlVars["id"] = "uAAA:" + suffix

rr := serveHTTP(t, handler.Handler(), http.MethodGet, orbDIDResolverEndpoint,
nil, urlVars, false)

require.Equal(t, http.StatusOK, rr.Code)
})

t.Run("error - resource not found", func(t *testing.T) {
or := &endpointmocks.OrbResolver{}
or.ResolveDocumentReturns(nil, orberrors.ErrContentNotFound)

c, err := restapi.New(&restapi.Config{
OperationPath: "/op",
ResolutionPath: "/resolve",
WebCASPath: "/cas",
ServiceEndpointURL: testutil.MustParseURL("http://base/services/orb"),
},
&restapi.Providers{OrbResolver: or})
require.NoError(t, err)

handler := getHandler(t, c, orbDIDResolverEndpoint)

urlVars := make(map[string]string)
urlVars["id"] = "uAAA:" + suffix

rr := serveHTTP(t, handler.Handler(), http.MethodGet, orbDIDResolverEndpoint,
nil, urlVars, false)

require.Equal(t, http.StatusNotFound, rr.Code)
require.Contains(t, rr.Body.String(), "resource not found")
})

t.Run("error - internal server error", func(t *testing.T) {
or := &endpointmocks.OrbResolver{}
or.ResolveDocumentReturns(nil, fmt.Errorf("internal error"))

c, err := restapi.New(&restapi.Config{
OperationPath: "/op",
ResolutionPath: "/resolve",
WebCASPath: "/cas",
ServiceEndpointURL: testutil.MustParseURL("http://base/services/orb"),
},
&restapi.Providers{OrbResolver: or})
require.NoError(t, err)

handler := getHandler(t, c, orbDIDResolverEndpoint)

urlVars := make(map[string]string)
urlVars["id"] = suffix

rr := serveHTTP(t, handler.Handler(), http.MethodGet, orbDIDResolverEndpoint,
nil, urlVars, false)

require.Equal(t, http.StatusInternalServerError, rr.Code)
require.Contains(t, rr.Body.String(), "error retrieving resource")
})
}

func TestOrbWebDIDFile(t *testing.T) {
t.Run("success", func(t *testing.T) {
didDoc := make(document.Document)
Expand Down
5 changes: 0 additions & 5 deletions test/bdd/did_orb_steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,6 @@ func (d *DIDOrbSteps) clientVerifiesWebDocumentFromOrbDocument(didWebVar, didOrb
}

return diddoctransformer.VerifyWebDocumentFromOrbDocument(&didWebResolutionResult, &didOrbResolutionResult)
if err != nil {
return err
}

return nil
}

func (d *DIDOrbSteps) clientFailsToVerifyResolvedDocument() error {
Expand Down
14 changes: 14 additions & 0 deletions test/bdd/features/did-sidetree.feature
Original file line number Diff line number Diff line change
Expand Up @@ -501,11 +501,25 @@ Feature:

When client sends request to "https://orb.domain3.com/sidetree/v1/identifiers" to resolve DID document with interim did
Then check success response contains "canonicalId"
Then the response is saved to variable "orbResponse"
And the JSON path "didDocumentMetadata.equivalentId.#" of the response has 3 items
And the JSON path "didDocumentMetadata.equivalentId.0" of the response is saved to variable "eqid_0"
And the JSON path "didDocumentMetadata.equivalentId.1" of the response is saved to variable "eqid_1"

# test published did without corresponding did:web in also known as
When an HTTP GET is sent to "https://orb.domain3.com/scid/${didSuffix}/did.json"

When an HTTP GET is sent to "https://orb.domain3.com/1.0/identifiers/did:web:orb.domain3.com:scid:${didSuffix}"
Then the response is saved to variable "webResponse"

Then client verifies that web document from variable "webResponse" is produced from orb document from variable "orbResponse"

# test unpublished ID
When an HTTP GET is sent to "https://orb.domain3.com/1.0/identifiers/did:orb:uAAA:${didSuffix}"

# test equivalent IDs (canonical, HL)
When an HTTP GET is sent to "https://orb.domain3.com/1.0/identifiers/${eqid_0}"
When an HTTP GET is sent to "https://orb.domain3.com/1.0/identifiers/${eqid_1}"

When client sends request to "https://orb.domain3.com/sidetree/v1/operations" to add also known as URI "did:web:orb.domain3.com:scid:${didSuffix}" to DID document
Then check for request success
Expand Down

0 comments on commit 9ec67d7

Please sign in to comment.