Skip to content

Commit

Permalink
Merge branch 'master' into marco/filter-dial-addrs
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoPolo authored Oct 15, 2024
2 parents fc2d270 + fa09c6c commit 972275f
Show file tree
Hide file tree
Showing 13 changed files with 2,130 additions and 42 deletions.
14 changes: 7 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,18 @@ require (
github.com/pion/webrtc/v3 v3.3.0
github.com/prometheus/client_golang v1.19.1
github.com/prometheus/client_model v0.6.1
github.com/quic-go/quic-go v0.45.2
github.com/quic-go/quic-go v0.47.0
github.com/quic-go/webtransport-go v0.8.0
github.com/raulk/go-watchdog v1.3.0
github.com/stretchr/testify v1.9.0
go.uber.org/fx v1.22.1
go.uber.org/goleak v1.3.0
go.uber.org/mock v0.4.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.25.0
golang.org/x/crypto v0.26.0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/sync v0.7.0
golang.org/x/sys v0.22.0
golang.org/x/sync v0.8.0
golang.org/x/sys v0.23.0
golang.org/x/tools v0.23.0
google.golang.org/protobuf v1.34.2
)
Expand Down Expand Up @@ -118,15 +118,15 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/wlynxg/anet v0.0.3 // indirect
go.uber.org/dig v1.17.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/text v0.17.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
)
28 changes: 14 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,10 @@ github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/quic-go v0.45.2 h1:DfqBmqjb4ExSdxRIb/+qXhPC+7k6+DUNZha4oeiC9fY=
github.com/quic-go/quic-go v0.45.2/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y=
github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E=
github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg=
github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM=
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
Expand Down Expand Up @@ -445,8 +445,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
Expand Down Expand Up @@ -487,8 +487,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand All @@ -504,8 +504,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -537,8 +537,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
Expand All @@ -555,8 +555,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
Expand Down
11 changes: 11 additions & 0 deletions p2p/http/auth/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package httppeeridauth

import (
logging "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p/p2p/http/auth/internal/handshake"
)

const PeerIDAuthScheme = handshake.PeerIDAuthScheme
const ProtocolID = "/http-peer-id-auth/1.0.0"

var log = logging.Logger("http-peer-id-auth")
243 changes: 243 additions & 0 deletions p2p/http/auth/auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package httppeeridauth

