mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-08-15 11:46:16 +00:00
Properly restore delegations.
This change addresses several points: 1. The integration tests didn't verify that delegations could be used for decryption following a restore. The integration tests now verify this. 2. There was no functionality for clearing persisted delegations if needed. The vault admin can now do this via the command line tool. 3. Restoring active delegations wasn't storing the key with the delegation. Keys are now serialised properly. 4. [Minor] The MSP package now reports the name of the offending user when it can't find a user name in the database.
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