2

I've setup a grpc-gateway for a small testbed service and I have a UnaryServerInterceptor setup that checks authorization bearer tokens and validate against an SSO introspection URL.

func (im *Middleware) GRPCAuthenticator() grpc.UnaryServerInterceptor {
    return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
        md, ok := metadata.FromIncomingContext(ctx)
        if !ok {
            return nil, status.Errorf(codes.Unauthenticated, "metadata is not provided.")
        }

        values := md[Authorization]
        if len(values) == 0 {
            grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "401"))
            return nil, status.Errorf(codes.Unauthenticated, "authorization token is not provided.")
        }

        accessToken := values[0]
        res, err := im.client.Introspect(ctx, accessToken)
        if err != nil {
            grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "401"))
            return nil, status.Errorf(codes.Unauthenticated, err.Error())
        }

        if !res.Valid() {
            grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "401"))
            return nil, status.Errorf(codes.Unauthenticated, "invalid token: either expired or inactive.")
        }

        return handler(ctx, req)
    }
}

I also have a forwardResponseOption that I use for (hopefully) controlling returned errors and write it to http.ResponseWriter.

mux := runtime.NewServeMux(
    runtime.WithForwardResponseOption(httpResponseModifier),
)
.
.
.
func httpResponseModifier(ctx context.Context, w http.ResponseWriter, p proto.Message) error {
    fmt.Println("httpResponseModifier!!!!!!!!!!")
    md, ok := runtime.ServerMetadataFromContext(ctx)
    if !ok {
        return nil
    }

    // set http status code
    if vals := md.HeaderMD.Get("x-http-code"); len(vals) > 0 {
        code, err := strconv.Atoi(vals[0])
        if err != nil {
            return err
        }
        // delete the headers to not expose any grpc-metadata in http response
        delete(md.HeaderMD, "x-http-code")
        delete(w.Header(), "Grpc-Metadata-X-Http-Code")
        w.WriteHeader(code)
    }

    return nil
}

when a token is good and valid and proceeds to the rpc method, it shows that it goes thru. enter image description here

But when it's terminated at the interceptor, it doesn't.

Was forwardResponseOption not the one I'm looking for in capturing responses given by (and terminated at) a UnaryServerInterceptor?

Odinovsky
  • 551
  • 1
  • 6
  • 23

0 Answers0