diff --git a/sso_test.go b/sso_test.go index 420c7645a935eec08df2ea9764ad7f62ce282d06..ebc33a11973cd15735fc1fe617fdf527a192a6ab 100644 --- a/sso_test.go +++ b/sso_test.go @@ -1,6 +1,11 @@ package sso import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" "testing" "time" @@ -42,6 +47,8 @@ var ( legacyPublicKey = []byte{47, 234, 144, 101, 76, 245, 1, 73, 155, 115, 89, 105, 165, 252, 49, 114, 48, 166, 231, 130, 82, 123, 147, 179, 50, 50, 34, 198, 219, 251, 151, 17} ) +// TestLegacy verifies that tickets signed by the legacy C +// implementation can be verified correctly by the Go code. func TestLegacy(t *testing.T) { validator := &ssoValidator{publicKey: legacyPublicKey} tkt, err := validator.parse(legacyTicket) @@ -52,3 +59,101 @@ func TestLegacy(t *testing.T) { t.Fatalf("decoded bad values: %+v", tkt) } } + +// Create a ssoSigner and sign a valid ticket. +func makeTestSigner(t *testing.T) (string, string, func()) { + dir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatal(err) + } + + pub, priv, err := ed25519.GenerateKey(nil) + if err != nil { + t.Fatal(err) + } + pubPath := filepath.Join(dir, "public.key") + ioutil.WriteFile(pubPath, pub, 0600) + //ioutil.WriteFile(filepath.Join(dir, "secret.key"), priv, 0600) + + tkt := NewTicket("user", "service/", "domain", "nonce", nil, 300*time.Second) + signer := &ssoSigner{key: priv} + signed, err := signer.Sign(tkt) + if err != nil { + t.Fatal("Sign():", err) + } + + return dir, signed, func() { + os.RemoveAll(dir) + } +} + +// TestLegacyIntegration verifies that tickets signed by the Go code +// can be verified successfully by the legacy C implementation. +// +// To run this test, set the SSO_SRCDIR environment variable and point +// it at the root of the ai/sso source package repository. +func TestLegacyIntegration(t *testing.T) { + ssoSrcDir := os.Getenv("SSO_SRCDIR") + if ssoSrcDir == "" { + t.Skip("SSO_SRCDIR not set") + } + ssotool := filepath.Join(ssoSrcDir, "src/sso/ssotool") + if _, err := os.Stat(ssotool); os.IsNotExist(err) { + t.Skip("ssotool not installed") + } + + dir, signed, cleanup := makeTestSigner(t) + defer cleanup() + pubPath := filepath.Join(dir, "public.key") + + cmd := exec.Command(ssotool, "--public-key", pubPath, "--service", "service/", "--domain", "domain", "--nonce", "nonce", "--verify", signed) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + err := cmd.Run() + if err != nil { + t.Fatalf("ssotool validation failed: %v", err) + } +} + +// TestLegacyIntegration verifies that tickets signed by the Go code +// can be verified successfully by the legacy Python implementation. +// +// To run this test, set the SSO_SRCDIR environment variable and point +// it at the root of the ai/sso source package repository. +func TestLegacyIntegration_Python(t *testing.T) { + ssoSrcDir := os.Getenv("SSO_SRCDIR") + if ssoSrcDir == "" { + t.Skip("SSO_SRCDIR not set") + } + pythonPath := fmt.Sprintf( + "%s:%s", + filepath.Join(ssoSrcDir, "src/python"), + filepath.Join(ssoSrcDir, "src/python/sso"), + ) + libPath := filepath.Join(ssoSrcDir, "src/sso/.libs") + + dir, signed, cleanup := makeTestSigner(t) + defer cleanup() + + pubPath := filepath.Join(dir, "public.key") + scriptPath := filepath.Join(dir, "test.py") + ioutil.WriteFile(scriptPath, []byte(` +import sso +import sys +with open(sys.argv[1]) as fd: + pubkey = fd.read() +verifier = sso.Verifier(pubkey, "service/", "domain", None) +tkt = verifier.verify(sys.argv[2].encode(), "nonce") +sys.exit(0 if (tkt.user() == "user") else 1) +`), 0600) + + cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf("env PYTHONPATH=%s LD_LIBRARY_PATH=%s python %s %s %s", pythonPath, libPath, scriptPath, pubPath, signed)) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + err := cmd.Run() + if err != nil { + t.Fatalf("python validation failed: %v", err) + } +}