Skip to content

Commit

Permalink
proxy+auth: fix post request
Browse files Browse the repository at this point in the history
  • Loading branch information
guggero committed May 24, 2024
1 parent 3a8936c commit 9ad67ea
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 15 deletions.
4 changes: 2 additions & 2 deletions auth/authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ const (
// complete.
//
// NOTE: This is part of the Authenticator interface.
func (l *L402Authenticator) FreshChallengeHeader(r *http.Request,
serviceName string, servicePrice int64) (http.Header, error) {
func (l *L402Authenticator) FreshChallengeHeader(serviceName string,
servicePrice int64) (http.Header, error) {

service := l402.Service{
Name: serviceName,
Expand Down
2 changes: 1 addition & 1 deletion auth/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type Authenticator interface {

// FreshChallengeHeader returns a header containing a challenge for the
// user to complete.
FreshChallengeHeader(*http.Request, string, int64) (http.Header, error)
FreshChallengeHeader(string, int64) (http.Header, error)
}

// Minter is an entity that is able to mint and verify L402s for a set of
Expand Down
4 changes: 2 additions & 2 deletions auth/mock_authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ func (a MockAuthenticator) Accept(header *http.Header, _ string) bool {

// FreshChallengeHeader returns a header containing a challenge for the user to
// complete.
func (a MockAuthenticator) FreshChallengeHeader(r *http.Request,
_ string, _ int64) (http.Header, error) {
func (a MockAuthenticator) FreshChallengeHeader(string, int64) (http.Header,
error) {

header := http.Header{
"Content-Type": []string{"application/grpc"},
Expand Down
2 changes: 1 addition & 1 deletion proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ func (p *Proxy) handlePaymentRequired(w http.ResponseWriter, r *http.Request,
serviceName string, servicePrice int64) {

header, err := p.authenticator.FreshChallengeHeader(
r, serviceName, servicePrice,
serviceName, servicePrice,
)
if err != nil {
log.Errorf("Error creating new challenge header: %v", err)
Expand Down
36 changes: 27 additions & 9 deletions proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,19 @@ func TestProxyHTTP(t *testing.T) {
for _, tc := range testCases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
runHTTPTest(t, tc)
t.Run(tc.name+" GET", func(t *testing.T) {
runHTTPTest(t, tc, "GET")
})

t.Run(tc.name+" POST", func(t *testing.T) {
runHTTPTest(t, tc, "POST")
})
}
}

// TestProxyHTTP tests that the proxy can forward HTTP requests to a backend
// service and handle L402 authentication correctly.
func runHTTPTest(t *testing.T, tc *testCase) {
func runHTTPTest(t *testing.T, tc *testCase, method string) {
// Create a list of services to proxy between.
services := []*proxy.Service{{
Address: testTargetServiceAddress,
Expand Down Expand Up @@ -148,11 +152,25 @@ func runHTTPTest(t *testing.T, tc *testCase) {
// Authorization header set.
client := &http.Client{}
url := fmt.Sprintf("http://%s/http/test", testProxyAddr)
resp, err := client.Get(url)

req, err := http.NewRequest(method, url, nil)
require.NoError(t, err)

if method == "POST" {
req.Header.Add("Content-Type", "application/json")
req.Body = io.NopCloser(strings.NewReader(`{}`))
}

resp, err := client.Do(req)
require.NoError(t, err)

require.Equal(t, "402 Payment Required", resp.Status)

bodyContent, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, "payment required\n", string(bodyContent))
require.EqualValues(t, len(bodyContent), resp.ContentLength)

authHeader := resp.Header.Get("Www-Authenticate")
require.Regexp(t, "(LSAT|L402)", authHeader)
_ = resp.Body.Close()
Expand All @@ -161,7 +179,7 @@ func runHTTPTest(t *testing.T, tc *testCase) {
// get the 402 response.
if len(tc.authWhitelist) > 0 {
url = fmt.Sprintf("http://%s/http/white", testProxyAddr)
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(method, url, nil)
require.NoError(t, err)
resp, err = client.Do(req)
require.NoError(t, err)
Expand All @@ -174,11 +192,12 @@ func runHTTPTest(t *testing.T, tc *testCase) {
require.NoError(t, err)

require.Equal(t, testHTTPResponseBody, string(bodyBytes))
require.EqualValues(t, len(bodyBytes), resp.ContentLength)
}

// Make sure that if the Auth header is set, the client's request is
// proxied to the backend service.
req, err := http.NewRequest("GET", url, nil)
req, err = http.NewRequest(method, url, nil)
require.NoError(t, err)
req.Header.Add("Authorization", "foobar")

Expand All @@ -193,6 +212,7 @@ func runHTTPTest(t *testing.T, tc *testCase) {
require.NoError(t, err)

require.Equal(t, testHTTPResponseBody, string(bodyBytes))
require.EqualValues(t, len(bodyBytes), resp.ContentLength)
}

// TestProxyHTTP tests that the proxy can forward gRPC requests to a backend
Expand Down Expand Up @@ -313,9 +333,7 @@ func runGRPCTest(t *testing.T, tc *testCase) {

// We expect the WWW-Authenticate header field to be set to an L402
// auth response.
expectedHeaderContent, _ := mockAuth.FreshChallengeHeader(&http.Request{
Header: map[string][]string{},
}, "", 0)
expectedHeaderContent, _ := mockAuth.FreshChallengeHeader("", 0)
capturedHeader := captureMetadata.Get("WWW-Authenticate")
require.Len(t, capturedHeader, 2)
require.Equal(
Expand Down

0 comments on commit 9ad67ea

Please sign in to comment.