server: add a WIP middleware example
This commit is contained in:
committed by
Michael Muré
parent
3ec8f56412
commit
1178e51b18
28
toolkit/server/context.go
Normal file
28
toolkit/server/context.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type contextKey string
|
||||||
|
|
||||||
|
var ctxUserId = contextKey("userId")
|
||||||
|
var ctxProjectId = contextKey("projectId")
|
||||||
|
|
||||||
|
// ContextGetUserId return the UserId stored in the context, if it exists.
|
||||||
|
func ContextGetUserId(ctx context.Context) (string, bool) {
|
||||||
|
val, ok := ctx.Value(ctxUserId).(string)
|
||||||
|
return val, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func addUserIdToContext(ctx context.Context, userId string) context.Context {
|
||||||
|
return context.WithValue(ctx, ctxUserId, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextGetProjectId return the ProjectID stored in the context, if it exists.
|
||||||
|
func ContextGetProjectId(ctx context.Context) (string, bool) {
|
||||||
|
val, ok := ctx.Value(ctxProjectId).(string)
|
||||||
|
return val, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func addProjectIdToContext(ctx context.Context, projectId string) context.Context {
|
||||||
|
return context.WithValue(ctx, ctxProjectId, projectId)
|
||||||
|
}
|
||||||
80
toolkit/server/middleware.go
Normal file
80
toolkit/server/middleware.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ucan-wg/go-ucan/delegation"
|
||||||
|
"github.com/ucan-wg/go-ucan/did"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Middleware func(http.Handler) http.Handler
|
||||||
|
|
||||||
|
func ExampleMiddleware(serviceDID did.DID) Middleware {
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
tokenReader, ok := extractBearerToken(r)
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "missing or malformed UCAN HTTP Bearer token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode
|
||||||
|
// TODO: ultimately, this token should be a container with one invocation and 1+ delegations.
|
||||||
|
// We are doing something simpler for now.
|
||||||
|
dlg, err := delegation.FromDagCborReader(tokenReader)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "malformed UCAN delegation", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional: http-bearer
|
||||||
|
|
||||||
|
// validate
|
||||||
|
if dlg.Subject() != serviceDID {
|
||||||
|
http.Error(w, "invalid UCAN delegation", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: policies check + inject in context
|
||||||
|
|
||||||
|
// extract values
|
||||||
|
userId, err := dlg.Meta().GetString("userId")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "missing or malformed userId", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
projectId, err := dlg.Meta().GetString("projectId")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "missing or malformed projectId", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// inject into context
|
||||||
|
ctx = addUserIdToContext(ctx, userId)
|
||||||
|
ctx = addProjectIdToContext(ctx, projectId)
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractBearerToken(r *http.Request) (io.Reader, bool) {
|
||||||
|
header := r.Header.Get("Authorization")
|
||||||
|
if header == "" {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(header, "Bearer ") {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip prefix
|
||||||
|
reader := strings.NewReader(header[len("Bearer "):])
|
||||||
|
|
||||||
|
// base64 decode
|
||||||
|
return base64.NewDecoder(base64.StdEncoding, reader), true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user