sig-auth.git

git clone https://git.crispbyte.dev/sig-auth.git

commit
6bc1ce6
parent
b223a25
author
cheddar
date
2025-02-15 01:41:22 +0100 CET
Implement test server
6 files changed,  +152, -6
M client/client.go
+1, -0
1@@ -31,6 +31,7 @@ func GetSigningClient(key crypto.PrivateKey, keyId string) (*http.Client, error)
2 	}
3 
4 	client := httpsig.NewClient(httpsig.ClientOpts{
5+		Tag:   "test-tag",
6 		KeyID: keyId,
7 		Alg:   alg,
8 	})
M main.go
+47, -6
 1@@ -4,22 +4,38 @@ import (
 2 	"bytes"
 3 	"crypto"
 4 	"encoding/json"
 5+	"flag"
 6 	"fmt"
 7+	"io"
 8 	"log"
 9+	"net/http"
10 	"os"
11 
12 	"crispbyte.dev/sig-auth/client"
13+	"crispbyte.dev/sig-auth/server"
14 	"github.com/opencontainers/go-digest"
15 	"golang.org/x/crypto/ssh"
16 )
17 
18 func main() {
19+	useClient := flag.Bool("c", false, "Run client")
20+
21+	keyPath := flag.String("key", "", "Path to the private (client mode) or public (server mode) to use")
22+
23+	flag.Parse()
24+
25+	if *useClient {
26+		runClient(keyPath)
27+	} else {
28+		runServer(keyPath)
29+	}
30+}
31+
32+func runClient(keyFile *string) {
33 	testData := map[string]string{"hello": "world"}
34 	json_data, _ := json.Marshal(testData)
35 
36-	keyFile := "testkey"
37-
38-	key, err := loadPrivateKey(keyFile)
39+	key, err := loadPrivateKey(*keyFile)
40 
41 	if err != nil {
42 		log.Fatal(err)
43@@ -50,11 +66,24 @@ func main() {
44 
45 	defer resp.Body.Close()
46 
47-	var res map[string]interface{}
48+	out, err := io.ReadAll(resp.Body)
49+
50+	if err != nil {
51+		log.Fatal(err)
52+	}
53+
54+	fmt.Println(resp.StatusCode)
55+	fmt.Println(string(out[:]))
56+}
57+
58+func runServer(keyFile *string) {
59+	key, err := loadPublicKey(*keyFile)
60 
61-	json.NewDecoder(resp.Body).Decode(&res)
62+	if err != nil {
63+		log.Fatal(err)
64+	}
65 
66-	fmt.Println(res)
67+	server.Start(key)
68 }
69 
70 func loadPrivateKey(keyFile string) (crypto.PrivateKey, error) {
71@@ -66,3 +95,15 @@ func loadPrivateKey(keyFile string) (crypto.PrivateKey, error) {
72 
73 	return ssh.ParseRawPrivateKey(keyBytes)
74 }
75+
76+func loadPublicKey(keyFile string) (crypto.PublicKey, error) {
77+	keyBytes, err := os.ReadFile(keyFile)
78+
79+	if err != nil {
80+		return nil, err
81+	}
82+
83+	pk, _, _, _, err := ssh.ParseAuthorizedKey(keyBytes)
84+
85+	return pk.(ssh.CryptoPublicKey).CryptoPublicKey(), err
86+}
A server/key_directory.go
+40, -0
 1@@ -0,0 +1,40 @@
 2+package server
 3+
 4+import (
 5+	"context"
 6+	"crypto"
 7+	"crypto/ed25519"
 8+	"fmt"
 9+
10+	"github.com/common-fate/httpsig/alg_ed25519"
11+	"github.com/common-fate/httpsig/verifier"
12+)
13+
14+type KeyEntry struct {
15+	alg       string
16+	publicKey crypto.PublicKey
17+	userId    string
18+}
19+
20+type InMemoryDirectory struct {
21+	records map[string]KeyEntry
22+}
23+
24+func (dir *InMemoryDirectory) GetKey(ctx context.Context, keyId string, _ string) (verifier.Algorithm, error) {
25+	entry := dir.records[keyId]
26+
27+	var alg verifier.Algorithm
28+	var err error
29+
30+	switch entry.alg {
31+	case "ed25519":
32+		alg = alg_ed25519.Ed25519{
33+			PublicKey: entry.publicKey.(ed25519.PublicKey),
34+			Attrs:     entry.userId,
35+		}
36+	default:
37+		err = fmt.Errorf("unknown algoritm: %s", entry.alg)
38+	}
39+
40+	return alg, err
41+}
A server/server.go
+56, -0
 1@@ -0,0 +1,56 @@
 2+package server
 3+
 4+import (
 5+	"context"
 6+	"crypto"
 7+	"fmt"
 8+	"net/http"
 9+
10+	"github.com/common-fate/httpsig"
11+	"github.com/common-fate/httpsig/inmemory"
12+)
13+
14+func Start(publicKey crypto.PublicKey) error {
15+	keyDir := InMemoryDirectory{
16+		records: map[string]KeyEntry{},
17+	}
18+
19+	keyId := "test-id"
20+
21+	keyDir.records[keyId] = KeyEntry{
22+		alg:       "ed25519",
23+		publicKey: publicKey,
24+		userId:    "test_user",
25+	}
26+
27+	mux := http.NewServeMux()
28+
29+	verifier := httpsig.Middleware(httpsig.MiddlewareOpts{
30+		NonceStorage: inmemory.NewNonceStorage(),
31+		KeyDirectory: &keyDir,
32+		Tag:          "test-tag",
33+		Scheme:       "http",
34+		Authority:    "localhost:8080",
35+
36+		OnValidationError: func(ctx context.Context, err error) {
37+			fmt.Printf("validation error: %s\n", err)
38+		},
39+
40+		OnDeriveSigningString: func(ctx context.Context, stringToSign string) {
41+			fmt.Printf("string to sign:\n%s\n", stringToSign)
42+		},
43+	})
44+
45+	mux.Handle("/", verifier(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
46+		fmt.Printf("Responding...\n")
47+		attr := httpsig.AttributesFromContext(r.Context()).(string)
48+		fmt.Printf("User is %s\n", attr)
49+		msg := fmt.Sprintf("hello, %s!", attr)
50+		w.Write([]byte(msg))
51+		fmt.Printf("Responded...\n")
52+	})))
53+
54+	err := http.ListenAndServe("localhost:8080", mux)
55+
56+	return err
57+}
A testkey2
+7, -0
1@@ -0,0 +1,7 @@
2+-----BEGIN OPENSSH PRIVATE KEY-----
3+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
4+QyNTUxOQAAACAVBfVj2Gf8IBbU9G8nYz9Y6UQRcjdocl3CD0GKhIAt5wAAAJA3GdxYNxnc
5+WAAAAAtzc2gtZWQyNTUxOQAAACAVBfVj2Gf8IBbU9G8nYz9Y6UQRcjdocl3CD0GKhIAt5w
6+AAAECcClGiCCayTB0yRGxnn3R26heCf966qN+YAISC4dCMERUF9WPYZ/wgFtT0bydjP1jp
7+RBFyN2hyXcIPQYqEgC3nAAAADGphbWllQGF0aGVuYQE=
8+-----END OPENSSH PRIVATE KEY-----
A testkey2.pub
+1, -0
1@@ -0,0 +1 @@
2+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBUF9WPYZ/wgFtT0bydjP1jpRBFyN2hyXcIPQYqEgC3n jamie@athena