Redesign authentication protocol

This commit is contained in:
2019-02-22 17:35:49 +01:00
parent 4a69555578
commit 19732daaf5
33 changed files with 791 additions and 413 deletions

View File

@ -5,6 +5,11 @@ import (
"testing"
"time"
"forge.cadoles.com/wpetit/go-http-peering/client"
peeringCrypto "forge.cadoles.com/wpetit/go-http-peering/crypto"
"forge.cadoles.com/wpetit/go-http-peering/memory"
"forge.cadoles.com/wpetit/go-http-peering/server"
peering "forge.cadoles.com/wpetit/go-http-peering"
"forge.cadoles.com/wpetit/go-http-peering/crypto"
)
@ -15,19 +20,35 @@ func TestAdvertise(t *testing.T) {
t.SkipNow()
}
id, pk, client, store := setup(t)
store := memory.NewStore()
serverPK := mustGeneratePrivateKey()
clientPK := mustGeneratePrivateKey()
peerID := peering.NewPeerID()
serverToken, err := peeringCrypto.CreateServerToken(serverPK, "test", peerID)
if err != nil {
t.Fatal(err)
}
advertise := server.AdvertiseHandler(store, &serverPK.PublicKey)
client := client.New(
client.WithHTTPClient(NewHTTPClientMock(advertise)),
client.WithPrivateKey(clientPK),
client.WithServerToken(serverToken),
)
attrs := peering.PeerAttributes{}
if err := client.Advertise(attrs); err != nil {
t.Fatal(err)
}
peer, err := store.Get(id)
peer, err := store.Get(peerID)
if err != nil {
t.Error(err)
}
if g, e := peer.ID, id; g != e {
if g, e := peer.ID, peerID; g != e {
t.Errorf("peer.ID: got '%v', expected '%v'", g, e)
}
@ -40,11 +61,7 @@ func TestAdvertise(t *testing.T) {
t.Error("peer.LastContact should not be time.Time zero value")
}
if peer.LastAddress == "" {
t.Error("peer.LastAddress should not be empty")
}
pem, err := crypto.EncodePublicKeyToPEM(pk.Public())
pem, err := crypto.EncodePublicKeyToPEM(clientPK.Public())
if err != nil {
t.Fatal(err)
}

View File

@ -4,6 +4,10 @@ import (
"testing"
peering "forge.cadoles.com/wpetit/go-http-peering"
"forge.cadoles.com/wpetit/go-http-peering/client"
peeringCrypto "forge.cadoles.com/wpetit/go-http-peering/crypto"
"forge.cadoles.com/wpetit/go-http-peering/memory"
"forge.cadoles.com/wpetit/go-http-peering/server"
)
func TestPing(t *testing.T) {
@ -12,33 +16,67 @@ func TestPing(t *testing.T) {
t.SkipNow()
}
id, _, client, store := setup(t)
store := memory.NewStore()
serverPK := mustGeneratePrivateKey()
clientPK := mustGeneratePrivateKey()
peerID := peering.NewPeerID()
attrs := peering.PeerAttributes{}
if err := client.Advertise(attrs); err != nil {
t.Fatal(err)
}
peer, err := store.Get(id)
// Generate a server token for the peer client
serverToken, err := peeringCrypto.CreateServerToken(serverPK, "test", peerID)
if err != nil {
t.Fatal(err)
}
advertise := server.AdvertiseHandler(store, &serverPK.PublicKey)
// Create advertise client
c := client.New(
client.WithHTTPClient(NewHTTPClientMock(advertise)),
client.WithPrivateKey(clientPK),
client.WithServerToken(serverToken),
)
// Advertise client with empty peer attributes
attrs := peering.PeerAttributes{}
if err := c.Advertise(attrs); err != nil {
t.Fatal(err)
}
// Retrieve peer from store
peer, err := store.Get(peerID)
if err != nil {
t.Fatal(err)
}
// Store last contact after advertising
lastContact := peer.LastContact
if err := store.Accept(id); err != nil {
// Accept peer
if err := store.Accept(peerID); err != nil {
t.Error(err)
}
if err := client.Ping(); err != nil {
// Create ping authenticated handler
ping := server.Authenticate(store, &serverPK.PublicKey)(server.PingHandler(store))
// Create client
c = client.New(
client.WithHTTPClient(NewHTTPClientMock(ping)),
client.WithPrivateKey(clientPK),
client.WithServerToken(serverToken),
)
// Do ping
if err := c.Ping(); err != nil {
t.Fatal(err)
}
peer, err = store.Get(id)
// Retrieve peer
peer, err = store.Get(peerID)
if err != nil {
t.Fatal(err)
}
// Assert that last contact has changed after ping
if peer.LastContact == lastContact {
t.Error("peer.LastContact should have been updated")
}

View File

@ -6,7 +6,11 @@ import (
"time"
peering "forge.cadoles.com/wpetit/go-http-peering"
"forge.cadoles.com/wpetit/go-http-peering/client"
"forge.cadoles.com/wpetit/go-http-peering/crypto"
peeringCrypto "forge.cadoles.com/wpetit/go-http-peering/crypto"
"forge.cadoles.com/wpetit/go-http-peering/memory"
"forge.cadoles.com/wpetit/go-http-peering/server"
)
func TestUpdate(t *testing.T) {
@ -15,42 +19,77 @@ func TestUpdate(t *testing.T) {
t.SkipNow()
}
id, pk, client, store := setup(t)
store := memory.NewStore()
serverPK := mustGeneratePrivateKey()
clientPK := mustGeneratePrivateKey()
peerID := peering.NewPeerID()
attrs := peering.PeerAttributes{}
if err := client.Advertise(attrs); err != nil {
t.Fatal(err)
}
if err := store.Accept(id); err != nil {
t.Error(err)
}
attrs["Label"] = "Foo Bar"
if err := client.UpdateAttributes(attrs); err != nil {
t.Fatal(err)
}
peer, err := store.Get(id)
// Generate a server token for the peer client
serverToken, err := peeringCrypto.CreateServerToken(serverPK, "test", peerID)
if err != nil {
t.Fatal(err)
}
if g, e := peer.ID, id; g != e {
advertise := server.AdvertiseHandler(store, &serverPK.PublicKey)
// Create advertise client
c := client.New(
client.WithHTTPClient(NewHTTPClientMock(advertise)),
client.WithPrivateKey(clientPK),
client.WithServerToken(serverToken),
)
// Advertise client with empty peer attributes
attrs := peering.PeerAttributes{}
if err := c.Advertise(attrs); err != nil {
t.Fatal(err)
}
// Accept peer
if err := store.Accept(peerID); err != nil {
t.Error(err)
}
// Create authenticated update handler
update := server.Authenticate(store, &serverPK.PublicKey)(server.UpdateHandler(store))
// Create update client
c = client.New(
client.WithHTTPClient(NewHTTPClientMock(update)),
client.WithPrivateKey(clientPK),
client.WithServerToken(serverToken),
)
// Update local attributes
attrs["Label"] = "Foo Bar"
// Update attributes
if err := c.UpdateAttributes(attrs); err != nil {
t.Fatal(err)
}
// Retrieve peer from store
peer, err := store.Get(peerID)
if err != nil {
t.Fatal(err)
}
// Assert that peer's ID did not change
if g, e := peer.ID, peerID; g != e {
t.Errorf("peer.ID: got '%v', expected '%v'", g, e)
}
// Assert that stored attributes are the same as the local ones
if g, e := peer.Attributes, attrs; !reflect.DeepEqual(g, e) {
t.Errorf("peer.Attributes: got '%v', expected '%v'", g, e)
}
// Assert that lastContact has changed
var defaultTime time.Time
if peer.LastContact == defaultTime {
t.Error("peer.LastContact should not be time.Time zero value")
}
pem, err := crypto.EncodePublicKeyToPEM(pk.Public())
pem, err := crypto.EncodePublicKeyToPEM(clientPK.Public())
if err != nil {
t.Fatal(err)
}

View File

@ -3,15 +3,8 @@ package test
import (
"crypto/rand"
"crypto/rsa"
"fmt"
"net"
"net/http"
"testing"
peering "forge.cadoles.com/wpetit/go-http-peering"
"forge.cadoles.com/wpetit/go-http-peering/client"
"forge.cadoles.com/wpetit/go-http-peering/memory"
"forge.cadoles.com/wpetit/go-http-peering/server"
"net/http/httptest"
)
func mustGeneratePrivateKey() *rsa.PrivateKey {
@ -22,43 +15,22 @@ func mustGeneratePrivateKey() *rsa.PrivateKey {
return privateKey
}
func startServer(store peering.Store) (int, error) {
listener, err := net.Listen("tcp", ":0")
if err != nil {
return -1, err
}
mux := createServerMux(store)
go http.Serve(listener, mux)
port := listener.Addr().(*net.TCPAddr).Port
return port, nil
type HTTPClientMock struct {
handler http.Handler
recorder *httptest.ResponseRecorder
}
func createServerMux(store peering.Store) *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc(peering.AdvertisePath, server.AdvertiseHandler(store))
update := server.Authenticate(store)(server.UpdateHandler(store))
mux.Handle(peering.UpdatePath, update)
ping := server.Authenticate(store)(server.PingHandler(store))
mux.Handle(peering.PingPath, ping)
return mux
func (c *HTTPClientMock) Do(r *http.Request) (*http.Response, error) {
w := httptest.NewRecorder()
c.recorder = w
c.handler.ServeHTTP(w, r)
return w.Result(), nil
}
func setup(t *testing.T) (peering.PeerID, *rsa.PrivateKey, *client.Client, peering.Store) {
store := memory.NewStore()
port, err := startServer(store)
if err != nil {
t.Fatal(err)
}
pk := mustGeneratePrivateKey()
id := peering.NewPeerID()
c := client.New(
client.WithBaseURL(fmt.Sprintf("http://127.0.0.1:%d", port)),
client.WithPrivateKey(pk),
client.WithPeerID(id),
)
return id, pk, c, store
func (c *HTTPClientMock) Recorder() *httptest.ResponseRecorder {
return c.recorder
}
func NewHTTPClientMock(h http.Handler) *HTTPClientMock {
return &HTTPClientMock{h, nil}
}