feat: propagate GRPC metadata across go-micro services

The server handlers for go-micro reuse the data from reva so the
propagation also works with reva services.
Both reva and go-micro services will propagate the data correctly.
This commit is contained in:
Juan Pablo Villafáñez
2025-12-16 14:18:58 +01:00
parent ddf5ecd719
commit d3f328320a
3 changed files with 105 additions and 3 deletions

View File

@@ -0,0 +1,66 @@
package metadata
import (
"context"
"strings"
"github.com/owncloud/reva/v2/pkg/rgrpc"
"go-micro.dev/v4/server"
"google.golang.org/grpc/metadata"
)
const (
// Prefix used to auto propagate GRPC metadata keys across servers.
// This is used in the NewHandlerWrapper and NewSubscriberWrapper, and
// it's expected to work in go-micro services.
// It needs to match the prefix used in reva for the same purpose.
AutoPropPrefix = rgrpc.AutoPropPrefix
)
// NewHandlerWrapper propagates the grpc metadata.
func NewHandlerWrapper() server.HandlerWrapper {
return func(h server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.MD{}
}
pairs := make([]string, 0, md.Len()*2)
for key, values := range md {
if strings.HasPrefix(key, AutoPropPrefix) {
for _, value := range values {
pairs = append(pairs, key, value)
}
}
}
newctx := metadata.AppendToOutgoingContext(ctx, pairs...)
return h(newctx, req, rsp)
}
}
}
// NewSubscriberWrapper propagates the grpc metadata
func NewSubscriberWrapper() server.SubscriberWrapper {
return func(next server.SubscriberFunc) server.SubscriberFunc {
return func(ctx context.Context, msg server.Message) error {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.MD{}
}
pairs := make([]string, 0, md.Len()*2)
for key, values := range md {
if strings.HasPrefix(key, AutoPropPrefix) {
for _, value := range values {
pairs = append(pairs, key, value)
}
}
}
newctx := metadata.AppendToOutgoingContext(ctx, pairs...)
return next(newctx, msg)
}
}
}

View File

@@ -21,6 +21,7 @@ import (
ociscrypto "github.com/owncloud/ocis/v2/ocis-pkg/crypto"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/registry"
ocismetadata "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc/handler/metadata"
)
// Service simply wraps the go-micro grpc service.
@@ -64,6 +65,7 @@ func NewServiceWithClient(client client.Client, opts ...Option) (Service, error)
mtracer.NewHandlerWrapper(
mtracer.WithTraceProvider(sopts.TraceProvider),
),
ocismetadata.NewHandlerWrapper(),
}
if sopts.Logger.GetLevel() == zerolog.DebugLevel {
handlerWrappers = append(handlerWrappers, LogHandler(&sopts.Logger))
@@ -87,9 +89,10 @@ func NewServiceWithClient(client client.Client, opts ...Option) (Service, error)
mtracer.WithTraceProvider(sopts.TraceProvider),
)),
micro.WrapHandler(handlerWrappers...),
micro.WrapSubscriber(mtracer.NewSubscriberWrapper(
mtracer.WithTraceProvider(sopts.TraceProvider),
)),
micro.WrapSubscriber(
mtracer.NewSubscriberWrapper(mtracer.WithTraceProvider(sopts.TraceProvider)),
ocismetadata.NewSubscriberWrapper(),
),
}
return Service{micro.NewService(mopts...)}, nil

View File

@@ -6,6 +6,7 @@ import (
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/reva/v2/pkg/auth/manager/publicshares"
"github.com/owncloud/reva/v2/pkg/rgrpc/todo/pool"
)
@@ -91,6 +92,38 @@ func (a PublicShareAuthenticator) Authenticate(r *http.Request) (*http.Request,
}
}
client, err := a.RevaGatewaySelector.Next()
if err != nil {
a.Logger.Error().
Err(err).
Str("authenticator", "public_share").
Str("public_share_token", shareToken).
Str("path", r.URL.Path).
Msg("could not select next gateway client")
return nil, false
}
// we just need the reva access token, so we want to skip the brute force
// protection in this case
ctx := publicshares.MarkSkipAttemptContext(r.Context(), shareToken)
authResp, err := client.Authenticate(ctx, &gateway.AuthenticateRequest{
Type: authenticationType,
ClientId: shareToken,
ClientSecret: sharePassword,
})
if err != nil {
a.Logger.Error().
Err(err).
Str("authenticator", "public_share").
Str("public_share_token", shareToken).
Str("path", r.URL.Path).
Msg("failed to authenticate request")
return nil, false
}
r.Header.Add(_headerRevaAccessToken, authResp.Token)
a.Logger.Debug().
Str("authenticator", "public_share").
Str("path", r.URL.Path).