Commit 128c384b authored by ale's avatar ale

Add a couple of basic tests

parent 0eaefcea
Pipeline #893 passed with stages
in 49 seconds
......@@ -81,12 +81,7 @@ type KeyStore struct {
validator sso.Validator
}
// NewKeyStore creates a new KeyStore with the given config and returns it.
func NewKeyStore(config *Config) (*KeyStore, error) {
if err := config.check(); err != nil {
return nil, err
}
func newKeyStoreWithBackend(config *Config, db Database) (*KeyStore, error) {
ssoKey, err := ioutil.ReadFile(config.SSOPublicKeyFile)
if err != nil {
return nil, err
......@@ -96,33 +91,46 @@ func NewKeyStore(config *Config) (*KeyStore, error) {
return nil, err
}
s := &KeyStore{
userKeys: make(map[string]userKey),
service: config.SSOService,
validator: v,
db: db,
}
go s.expireLoop()
return s, nil
}
// NewKeyStore creates a new KeyStore with the given config and returns it.
func NewKeyStore(config *Config) (*KeyStore, error) {
if err := config.check(); err != nil {
return nil, err
}
// There is only one supported backend type, ldap.
ldap, err := backend.NewLDAPBackend(config.LDAPConfig)
if err != nil {
return nil, err
}
s := &KeyStore{
userKeys: make(map[string]userKey),
service: config.SSOService,
validator: v,
db: ldap,
return newKeyStoreWithBackend(config, ldap)
}
func (s *KeyStore) expire(t time.Time) {
s.mx.Lock()
for u, k := range s.userKeys {
if k.expiry.Before(t) {
log.Printf("forgetting key for %s", u)
wipeBytes(k.pkey)
delete(s.userKeys, u)
}
}
go s.expire()
return s, nil
s.mx.Unlock()
}
func (s *KeyStore) expire() {
func (s *KeyStore) expireLoop() {
for t := range time.NewTicker(600 * time.Second).C {
s.mx.Lock()
for u, k := range s.userKeys {
if k.expiry.Before(t) {
log.Printf("forgetting key for %s", u)
wipeBytes(k.pkey)
delete(s.userKeys, u)
}
}
s.mx.Unlock()
s.expire(t)
}
}
......
package server
import (
"bytes"
"context"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
"golang.org/x/crypto/ed25519"
"git.autistici.org/id/go-sso"
"git.autistici.org/id/keystore/userenckey"
)
type testContext struct {
dir string
pubkeyPath string
signer sso.Signer
}
func newTestContext(t testing.TB) *testContext {
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
ctx := &testContext{
dir: dir,
pubkeyPath: filepath.Join(dir, "public.key"),
}
pub, priv, err := ed25519.GenerateKey(nil)
if err != nil {
t.Fatal("ed25519.GenerateKey():", err)
}
ctx.signer, err = sso.NewSigner(priv)
if err != nil {
t.Fatal("sso.NewSigner():", err)
}
ioutil.WriteFile(ctx.pubkeyPath, pub, 0644)
return ctx
}
func (c *testContext) Close() {
os.RemoveAll(c.dir)
}
func (c *testContext) sign(user, service, domain string) string {
tkt, _ := c.signer.Sign(sso.NewTicket(user, service, domain, "", nil, 600*time.Second))
return tkt
}
type testDB struct {
keys map[string][][]byte
}
func (t *testDB) GetPrivateKeys(_ context.Context, username string) ([][]byte, error) {
keys, ok := t.keys[username]
if !ok {
return nil, nil
}
return keys, nil
}
var (
privKey = []byte("fairly secret key")
pw = []byte("equally secret password")
encPrivKey []byte
)
func init() {
var err error
encPrivKey, err = userenckey.Encrypt(privKey, pw)
if err != nil {
panic(err)
}
}
func TestKeystore_OpenAndGet(t *testing.T) {
c := newTestContext(t)
defer c.Close()
db := &testDB{
keys: map[string][][]byte{
"testuser": [][]byte{encPrivKey},
},
}
keystore, err := newKeyStoreWithBackend(&Config{
SSOPublicKeyFile: c.pubkeyPath,
SSOService: "keystore/",
SSODomain: "domain",
}, db)
if err != nil {
t.Fatal(err)
}
// Decrypt the private key with the right password.
err = keystore.Open(context.Background(), "testuser", string(pw), 60)
if err != nil {
t.Fatal("keystore.Open():", err)
}
keystore.expire(time.Now())
// Sign a valid SSO ticket and use it to obtain the private
// key we just stored.
ssoTicket := c.sign("testuser", "keystore/", "domain")
result, err := keystore.Get("testuser", ssoTicket)
if err != nil {
t.Fatal("keystore.Get():", err)
}
if !bytes.Equal(result, privKey) {
t.Fatalf("keystore.Get() returned bad key: got %v, expected %v", result, privKey)
}
}
func TestKeystore_Expire(t *testing.T) {
c := newTestContext(t)
defer c.Close()
db := &testDB{
keys: map[string][][]byte{
"testuser": [][]byte{encPrivKey},
},
}
keystore, err := newKeyStoreWithBackend(&Config{
SSOPublicKeyFile: c.pubkeyPath,
SSOService: "keystore/",
SSODomain: "domain",
}, db)
if err != nil {
t.Fatal(err)
}
// Decrypt the private key with the right password.
err = keystore.Open(context.Background(), "testuser", string(pw), 60)
if err != nil {
t.Fatal("keystore.Open():", err)
}
keystore.expire(time.Now().Add(3600 * time.Second))
// Sign a valid SSO ticket and use it to obtain the private
// key we just stored.
ssoTicket := c.sign("testuser", "keystore/", "domain")
_, err = keystore.Get("testuser", ssoTicket)
if err != errNoKeys {
t.Fatal("keystore.Get():", err)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment