Add native NixOS deployment and UI-managed provider credentials
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package banking
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
@@ -14,8 +15,6 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -27,11 +26,8 @@ func testProvider(t *testing.T, handler http.HandlerFunc) (*EnableBanking, *rsa.
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path := filepath.Join(t.TempDir(), "private.pem")
|
||||
if err := os.WriteFile(path, pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p, err := NewEnableBanking("test-app", path, "http://localhost:8080/api/banking/callback")
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
|
||||
p, err := NewEnableBanking("test-app", keyPEM, "http://localhost:8080/api/banking/callback")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -268,3 +264,60 @@ func TestEnableBankingExpiredConsentRequiresReconnect(t *testing.T) {
|
||||
t.Fatalf("expired consent must request reconnection: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableBankingValidatesUploadedCredentials(t *testing.T) {
|
||||
_, key := testProvider(t, func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Error("credential validation must not call provider")
|
||||
})
|
||||
pkcs1 := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
|
||||
der, err := x509.MarshalPKCS8PrivateKey(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pkcs8 := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: der})
|
||||
for _, content := range [][]byte{pkcs1, pkcs8} {
|
||||
p, err := NewEnableBanking("test-app", content, "https://finance.example/api/banking/callback")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
token, err := p.jwt()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
r.Header.Set("Authorization", "Bearer "+token)
|
||||
assertJWT(t, r, key)
|
||||
}
|
||||
weak, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for name, content := range map[string][]byte{
|
||||
"invalid": []byte("secret-invalid-key"),
|
||||
"oversized": bytes.Repeat([]byte("k"), MaxPrivateKeyPEM+1),
|
||||
"multiple": append(append([]byte{}, pkcs1...), pkcs8...),
|
||||
"prefix": append([]byte("secret-prefix\n"), pkcs1...),
|
||||
"weak": pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(weak)}),
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if _, err := NewEnableBanking("test-app", content, "https://finance.example/api/banking/callback"); err == nil || strings.Contains(err.Error(), "secret") {
|
||||
t.Fatal("invalid PEM accepted or leaked")
|
||||
}
|
||||
})
|
||||
}
|
||||
for _, appID := range []string{"", "app one", "app\none", "app\u007fone", strings.Repeat("a", 257)} {
|
||||
if _, err := NewEnableBanking(appID, pkcs1, "https://finance.example/api/banking/callback"); err == nil {
|
||||
t.Fatal("invalid app ID accepted")
|
||||
}
|
||||
}
|
||||
for _, redirect := range []string{
|
||||
"https://finance.example/", "https://finance.example/api/banking/callback?secret=value",
|
||||
"https://finance.example/api/banking/callback#", "https://finance.example/api/banking/callback?",
|
||||
"https://user:secret@finance.example/api/banking/callback", "ftp://finance.example/api/banking/callback",
|
||||
"https://finance.example/api/banking/%63allback", "https:///api/banking/callback",
|
||||
} {
|
||||
if _, err := NewEnableBanking("test-app", pkcs1, redirect); err == nil || strings.Contains(err.Error(), "secret") {
|
||||
t.Fatal("invalid callback accepted or leaked")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user