import (
"bytes"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"crypto/tls"
"hash"
"io"
"net/http"
"net/http/httptest"
"strings"
"sync"
"testing"
"time"

logging "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestMutualAuth tests that we can do a mutually authenticated round trip
func TestMutualAuth(t *testing.T) {
logging.SetLogLevel("httppeeridauth", "DEBUG")

zeroBytes := make([]byte, 64)
serverKey, _, err := crypto.GenerateEd25519Key(bytes.NewReader(zeroBytes))
require.NoError(t, err)

type clientTestCase struct {
name string
clientKeyGen func(t *testing.T) crypto.PrivKey
}

clientTestCases := []clientTestCase{
{
name: "ED25519",
clientKeyGen: func(t *testing.T) crypto.PrivKey {
t.Helper()
clientKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
require.NoError(t, err)
return clientKey
},
},
{
name: "RSA",
clientKeyGen: func(t *testing.T) crypto.PrivKey {
t.Helper()
clientKey, _, err := crypto.GenerateRSAKeyPair(2048, rand.Reader)
require.NoError(t, err)
return clientKey
},
},
}

type serverTestCase struct {
name string
serverGen func(t *testing.T) (*httptest.Server, *ServerPeerIDAuth)
}

serverTestCases := []serverTestCase{
{
name: "no TLS",
serverGen: func(t *testing.T) (*httptest.Server, *ServerPeerIDAuth) {
t.Helper()
auth := ServerPeerIDAuth{
PrivKey: serverKey,
ValidHostnameFn: func(s string) bool {
return s == "example.com"
},
TokenTTL: time.Hour,
NoTLS: true,
}

ts := httptest.NewServer(&auth)
t.Cleanup(ts.Close)
return ts, &auth
},
},
{
name: "TLS",
serverGen: func(t *testing.T) (*httptest.Server, *ServerPeerIDAuth) {
t.Helper()
auth := ServerPeerIDAuth{
PrivKey: serverKey,
ValidHostnameFn: func(s string) bool {
return s == "example.com"
},
TokenTTL: time.Hour,
}

ts := httptest.NewTLSServer(&auth)
t.Cleanup(ts.Close)
return ts, &auth
},
},
}

for _, ctc := range clientTestCases {
for _, stc := range serverTestCases {
t.Run(ctc.name+"+"+stc.name, func(t *testing.T) {
ts, server := stc.serverGen(t)
client := ts.Client()
roundTripper := instrumentedRoundTripper{client.Transport, 0}
client.Transport = &roundTripper
requestsSent := func() int {
defer func() { roundTripper.timesRoundtripped = 0 }()
return roundTripper.timesRoundtripped
}

tlsClientConfig := roundTripper.TLSClientConfig()
if tlsClientConfig != nil {
// If we're using TLS, we need to set the SNI so that the
// server can verify the request Host matches it.
tlsClientConfig.ServerName = "example.com"
}
clientKey := ctc.clientKeyGen(t)
clientAuth := ClientPeerIDAuth{PrivKey: clientKey}

expectedServerID, err := peer.IDFromPrivateKey(serverKey)
require.NoError(t, err)

req, err := http.NewRequest("POST", ts.URL, nil)
require.NoError(t, err)
req.Host = "example.com"
serverID, resp, err := clientAuth.AuthenticatedDo(client, req)
require.NoError(t, err)
require.Equal(t, expectedServerID, serverID)
require.NotZero(t, clientAuth.tm.tokenMap["example.com"])
require.Equal(t, http.StatusOK, resp.StatusCode)
require.Equal(t, 2, requestsSent())

// Once more with the auth token
req, err = http.NewRequest("POST", ts.URL, nil)
require.NoError(t, err)
req.Host = "example.com"
serverID, resp, err = clientAuth.AuthenticatedDo(client, req)
require.NotEmpty(t, req.Header.Get("Authorization"))
require.NoError(t, err)
require.Equal(t, expectedServerID, serverID)
require.NotZero(t, clientAuth.tm.tokenMap["example.com"])
require.Equal(t, http.StatusOK, resp.StatusCode)
require.Equal(t, 1, requestsSent(), "should only call newRequest once since we have a token")

t.Run("Tokens Expired", func(t *testing.T) {
// Clear the auth token on the server side
server.TokenTTL = 1 // Small TTL
time.Sleep(100 * time.Millisecond)
resetServerTokenTTL := sync.OnceFunc(func() {
server.TokenTTL = time.Hour
})

req, err := http.NewRequest("POST", ts.URL, nil)
require.NoError(t, err)
req.Host = "example.com"
req.GetBody = func() (io.ReadCloser, error) {
resetServerTokenTTL()
return nil, nil
}
serverID, resp, err = clientAuth.AuthenticatedDo(client, req)
require.NoError(t, err)
require.NotEmpty(t, req.Header.Get("Authorization"))
require.Equal(t, http.StatusOK, resp.StatusCode)
require.Equal(t, expectedServerID, serverID)
require.NotZero(t, clientAuth.tm.tokenMap["example.com"])
require.Equal(t, 3, requestsSent(), "should call newRequest 3x since our token expired")
})

t.Run("Tokens Invalidated", func(t *testing.T) {
// Clear the auth token on the server side
server.Hmac = func() hash.Hash {
key := make([]byte, 32)
_, err := rand.Read(key)
if err != nil {
panic(err)
}
return hmac.New(sha256.New, key)
}()

req, err := http.NewRequest("POST", ts.URL, nil)
req.GetBody = func() (io.ReadCloser, error) {
return nil, nil
}
require.NoError(t, err)
req.Host = "example.com"
serverID, resp, err = clientAuth.AuthenticatedDo(client, req)
require.NoError(t, err)
require.NotEmpty(t, req.Header.Get("Authorization"))
require.Equal(t, http.StatusOK, resp.StatusCode)
require.Equal(t, expectedServerID, serverID)
require.NotZero(t, clientAuth.tm.tokenMap["example.com"])
require.Equal(t, 3, requestsSent(), "should call have sent 3 reqs since our token expired")
})

})
}
}
}

func TestBodyNotSentDuringRedirect(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := io.ReadAll(r.Body)
assert.NoError(t, err)
assert.Empty(t, string(b))
if r.URL.Path != "/redirected" {
w.Header().Set("Location", "/redirected")
w.WriteHeader(http.StatusTemporaryRedirect)
return
}
}))
t.Cleanup(ts.Close)
client := ts.Client()
clientKey, _, _ := crypto.GenerateEd25519Key(rand.Reader)
clientAuth := ClientPeerIDAuth{PrivKey: clientKey}

req, err :=
http.NewRequest(
"POST",
ts.URL,
strings.NewReader("Only for authenticated servers"),
)
req.Host = "example.com"
require.NoError(t, err)
_, _, err = clientAuth.AuthenticatedDo(client, req)
require.ErrorContains(t, err, "signature not set") // server doesn't actually handshake
}

type instrumentedRoundTripper struct {
http.RoundTripper
timesRoundtripped int
}

func (irt *instrumentedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
irt.timesRoundtripped++
return irt.RoundTripper.RoundTrip(req)
}

func (irt *instrumentedRoundTripper) TLSClientConfig() *tls.Config {
return irt.RoundTripper.(*http.Transport).TLSClientConfig
}
Loading

0 comments on commit 972275f

Please sign in to comment.