コンテンツにスキップ

Request Rewrite Plugins

Mayhem has support for request rewriting via plugins, which are standalone programs that implement a protobuf interface and expose it via gRPC.

The interface details are below. But first...

Do I Need This?

We've tried to make Mayhem work out of the box for as many use-cases as we can, and we'll keep adding more. The request rewrite plugin is intended as a kind of escape-hatch for situations where an API has requirements that we can't currently meet out of the box.

Here are the cases we had in mind when building the feature:

Just In Time Authentication

In any situation where the authentication needs to change during a testing job, we don't currently have a solution directly in Mayhem for API.

A request rewrite plugin can inject the appropriate credentials at whatever cadence your API requires.

Request Digesting/Signing

If your API uses any kind of digesting or signing as authentication measures, Mayhem will be unable to generate valid requests.

A request rewrite plugin can compute and inject these per-request checksums or signatures.

Something else?

The request plugin interface is extremely open-ended, and can rewrite just about any part of any request.

If you're thinking about using a rewrite plugin for any reason, please get in touch. This is a very young, very raw feature, and we'd like to know how people are using it, and how we can make it better!

Interface

Invocation

To add a request rewrite plugin to an API testing run, use the --rewrite-plugin <path-to-plugin-executable> argument to mapi run.

Executable gRPC Server

mapi will run the executable with no command-line arguments, and expects it to be a long-lived process that: * listens for gRPC traffic on a localhost port * prints the port number, followed by a newline, to stdout as the first line

Beyond that, it can do whatever it wants. Additional stdout/stderr output from the plugin are forwarded to the mapi debug logs.

At the end of the testing run, mapi will attempt to kill the plugin process.

Protobuf

Request rewrite plugins implement the following protobuf interface:

syntax = "proto3";

package mapi.rewrite;

service RewritePlugin {
   rpc Rewrite(Request) returns (Request);
}

message Request {
   message Header {
      bytes name = 1;
      bytes value = 2;
   }
   string url = 1;
   repeated Header headers = 2;
   bytes body = 3;
   string http_method = 4;
}

Example

Here's an example request rewrite plugin, which does... absolutely nothing, just returning the original request unchanged!

First, generate all of the gRPC and protobuf boilerplate from the .proto above:

$ pip install grpcio-tools
$ python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. request-rewrite-plugin.proto

Then create a python program which implements the RewritePluginServicer, stands up a gRPC server, and lets mapi know what port it's listening on:

#!/usr/bin/env python

import sys
from concurrent import futures
import grpc
import request_rewrite_plugin_pb2
import request_rewrite_plugin_pb2_grpc

## implement the RewritePlugin interface
class RewritePluginServicer(request_rewrite_plugin_pb2_grpc.RewritePluginServicer):
    def Rewrite(self, request, context):
        ## well, this isn't very interesting :)
        return request

if __name__ == '__main__':
    ## boot up the gRPC server
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    request_rewrite_plugin_pb2_grpc.add_RewritePluginServicer_to_server(
        RewritePluginServicer(), server)
    server.add_insecure_port('127.0.0.1:50051')
    server.start()

    ## inform mapi of the port we're listening on
    print("50051")
    sys.stdout.flush()

    server.wait_for_termination()

Make sure your .py file is executable, then pass it to mapi via --rewrite-plugin. That's it!

More Examples

Please visit our GitHub Repository for more examples that you can try yourself!

Caveats and Cautions

bytes, Not string!

Mayhem API testing requests are not always representable as strings. Be careful!

Subject to Change

All of this is volatile and subject to change. If you're using this feature, please get in touch, so that we can keep you in the loop as we consider refinements and changes.

Injected Header Secrets

If a rewrite plugin adds a sensitive header into the request, option --redact-header may be used to suppress the value of the added header in the reports. See Suppressing Header Secrets for more details.