From 1284ea502b589f2aa518d7bcaf260abc3495da0c Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Sun, 15 Dec 2019 21:53:35 +0000
Subject: [PATCH] Add script to run a local server for UI testing purposes

---
 server/scripts/localserver.go | 159 ++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)
 create mode 100644 server/scripts/localserver.go

diff --git a/server/scripts/localserver.go b/server/scripts/localserver.go
new file mode 100644
index 0000000..651ff05
--- /dev/null
+++ b/server/scripts/localserver.go
@@ -0,0 +1,159 @@
+// +build ignore
+
+package main
+
+import (
+	"context"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"flag"
+	"io/ioutil"
+	"log"
+	"math/big"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/gorilla/securecookie"
+	"golang.org/x/crypto/ed25519"
+
+	"git.autistici.org/id/auth"
+	"git.autistici.org/id/go-sso/server"
+)
+
+var (
+	addr = flag.String("addr", ":4872", "address to listen on")
+)
+
+type fakeAuthClient struct{}
+
+func (c *fakeAuthClient) Authenticate(_ context.Context, req *auth.Request) (*auth.Response, error) {
+	log.Printf("authenticate(%+v)", req)
+
+	p := string(req.Password)
+	info := &auth.UserInfo{Shard: "shard1"}
+	switch {
+	case req.Username == "testuser" && p == "password":
+		return &auth.Response{Status: auth.StatusOK, UserInfo: info}, nil
+	case req.Username == "test2fa" && p == "password" && req.OTP == "123456":
+		return &auth.Response{Status: auth.StatusOK, UserInfo: info}, nil
+	case req.Username == "test2fa" && p == "password":
+		return &auth.Response{
+			Status:     auth.StatusInsufficientCredentials,
+			TFAMethods: []auth.TFAMethod{auth.TFAMethodOTP},
+		}, nil
+	}
+
+	return &auth.Response{Status: auth.StatusError}, nil
+}
+
+func generateSSLCert(tmpdir string) (string, string) {
+	priv, err := rsa.GenerateKey(rand.Reader, 2048)
+	if err != nil {
+		panic(err)
+	}
+
+	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+	if err != nil {
+		panic(err)
+	}
+
+	now := time.Now()
+	notBefore := now.Add(-1 * time.Hour)
+	notAfter := now.Add(1000 * time.Hour)
+	template := x509.Certificate{
+		SerialNumber: serialNumber,
+		Subject: pkix.Name{
+			Organization: []string{"Acme Co"},
+		},
+		NotBefore:             notBefore,
+		NotAfter:              notAfter,
+		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+		BasicConstraintsValid: true,
+		DNSNames:              []string{"localhost"},
+	}
+
+	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+	if err != nil {
+		panic(err)
+	}
+
+	certPath := filepath.Join(tmpdir, "cert.pem")
+	certOut, err := os.Create(certPath)
+	if err != nil {
+		panic(err)
+	}
+	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
+		panic(err)
+	}
+	certOut.Close()
+
+	keyPath := filepath.Join(tmpdir, "privkey.pem")
+	keyOut, err := os.Create(keyPath)
+	if err != nil {
+		panic(err)
+	}
+	privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
+	if err != nil {
+		panic(err)
+	}
+	if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
+		panic(err)
+	}
+
+	keyOut.Close()
+
+	return certPath, keyPath
+}
+
+func main() {
+	flag.Parse()
+
+	tmpdir, err := ioutil.TempDir("", "")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	pub, priv, err := ed25519.GenerateKey(nil)
+	if err != nil {
+		log.Fatal(err)
+	}
+	secretPath := filepath.Join(tmpdir, "secret")
+	publicPath := filepath.Join(tmpdir, "public")
+	ioutil.WriteFile(secretPath, priv, 0600) // nolint
+	ioutil.WriteFile(publicPath, pub, 0600)  // nolint
+
+	config := &server.Config{
+		SecretKeyFile:   secretPath,
+		PublicKeyFile:   publicPath,
+		Domain:          "example.com",
+		AuthService:     "test",
+		AllowedServices: []string{"service.example.com/"},
+		CSRFSecret:      string(securecookie.GenerateRandomKey(32)),
+	}
+	if err := config.Compile(); err != nil {
+		log.Fatalf("config error: %v", err)
+	}
+
+	svc, err := server.NewLoginService(config)
+	if err != nil {
+		log.Fatalf("server.NewLoginService(): %v", err)
+	}
+
+	srv, err := server.New(svc, &fakeAuthClient{}, config)
+	if err != nil {
+		log.Fatalf("server.New(): %v", err)
+	}
+
+	certPath, keyPath := generateSSLCert(tmpdir)
+	log.Printf("serving on https://localhost:%s/", strings.Split(*addr, ":")[1])
+	http.ListenAndServeTLS(*addr, certPath, keyPath, srv.Handler())
+}
-- 
GitLab