mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-08-28 03:46:34 +00:00
Merge pull request #170 from cloudflare/kyle/delegation-restore
Properly restore delegations.
This commit is contained in:
@@ -404,3 +404,20 @@ func (c *RemoteServer) Restore(req core.DelegateRequest) (*core.ResponseData, er
|
||||
|
||||
return unmarshalResponseData(respBytes)
|
||||
}
|
||||
|
||||
// ResetPersisted issues a persisted delegation reset request,
|
||||
// clearing out any persisted delegations. This must be done by an
|
||||
// admin user.
|
||||
func (c *RemoteServer) ResetPersisted(req core.PurgeRequest) (*core.ResponseData, error) {
|
||||
reqBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
respBytes, err := c.doAction("reset-persisted", reqBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unmarshalResponseData(respBytes)
|
||||
}
|
||||
|
||||
+25
-11
@@ -35,17 +35,18 @@ type command struct {
|
||||
var roServer *client.RemoteServer
|
||||
|
||||
var commandSet = map[string]command{
|
||||
"create": command{Run: runCreate, Desc: "create the disk vault and admin account"},
|
||||
"create-user": command{Run: runCreateUser, Desc: "create a user account"},
|
||||
"summary": command{Run: runSummary, Desc: "list the user and delegation summary"},
|
||||
"delegate": command{Run: runDelegate, Desc: "do decryption delegation"},
|
||||
"encrypt": command{Run: runEncrypt, Desc: "encrypt a file"},
|
||||
"decrypt": command{Run: runDecrypt, Desc: "decrypt a file"},
|
||||
"re-encrypt": command{Run: runReEncrypt, Desc: "re-encrypt a file"},
|
||||
"order": command{Run: runOrder, Desc: "place an order for delegations"},
|
||||
"owners": command{Run: runOwner, Desc: "show owners list"},
|
||||
"status": command{Run: runStatus, Desc: "show Red October persistent delegation state"},
|
||||
"restore": command{Run: runRestore, Desc: "perform a restore delegation"},
|
||||
"create": command{Run: runCreate, Desc: "create the disk vault and admin account"},
|
||||
"create-user": command{Run: runCreateUser, Desc: "create a user account"},
|
||||
"summary": command{Run: runSummary, Desc: "list the user and delegation summary"},
|
||||
"delegate": command{Run: runDelegate, Desc: "do decryption delegation"},
|
||||
"encrypt": command{Run: runEncrypt, Desc: "encrypt a file"},
|
||||
"decrypt": command{Run: runDecrypt, Desc: "decrypt a file"},
|
||||
"re-encrypt": command{Run: runReEncrypt, Desc: "re-encrypt a file"},
|
||||
"order": command{Run: runOrder, Desc: "place an order for delegations"},
|
||||
"owners": command{Run: runOwner, Desc: "show owners list"},
|
||||
"status": command{Run: runStatus, Desc: "show Red October persistent delegation state"},
|
||||
"restore": command{Run: runRestore, Desc: "perform a restore delegation"},
|
||||
"reset-persisted": command{Run: runResetPersisted, Desc: "reset the persisted delegations"},
|
||||
}
|
||||
|
||||
func registerFlags() {
|
||||
@@ -313,6 +314,19 @@ func runStatus() {
|
||||
fmt.Println(resp)
|
||||
}
|
||||
|
||||
func runResetPersisted() {
|
||||
req := core.PurgeRequest{
|
||||
Name: user,
|
||||
Password: pswd,
|
||||
}
|
||||
|
||||
resp, err := roServer.ResetPersisted(req)
|
||||
processError(err)
|
||||
|
||||
fmt.Println(resp.Status)
|
||||
fmt.Println(resp)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = func() {
|
||||
fmt.Println("Usage: ro [options] subcommand")
|
||||
|
||||
@@ -995,3 +995,37 @@ func Restore(jsonIn []byte) (out []byte, err error) {
|
||||
|
||||
return jsonResponse(out)
|
||||
}
|
||||
|
||||
// ResetPersisted clears the persisted user data from the server. This
|
||||
// request requires an admin.
|
||||
func ResetPersisted(jsonIn []byte) (out []byte, err error) {
|
||||
var req PurgeRequest
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.Printf("core.resetpersisted failed: user=%s %v", req.Name, err)
|
||||
} else {
|
||||
log.Printf("core.resetpersisted success: user=%s", req.Name)
|
||||
}
|
||||
}()
|
||||
|
||||
if err = json.Unmarshal(jsonIn, &req); err != nil {
|
||||
return jsonStatusError(err)
|
||||
}
|
||||
|
||||
if err := validateUser(req.Name, req.Password, true); err != nil {
|
||||
return jsonStatusError(err)
|
||||
}
|
||||
|
||||
st, err := crypt.ResetPersisted()
|
||||
if err != nil {
|
||||
return jsonStatusError(err)
|
||||
}
|
||||
|
||||
resp := &StatusData{Status: st.State}
|
||||
if out, err = json.Marshal(resp); err != nil {
|
||||
return jsonStatusError(err)
|
||||
}
|
||||
|
||||
return jsonResponse(out)
|
||||
}
|
||||
|
||||
+18
-4
@@ -1306,10 +1306,11 @@ func afterRestartRestore(t *testing.T) {
|
||||
}
|
||||
|
||||
func restoreDelegateRestore(t *testing.T) {
|
||||
delegateJsonBad := []byte("{\"Name\":\"Alice\",\"Password\":\"Hi\",\"Time\":\"5m\",\"Uses\":1}")
|
||||
delegateJson1 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":1}")
|
||||
delegateJson2 := []byte("{\"Name\":\"Carl\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":1}")
|
||||
delegateJson3 := []byte("{\"Name\":\"Carl\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":1}")
|
||||
adminUser := []byte("{\"Name\":\"Admin\",\"Password\":\"Admin\"}")
|
||||
delegateJsonBad := []byte("{\"Name\":\"Alice\",\"Password\":\"Hi\",\"Time\":\"5m\",\"Uses\":3}")
|
||||
delegateJson1 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":3}")
|
||||
delegateJson2 := []byte("{\"Name\":\"Carl\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":3}")
|
||||
delegateJson3 := []byte("{\"Name\":\"Carl\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":3}")
|
||||
|
||||
var s ResponseData
|
||||
respJson, err := Restore(delegateJsonBad)
|
||||
@@ -1382,6 +1383,19 @@ func restoreDelegateRestore(t *testing.T) {
|
||||
} else if _, ok = summary.Live["Bob"]; !ok {
|
||||
t.Fatalf("Bob should be present in the active delegations.")
|
||||
}
|
||||
|
||||
respJson, err = ResetPersisted(adminUser)
|
||||
if err != nil {
|
||||
t.Fatalf("Resetting persisted delegations failed: %s", err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(respJson, &s)
|
||||
if err != nil {
|
||||
t.Fatalf("Error resetting persisted delegations: %s", err)
|
||||
} else if s.Status != "ok" {
|
||||
t.Fatalf("Error resetting persisted delegations: %s", s.Status)
|
||||
}
|
||||
restoreState(t, persist.Active)
|
||||
}
|
||||
|
||||
func TestRestore(t *testing.T) {
|
||||
|
||||
+14
-1
@@ -777,7 +777,13 @@ func (c *Cryptor) Restore(name, password string, uses int, slot, durationString
|
||||
return err
|
||||
}
|
||||
|
||||
c.cache = keycache.NewFrom(uk)
|
||||
rcache := keycache.NewFrom(uk)
|
||||
err = rcache.Restore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.cache = rcache
|
||||
c.persist.Persist()
|
||||
c.persist.Cache().Flush()
|
||||
return nil
|
||||
@@ -787,3 +793,10 @@ func (c *Cryptor) Restore(name, password string, uses int, slot, durationString
|
||||
func (c *Cryptor) Status() *persist.Status {
|
||||
return c.persist.Status()
|
||||
}
|
||||
|
||||
// ResetPersisted clears any persisted delegations and returns the
|
||||
// vault to an active delegation state if configured.
|
||||
func (c *Cryptor) ResetPersisted() (*persist.Status, error) {
|
||||
err := c.persist.Purge()
|
||||
return c.persist.Status(), err
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -44,6 +45,7 @@ type ActiveUser struct {
|
||||
AltNames map[string]string
|
||||
Admin bool
|
||||
Type string
|
||||
Key []byte
|
||||
|
||||
rsaKey rsa.PrivateKey
|
||||
eccKey *ecdsa.PrivateKey
|
||||
@@ -225,8 +227,16 @@ func (cache *Cache) AddKeyFromRecord(record passvault.PasswordRecord, name, pass
|
||||
switch record.Type {
|
||||
case passvault.RSARecord:
|
||||
current.rsaKey, err = record.GetKeyRSA(password)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
current.Key = x509.MarshalPKCS1PrivateKey(¤t.rsaKey)
|
||||
case passvault.ECCRecord:
|
||||
current.eccKey, err = record.GetKeyECC(password)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
current.Key, err = x509.MarshalECPrivateKey(current.eccKey)
|
||||
default:
|
||||
err = errors.New("Unknown record type")
|
||||
}
|
||||
@@ -370,3 +380,31 @@ func (cache *Cache) DelegateStatus(name string, labels, admins []string) (admins
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Restore unmarshals the private key stored in the delegator to the
|
||||
// appropriate private structure.
|
||||
func (cache *Cache) Restore() (err error) {
|
||||
for index, uk := range cache.UserKeys {
|
||||
if len(uk.Key) == 0 {
|
||||
return errors.New("keycache: no private key in active user")
|
||||
}
|
||||
|
||||
rsaPriv, err := x509.ParsePKCS1PrivateKey(uk.Key)
|
||||
if err == nil {
|
||||
uk.rsaKey = *rsaPriv
|
||||
cache.UserKeys[index] = uk
|
||||
continue
|
||||
}
|
||||
|
||||
ecPriv, err := x509.ParseECPrivateKey(uk.Key)
|
||||
if err == nil {
|
||||
uk.eccKey = ecPriv
|
||||
cache.UserKeys[index] = uk
|
||||
continue
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ import (
|
||||
"container/heap"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -191,7 +192,7 @@ func (m MSP) DistributeShares(sec []byte, db UserDatabase) (map[string][][]byte,
|
||||
case Name:
|
||||
name := cond.string
|
||||
if !db.ValidUser(name) {
|
||||
return nil, errors.New("Unknown user in predicate.")
|
||||
return nil, fmt.Errorf("Unknown user '%s' in predicate.", name)
|
||||
}
|
||||
|
||||
out[name] = append(out[name], share)
|
||||
|
||||
@@ -127,3 +127,12 @@ func (f *File) Status() *Status {
|
||||
Summary: f.cache.GetSummary(),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *File) Purge() error {
|
||||
f.state = Active
|
||||
f.blob = nil
|
||||
if err := os.Remove(f.config.Location); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ import (
|
||||
"github.com/cloudflare/redoctober/config"
|
||||
)
|
||||
|
||||
func fexists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
|
||||
func TestFileConfig(t *testing.T) {
|
||||
cfg := &config.Delegations{
|
||||
Persist: false,
|
||||
@@ -165,3 +170,96 @@ func TestNewFilePersists(t *testing.T) {
|
||||
t.Fatalf("fresh store should be persisting")
|
||||
}
|
||||
}
|
||||
|
||||
func TestActivePurge(t *testing.T) {
|
||||
sf, err := tempName()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(sf)
|
||||
|
||||
cfg := &config.Delegations{
|
||||
Persist: true,
|
||||
Mechanism: FileMechanism,
|
||||
Policy: "alice & bob",
|
||||
Users: []string{"alice", "bob"},
|
||||
Location: sf,
|
||||
}
|
||||
|
||||
f, err := New(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, ok := f.(*File)
|
||||
if !ok {
|
||||
t.Fatalf("persist: expected to get a *File but have %T", f)
|
||||
}
|
||||
|
||||
const expected = "test data"
|
||||
if err = f.Store([]byte(expected)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !fexists(sf) {
|
||||
t.Fatalf("persist: file store wasn't written to disk")
|
||||
}
|
||||
|
||||
err = f.Purge()
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
if fexists(sf) {
|
||||
t.Fatalf("persist: store should have been removed during purge")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInactivePurge(t *testing.T) {
|
||||
sf, err := tempName()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(sf)
|
||||
|
||||
cfg := &config.Delegations{
|
||||
Persist: true,
|
||||
Mechanism: FileMechanism,
|
||||
Policy: "alice & bob",
|
||||
Users: []string{"alice", "bob"},
|
||||
Location: sf,
|
||||
}
|
||||
|
||||
const expected = "test data"
|
||||
err = ioutil.WriteFile(sf, []byte(expected), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
f, err := New(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
file, ok := f.(*File)
|
||||
if !ok {
|
||||
t.Fatalf("persist: expected to get a *File but have %T", f)
|
||||
}
|
||||
|
||||
if err = f.Store([]byte(expected)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = f.Purge()
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
if fexists(sf) {
|
||||
t.Fatalf("persist: store should have been removed during purge")
|
||||
}
|
||||
|
||||
if file.Status().State != Active {
|
||||
t.Fatalf("fresh store should be persisting")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,3 +57,7 @@ func (n *Null) Cache() *keycache.Cache {
|
||||
cache := keycache.NewCache()
|
||||
return &cache
|
||||
}
|
||||
|
||||
func (n *Null) Purge() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ func TestNewNull(t *testing.T) {
|
||||
}
|
||||
|
||||
if cache := store.Cache(); len(cache.UserKeys) != 0 {
|
||||
t.Fatal("persist: Null Cache should return an empty cache")
|
||||
t.Fatal("persist: Null Cache() should return an empty cache")
|
||||
}
|
||||
|
||||
if store.Purge() != nil {
|
||||
t.Fatal("persist: Null Purge() shouldn't return an error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ type Store interface {
|
||||
// This is not the main keycache. This is the keycache for
|
||||
// users that can decrypt the store.
|
||||
Cache() *keycache.Cache
|
||||
// Purge clears the persisted keys.
|
||||
Purge() error
|
||||
}
|
||||
|
||||
// FileMechanism indicates that the persistence mechanism is a file.
|
||||
|
||||
+19
-18
@@ -29,24 +29,25 @@ import (
|
||||
// List of URLs to register and their related functions
|
||||
|
||||
var functions = map[string]func([]byte) ([]byte, error){
|
||||
"/create": core.Create,
|
||||
"/create-user": core.CreateUser,
|
||||
"/summary": core.Summary,
|
||||
"/purge": core.Purge,
|
||||
"/delegate": core.Delegate,
|
||||
"/password": core.Password,
|
||||
"/encrypt": core.Encrypt,
|
||||
"/re-encrypt": core.ReEncrypt,
|
||||
"/decrypt": core.Decrypt,
|
||||
"/owners": core.Owners,
|
||||
"/modify": core.Modify,
|
||||
"/export": core.Export,
|
||||
"/order": core.Order,
|
||||
"/orderout": core.OrdersOutstanding,
|
||||
"/orderinfo": core.OrderInfo,
|
||||
"/ordercancel": core.OrderCancel,
|
||||
"/restore": core.Restore,
|
||||
"/status": core.Status,
|
||||
"/create": core.Create,
|
||||
"/create-user": core.CreateUser,
|
||||
"/summary": core.Summary,
|
||||
"/purge": core.Purge,
|
||||
"/delegate": core.Delegate,
|
||||
"/password": core.Password,
|
||||
"/encrypt": core.Encrypt,
|
||||
"/re-encrypt": core.ReEncrypt,
|
||||
"/decrypt": core.Decrypt,
|
||||
"/owners": core.Owners,
|
||||
"/modify": core.Modify,
|
||||
"/export": core.Export,
|
||||
"/order": core.Order,
|
||||
"/orderout": core.OrdersOutstanding,
|
||||
"/orderinfo": core.OrderInfo,
|
||||
"/ordercancel": core.OrderCancel,
|
||||
"/restore": core.Restore,
|
||||
"/reset-persisted": core.ResetPersisted,
|
||||
"/status": core.Status,
|
||||
}
|
||||
|
||||
type userRequest struct {
|
||||
|
||||
+120
-13
@@ -9,6 +9,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/redoctober/client"
|
||||
"github.com/cloudflare/redoctober/config"
|
||||
"github.com/cloudflare/redoctober/core"
|
||||
"github.com/cloudflare/redoctober/persist"
|
||||
@@ -59,7 +61,8 @@ var (
|
||||
Uses: 1,
|
||||
}
|
||||
|
||||
encryptInput = &core.EncryptRequest{
|
||||
encryptMessage = "Why is a raven like a writing desk?\n"
|
||||
encryptInput = &core.EncryptRequest{
|
||||
Minimum: 2,
|
||||
Name: createVaultInput.Name,
|
||||
Password: createVaultInput.Password,
|
||||
@@ -636,6 +639,22 @@ func TestPurge(t *testing.T) {
|
||||
// These need to write files to disk in order to test recovering delegations. //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var (
|
||||
restore *client.RemoteServer
|
||||
|
||||
// restoreSecret is the encrypted data that should be decryptable
|
||||
// both before and after the restart.
|
||||
restoreSecret []byte
|
||||
|
||||
restoreEncryptInput = &core.EncryptRequest{
|
||||
Minimum: 2,
|
||||
Name: createVaultInput.Name,
|
||||
Password: createVaultInput.Password,
|
||||
Owners: []string{createUserInput3.Name, createUserInput2.Name},
|
||||
Data: []byte(base64.StdEncoding.EncodeToString([]byte(encryptMessage))),
|
||||
}
|
||||
)
|
||||
|
||||
func restoreSetup(t *testing.T, configPath, vaultPath string) (cmd *exec.Cmd) {
|
||||
const maxAttempts = 5
|
||||
|
||||
@@ -650,7 +669,6 @@ func restoreSetup(t *testing.T, configPath, vaultPath string) (cmd *exec.Cmd) {
|
||||
}
|
||||
|
||||
cmd = exec.Command(binaryPath, "-vaultpath", vaultPath, "-f", configPath)
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatalf("Error running redoctober command, %v", err)
|
||||
}
|
||||
@@ -705,6 +723,9 @@ func TestRestore(t *testing.T) {
|
||||
// The server has restarted --- verify that the persisted
|
||||
// delegations are available.
|
||||
afterRestartRestore(t, cfgPath, vaultPath)
|
||||
|
||||
// Verify that we can reset the persisted delegations.
|
||||
afterRestartPurge(t, cfgPath, vaultPath)
|
||||
}
|
||||
|
||||
func prepareSetup(t *testing.T, pstore, cfgPath string) {
|
||||
@@ -736,6 +757,16 @@ func prepareSetup(t *testing.T, pstore, cfgPath string) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to write config file: %s", err)
|
||||
}
|
||||
|
||||
// We'll have two uses: one to permit the pre-restart decryption,
|
||||
// one to permit the post-restart decryption, and one to verify
|
||||
// the purge functionality.
|
||||
delegateInput1.Uses = 3
|
||||
delegateInput2.Uses = 3
|
||||
|
||||
// Allow someone to decrypt.
|
||||
delegateInput1.Users = []string{createVaultInput.Name}
|
||||
delegateInput2.Users = []string{createVaultInput.Name}
|
||||
}
|
||||
|
||||
func restoreCheckStatus(t *testing.T, expected string) {
|
||||
@@ -816,17 +847,23 @@ func beforeRestartRestore(t *testing.T, cfgPath, vaultPath string) {
|
||||
cmd := restoreSetup(t, cfgPath, vaultPath)
|
||||
defer teardown(t, cmd)
|
||||
|
||||
srv, err := client.NewRemoteServer("localhost:8080", "testdata/server.crt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set up client: %s", err)
|
||||
}
|
||||
|
||||
// Create a vault/admin user and 2 normal users so there is data to work with.
|
||||
if _, _, err := post("create", createVaultInput); err != nil {
|
||||
if _, _, err = post("create", createVaultInput); err != nil {
|
||||
t.Fatalf("failed to create the vault: %s", err)
|
||||
}
|
||||
if _, _, err := post("create-user", createUserInput1); err != nil {
|
||||
|
||||
if _, err = srv.CreateUser(*createUserInput1); err != nil {
|
||||
t.Fatalf("couldn't create user %s: %s", createUserInput1.Name, err)
|
||||
}
|
||||
if _, _, err := post("create-user", createUserInput2); err != nil {
|
||||
if _, err = srv.CreateUser(*createUserInput2); err != nil {
|
||||
t.Fatalf("couldn't create user %s: %s", createUserInput2.Name, err)
|
||||
}
|
||||
if _, _, err := post("create-user", createUserInput3); err != nil {
|
||||
if _, err = srv.CreateUser(*createUserInput3); err != nil {
|
||||
t.Fatalf("couldn't create user %s: %s", createUserInput3.Name, err)
|
||||
}
|
||||
|
||||
@@ -835,29 +872,55 @@ func beforeRestartRestore(t *testing.T, cfgPath, vaultPath string) {
|
||||
restoreCheckStatus(t, persist.Active)
|
||||
|
||||
// Delegate two users.
|
||||
if _, _, err := post("delegate", delegateInput2); err != nil {
|
||||
if _, err = srv.Delegate(*delegateInput2); err != nil {
|
||||
t.Fatalf("failed to delegate for %s: %s", delegateInput2.Name, err)
|
||||
}
|
||||
if _, _, err := post("delegate", delegateInput3); err != nil {
|
||||
if _, err = srv.Delegate(*delegateInput3); err != nil {
|
||||
t.Fatalf("failed to delegate for %s: %s", delegateInput3.Name, err)
|
||||
}
|
||||
|
||||
restoreCheckLiveCount(t, 2)
|
||||
restoreCheckLiveUsers(t, []string{delegateInput2.Name, delegateInput3.Name},
|
||||
[]string{createUserInput1.Name, createVaultInput.Name})
|
||||
|
||||
// Encrypt a message, and make sure it can be decrypted.
|
||||
resp, err := srv.Encrypt(*restoreEncryptInput)
|
||||
restoreSecret = resp.Response
|
||||
|
||||
decryptInput := &core.DecryptRequest{
|
||||
Name: createVaultInput.Name,
|
||||
Password: createVaultInput.Password,
|
||||
Data: restoreSecret[:],
|
||||
}
|
||||
|
||||
decrypted, err := srv.DecryptIntoData(*decryptInput)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decrypt message: %s", err)
|
||||
}
|
||||
|
||||
decryptedMessage, err := base64.StdEncoding.DecodeString(string(decrypted))
|
||||
if string(decryptedMessage) != encryptMessage {
|
||||
t.Fatalf("decryption produced the wrong message: want '%s' but have '%s'",
|
||||
encryptMessage, decryptedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func afterRestartRestore(t *testing.T, cfgPath, vaultPath string) {
|
||||
cmd := restoreSetup(t, cfgPath, vaultPath)
|
||||
defer teardown(t, cmd)
|
||||
|
||||
srv, err := client.NewRemoteServer("localhost:8080", "testdata/server.crt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set up client: %s", err)
|
||||
}
|
||||
|
||||
// An existing vault with a persisted delegation store should
|
||||
// be inactive.
|
||||
restoreCheckStatus(t, persist.Inactive)
|
||||
|
||||
// Delegate a user who wasn't in the persisted delegation set.
|
||||
if _, _, err := post("delegate", delegateInput1); err != nil {
|
||||
t.Fatalf("Error delegating with user 1, %v", err)
|
||||
if _, err := srv.Delegate(*delegateInput1); err != nil {
|
||||
t.Fatalf("error delegating with user 1, %v", err)
|
||||
}
|
||||
|
||||
restoreCheckLiveCount(t, 1)
|
||||
@@ -865,7 +928,7 @@ func afterRestartRestore(t *testing.T, cfgPath, vaultPath string) {
|
||||
[]string{createUserInput2.Name, delegateInput3.Name, createVaultInput.Name})
|
||||
|
||||
// Begin the restoration by delegating for a single user.
|
||||
if _, _, err := post("restore", delegateInput1); err != nil {
|
||||
if _, err := srv.Restore(*delegateInput1); err != nil {
|
||||
t.Fatalf("restoration by user %s failed: %s", delegateInput1.Name, err)
|
||||
}
|
||||
|
||||
@@ -877,12 +940,56 @@ func afterRestartRestore(t *testing.T, cfgPath, vaultPath string) {
|
||||
|
||||
// Delegate the second user, which should lead to restoring
|
||||
// the delegations.
|
||||
if _, _, err := post("restore", delegateInput4); err != nil {
|
||||
t.Fatalf("restoration by user %s failed: %s", delegateInput4.Name, err)
|
||||
if _, err := srv.Restore(*delegateInput4); err != nil {
|
||||
t.Fatalf("restoration by user %s failed: %s", delegateInput1.Name, err)
|
||||
}
|
||||
|
||||
restoreCheckStatus(t, persist.Active)
|
||||
restoreCheckLiveCount(t, 2)
|
||||
restoreCheckLiveUsers(t, []string{delegateInput2.Name, delegateInput3.Name},
|
||||
[]string{createUserInput1.Name, createVaultInput.Name})
|
||||
|
||||
decryptInput := &core.DecryptRequest{
|
||||
Name: createVaultInput.Name,
|
||||
Password: createVaultInput.Password,
|
||||
Data: restoreSecret[:],
|
||||
}
|
||||
|
||||
decrypted, err := srv.DecryptIntoData(*decryptInput)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decrypt message: %s", err)
|
||||
}
|
||||
|
||||
decryptedMessage, err := base64.StdEncoding.DecodeString(string(decrypted))
|
||||
if string(decryptedMessage) != encryptMessage {
|
||||
t.Fatalf("decryption produced the wrong message: want '%s' but have '%s'",
|
||||
encryptMessage, decryptedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func afterRestartPurge(t *testing.T, cfgPath, vaultPath string) {
|
||||
cmd := restoreSetup(t, cfgPath, vaultPath)
|
||||
defer teardown(t, cmd)
|
||||
|
||||
srv, err := client.NewRemoteServer("localhost:8080", "testdata/server.crt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set up client: %s", err)
|
||||
}
|
||||
|
||||
// An existing vault with a persisted delegation store should
|
||||
// be inactive.
|
||||
restoreCheckStatus(t, persist.Inactive)
|
||||
|
||||
resp, err := srv.ResetPersisted(core.PurgeRequest{Name: createVaultInput.Name, Password: createVaultInput.Password})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to reset persisted delegations: %s", err)
|
||||
}
|
||||
|
||||
if resp.Status != "ok" {
|
||||
t.Fatalf("failed to reset persisted delegations: %s", resp.Status)
|
||||
}
|
||||
|
||||
// An existing vault whose persistence store has been reset
|
||||
// should be active.
|
||||
restoreCheckStatus(t, persist.Active)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user