erste module drin.
zwischenstand: Architektur aktualisiert, TOFU implementiert,
This commit is contained in:
1 parent
9d5789c5d7
commit
c8df9d7651
41 files changed
+6455
-36
No files matched your search
@@ -0,0 +1,87 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ed25519PublicKey = ed25519.PublicKey
|
||||
|
||||
func TestSign_SetsHeaders(t *testing.T) {
|
||||
priv, _ := GenerateKey()
|
||||
s := &Signer{Key: priv}
|
||||
r, _ := http.NewRequest(http.MethodGet, "https://ingress.example:8443/api/v1/stream", nil)
|
||||
if err := s.Sign(r); err != nil {
|
||||
t.Fatalf("Sign: %v", err)
|
||||
}
|
||||
if got := r.Header.Get(HeaderKey); got != EncodePublicKey(priv.Public().(ed25519.PublicKey)) {
|
||||
t.Errorf("%s = %q", HeaderKey, got)
|
||||
}
|
||||
for _, h := range []string{HeaderTimestamp, HeaderNonce, HeaderSignature} {
|
||||
if r.Header.Get(h) == "" {
|
||||
t.Errorf("Header %s fehlt", h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign_FreshNonceEachTime(t *testing.T) {
|
||||
priv, _ := GenerateKey()
|
||||
s := &Signer{Key: priv}
|
||||
seen := map[string]bool{}
|
||||
for range 100 {
|
||||
r, _ := http.NewRequest(http.MethodGet, "https://h/x", nil)
|
||||
if err := s.Sign(r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
n := r.Header.Get(HeaderNonce)
|
||||
if seen[n] {
|
||||
t.Fatalf("Nonce %q doppelt", n)
|
||||
}
|
||||
seen[n] = true
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign_PreservesBody(t *testing.T) {
|
||||
priv, _ := GenerateKey()
|
||||
r, _ := http.NewRequest(http.MethodPost, "https://h/api/v1/state", strings.NewReader(`{"a":1}`))
|
||||
if err := (&Signer{Key: priv}).Sign(r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
if string(body) != `{"a":1}` {
|
||||
t.Errorf("Body nach Sign = %q", body)
|
||||
}
|
||||
if r.GetBody == nil {
|
||||
t.Fatal("GetBody fehlt – Redirects/Retries könnten den Body nicht erneut senden")
|
||||
}
|
||||
again, _ := r.GetBody()
|
||||
body, _ = io.ReadAll(again)
|
||||
if !bytes.Equal(body, []byte(`{"a":1}`)) {
|
||||
t.Errorf("GetBody liefert %q", body)
|
||||
}
|
||||
}
|
||||
|
||||
// Kein Signieren für Klartext-Verbindungen: Signatur und Body dürfen nie
|
||||
// unverschlüsselt über die Leitung gehen.
|
||||
func TestSign_RefusesPlainHTTP(t *testing.T) {
|
||||
priv, _ := GenerateKey()
|
||||
r, _ := http.NewRequest(http.MethodGet, "http://ingress.example:8080/api/v1/stream", nil)
|
||||
if err := (&Signer{Key: priv}).Sign(r); !errors.Is(err, ErrInsecureTransport) {
|
||||
t.Errorf("erwartet ErrInsecureTransport, bekommen %v", err)
|
||||
}
|
||||
if r.Header.Get(HeaderSignature) != "" {
|
||||
t.Error("Signatur trotz Klartext gesetzt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign_NoKey(t *testing.T) {
|
||||
r, _ := http.NewRequest(http.MethodGet, "https://h/x", nil)
|
||||
if err := (&Signer{}).Sign(r); !errors.Is(err, ErrInvalidKey) {
|
||||
t.Errorf("erwartet ErrInvalidKey, bekommen %v", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user