-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot alter authorisation headers when verifying pact #702
Comments
request filters work by having a proxy application, that receives the requests from the mock consumer, and allowing callbacks, to modify the request contents before being sent to the application under test. Ideally its provided to the user by the framework for ease of use, but there should be nothing stopping you from doing that yourself |
Here is my sample contract verification in PHP: It would be nice to have something like: $verifier->requestCallback(function (Request $request): void {
$request->headers->set('Authorization', $this->getTokenForPayload($request->getContent()));
});
$verify = $verifier->verify(); I've manage to do some workaround inside the app, which you can check here - https://gist.github.com/lkankowski/2cee67803f2c45c274b9609af26ff5ab#file-pactrequestsignsubscriber-php |
$verifier->requestCallback(function (Request $request): void {
$request->headers->set('Authorization', $this->getTokenForPayload($request->getContent()));
}); I assume you are using v10. I think it's currently not possible to do that, because pact-reference (pact-core) doesn't have a way to implement it.
I think your solution is acceptable since pact-php doesn't provide a way to do it. |
Or, you can create a simple proxy to do it for you. Here is an example code in go: package main
import (
"encoding/base64"
"flag"
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
)
func proxyHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Received request", r.Method, r.URL)
proxy := &httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) {
dest := fmt.Sprintf("%s:%s", os.Getenv("DEST_HOST"), os.Getenv("DEST_PORT"))
target, _ := url.Parse(dest)
r.SetURL(target)
sig := "some signature calculation" # based on r.In
r.Out.Header.Add("Authorization", sig)
},
}
proxy.ServeHTTP(w, r)
}
func main() {
var help = flag.Bool("help", false, "help")
var host = flag.String("host", "127.0.0.1", "proxy host")
var port = flag.String("port", "8888", "proxy port")
flag.Parse()
if *help {
fmt.Println("Pact Proxy")
fmt.Println("")
fmt.Println("This program attach Authorization header and proxy requests to the real selenium server.")
fmt.Println("")
fmt.Println("Usage: env DEST_HOST=192.168.1.11 DEST_PORT=9999 ./main --host=127.0.0.1 --port=8888")
os.Exit(1)
}
var addr = fmt.Sprintf("%s:%s", *host, *port)
http.HandleFunc("/", proxyHandler)
log.Println("Starting proxy server on", addr)
if err := http.ListenAndServe(addr, nil); err != nil {
log.Fatalf("Can not start proxy: %s", err)
}
} |
Or you can use the provider state approach. Consumer side: $request = new ConsumerRequest();
$request
// ...
->addHeader('Authorization', $this->matcher->fromProviderState($this->matcher->string(), '${signature}'));
$response = new ProviderResponse();
// ...
$config = new MockServerConfig();
// ...
$builder = new InteractionBuilder($config);
$builder
->uponReceiving('A request with uuid cfeda9c2-fc1a-42ae-862a-10f7192eb96e')
->with($request)
->willRespondWith($response); Provider side: (Look like you are using Symfony, so I will suggest the code from my own bundle to make life easier) namespace App\StateHandler;
use Tienvx\Bundle\PactProviderBundle\Attribute\AsStateHandler;
use Tienvx\Bundle\PactProviderBundle\Model\StateValues;
use Tienvx\Bundle\PactProviderBundle\StateHandler\SetUpInterface;
use Tienvx\Bundle\PactProviderBundle\StateHandler\TearDownInterface;
#[AsStateHandler(state: 'A request with uuid cfeda9c2-fc1a-42ae-862a-10f7192eb96e')]
class UserHandler implements SetUpInterface, TearDownInterface
{
public function setUp(array $params): ?StateValues
{
return new StateValues([
'signature' => 'hard coded signature for this request only',
]);
}
public function tearDown(array $params): void
{
}
} This approach probably not what you want. But at least you can find that my bundle is useful and can be used in other places. |
@tienvx Thank you for all comments and ideas. Nice to know about your bundle :) The answer about "it is impossible in v10" is enough to close this issue, as there are enough workarounds. But, stil I think there should be a nicer way... :) |
Hi.
I have a code where requests payload is signed with a secret.
I am aware of https://docs.pact.io/provider/handling_auth#4-modify-the-request-to-use-real-credentials, but it does not apply to signing content.
Ideal solution would be some request filter, so I could get real content, calculate signature and generate appropriate header.
Another solution is to give ability in provider setting state access to real request, but this is meant for different thing.
The text was updated successfully, but these errors were encountered: