bearer: add some tests
This commit is contained in:
@@ -2,7 +2,6 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"iter"
|
"iter"
|
||||||
"slices"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -14,7 +13,13 @@ import (
|
|||||||
|
|
||||||
func TestFindProof(t *testing.T) {
|
func TestFindProof(t *testing.T) {
|
||||||
dlgs := func() iter.Seq[*delegation.Bundle] {
|
dlgs := func() iter.Seq[*delegation.Bundle] {
|
||||||
return slices.Values(delegationtest.AllBundles)
|
return func(yield func(*delegation.Bundle) bool) {
|
||||||
|
for _, bundle := range delegationtest.AllBundles {
|
||||||
|
if !yield(&bundle) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, delegationtest.ProofAliceBob,
|
require.Equal(t, delegationtest.ProofAliceBob,
|
||||||
|
|||||||
32
toolkit/server/bearer/bearer_test.go
Normal file
32
toolkit/server/bearer/bearer_test.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package bearer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/ucan-wg/go-ucan/pkg/container"
|
||||||
|
"github.com/ucan-wg/go-ucan/pkg/container/containertest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHTTPBearer(t *testing.T) {
|
||||||
|
for _, fn := range []func(h http.Header, container container.Writer) error{
|
||||||
|
AddBearerContainer,
|
||||||
|
AddBearerContainerCompressed,
|
||||||
|
} {
|
||||||
|
r, err := http.NewRequest(http.MethodPost, "/foo/bar", nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cont, err := container.FromBytes(containertest.Bytes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = fn(r.Header, cont.ToWriter())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
contRead, err := ExtractBearerContainer(r.Header)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NotEmpty(t, contRead)
|
||||||
|
require.Equal(t, cont, contRead)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package exectx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/INFURA/go-ucan-toolkit/server/bearer"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Middleware returns an HTTP middleware tasked with:
|
|
||||||
// - extracting UCAN credentials from the `Authorization: Bearer <data>` HTTP header
|
|
||||||
// - performing basic checks, and returning HTTP errors if necessary
|
|
||||||
// - exposing those credentials in the go context as a UcanCtx for further usage
|
|
||||||
func Middleware(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
ctn, err := bearer.ExtractBearerContainer(r.Header)
|
|
||||||
if errors.Is(err, bearer.ErrNoUcan) {
|
|
||||||
http.Error(w, "no UCAN auth", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if errors.Is(err, bearer.ErrContainerMalformed) {
|
|
||||||
http.Error(w, "malformed token", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
// should not happen, defensive programming
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare a UcanCtx from the container, for further evaluation in the server pipeline
|
|
||||||
ucanCtx, err := FromContainer(ctn)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert into the go context
|
|
||||||
r = r.WithContext(AddUcanCtxToContext(r.Context(), ucanCtx))
|
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
87
toolkit/server/exectx/middlewares.go
Normal file
87
toolkit/server/exectx/middlewares.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package exectx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/ucan-wg/go-ucan/did"
|
||||||
|
|
||||||
|
"github.com/INFURA/go-ucan-toolkit/server/bearer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExtractMW returns an HTTP middleware tasked with:
|
||||||
|
// - extracting UCAN credentials from the `Authorization: Bearer <data>` HTTP header
|
||||||
|
// - performing basic checks, and returning HTTP errors if necessary
|
||||||
|
// - verify that the invocation targets our service
|
||||||
|
// - exposing those credentials in the go context as a UcanCtx for further usage
|
||||||
|
func ExtractMW(next http.Handler, serviceDID did.DID) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctn, err := bearer.ExtractBearerContainer(r.Header)
|
||||||
|
if errors.Is(err, bearer.ErrNoUcan) {
|
||||||
|
http.Error(w, "no UCAN auth", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if errors.Is(err, bearer.ErrContainerMalformed) {
|
||||||
|
http.Error(w, "malformed token", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// should not happen, defensive programming
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare a UcanCtx from the container, for further evaluation in the server pipeline
|
||||||
|
ucanCtx, err := FromContainer(ctn)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ucanCtx.Invocation().Subject() != serviceDID {
|
||||||
|
http.Error(w, "UCAN delegation doesn't match the service DID", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert into the go context
|
||||||
|
r = r.WithContext(AddUcanCtxToContext(r.Context(), ucanCtx))
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HttpExtArgsVerify returns an HTTP middleware tasked with verifying the UCAN policies applying on the HTTP request.
|
||||||
|
func HttpExtArgsVerify(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ucanCtx, ok := FromContext(r.Context())
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "no ucan-ctx found", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ucanCtx.VerifyHttp(r); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnforceMW returns an HTTP middleware tasked with the final verification of the UCAN policies.
|
||||||
|
func EnforceMW(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ucanCtx, ok := FromContext(r.Context())
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "no ucan-ctx found", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ucanCtx.ExecutionAllowed(); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user