Skip to content

Commit

Permalink
Implementation of a file-backed persistence store.
Browse files Browse the repository at this point in the history
This is a rather large change. It consists of the following changes:

+ Direct access to the keycache has been removed from the core
  package. This forces all interaction with the cache to go
  through the Cryptor, which is required for persistence. The
  Cryptor needs to know when the cache has changed, and the only
  way to do this effectively is to make the Cryptor responsible
  for managing the keycache.

+ A new persist package has been added. This provides a Store
  interface, for which two implementations are provided. The
  first is a null persister: this is used when no persistence
  is configured. The second is a file-backed persistence store.

+ The Cryptor now persists the cache every time it changes.

Additionally, a number of missing returns in a function in the core
package have been added.
  • Loading branch information
kisom committed Aug 4, 2016
1 parent c230e7a commit 15a8126
Show file tree
Hide file tree
Showing 13 changed files with 1,074 additions and 48 deletions.
14 changes: 12 additions & 2 deletions config/config.go
Expand Up @@ -77,8 +77,18 @@ type Delegations struct {
Persist bool `json:"persist"`

// Policy contains the MSP predicate for delegation
// persistence.
Policy string `json:"policy"`
// persistence, and users contains the users allowed
// to delegate.
Policy string `json:"policy"`
Users []string `json:"users"`

// Mechanism specifies the persistence mechanism to use.
Mechanism string `json:"mechanism"`

// Location contains location information for the persistence
// mechanism, such as a file path or database connection
// string.
Location string `json:"location"`
}

// Config contains all the configuration options for a redoctober
Expand Down
52 changes: 28 additions & 24 deletions core/core.go
Expand Up @@ -18,12 +18,12 @@ import (
"github.com/cloudflare/redoctober/keycache"
"github.com/cloudflare/redoctober/order"
"github.com/cloudflare/redoctober/passvault"
"github.com/cloudflare/redoctober/persist"
)

var (
crypt cryptor.Cryptor
crypt *cryptor.Cryptor
records passvault.Records
cache keycache.Cache
orders order.Orderer
)

Expand Down Expand Up @@ -177,14 +177,6 @@ type StatusData struct {
Status string
}

// Delegation restoration and persistance configuration follows.

const (
PDStateNeverPersist = "disabled"
PDStateNotPersisting = "inactive"
PDStateNowPersisting = "active"
)

var restore struct {
Config *config.Delegations
State string
Expand All @@ -199,7 +191,7 @@ func jsonStatusError(err error) ([]byte, error) {
return json.Marshal(ResponseData{Status: err.Error()})
}
func jsonSummary() ([]byte, error) {
return json.Marshal(SummaryData{Status: "ok", Live: cache.GetSummary(), All: records.GetSummary()})
return json.Marshal(SummaryData{Status: "ok", Live: crypt.LiveSummary(), All: records.GetSummary()})
}
func jsonResponse(resp []byte) ([]byte, error) {
return json.Marshal(ResponseData{Status: "ok", Response: resp})
Expand Down Expand Up @@ -273,11 +265,10 @@ func Init(path string, config *config.Config) error {
}

restore.Config = config.Delegations
restore.State = PDStateNeverPersist
restore.State = persist.Disabled

orders = order.NewOrderer(hipchatClient)
cache = keycache.Cache{UserKeys: make(map[keycache.DelegateIndex]keycache.ActiveUser)}
crypt = cryptor.New(&records, &cache)
crypt, err = cryptor.New(&records, nil, config)

return err
}
Expand Down Expand Up @@ -320,7 +311,6 @@ func Create(jsonIn []byte) ([]byte, error) {
func Summary(jsonIn []byte) ([]byte, error) {
var s SummaryRequest
var err error
cache.Refresh()

defer func() {
if err != nil {
Expand All @@ -330,6 +320,11 @@ func Summary(jsonIn []byte) ([]byte, error) {
}
}()

err = crypt.Refresh()
if err != nil {
return jsonStatusError(err)
}

if err := json.Unmarshal(jsonIn, &s); err != nil {
return jsonStatusError(err)
}
Expand Down Expand Up @@ -373,7 +368,11 @@ func Purge(jsonIn []byte) ([]byte, error) {
return jsonStatusError(err)
}

cache.FlushCache()
err = crypt.Flush()
if err != nil {
return jsonStatusError(err)
}

return jsonStatusOk()
}

Expand Down Expand Up @@ -426,7 +425,7 @@ func Delegate(jsonIn []byte) ([]byte, error) {
}

// add signed-in record to active set
if err = cache.AddKeyFromRecord(pr, s.Name, s.Password, s.Users, s.Labels, s.Uses, s.Slot, s.Time); err != nil {
if err = crypt.Delegate(pr, s.Name, s.Password, s.Users, s.Labels, s.Uses, s.Slot, s.Time); err != nil {
return jsonStatusError(err)
}

Expand Down Expand Up @@ -798,27 +797,32 @@ func Order(jsonIn []byte) (out []byte, err error) {
// Get the owners of the ciphertext.
owners, _, err := crypt.GetOwners(o.EncryptedData)
if err != nil {
jsonStatusError(err)
return jsonStatusError(err)
}
if o.Duration == "" {
err = errors.New("Duration required when placing an order.")
jsonStatusError(err)
return jsonStatusError(err)
}
if o.Uses == 0 {
err = errors.New("Number of required uses necessary when placing an order.")
jsonStatusError(err)
return jsonStatusError(err)
}

err = crypt.Refresh()
if err != nil {
return jsonStatusError(err)
}
cache.Refresh()

orderNum := order.GenerateNum()

if len(o.Users) == 0 {
err = errors.New("Must specify at least one user per order.")
jsonStatusError(err)
return jsonStatusError(err)
}
adminsDelegated, numDelegated := cache.DelegateStatus(o.Users[0], o.Labels, owners)
adminsDelegated, numDelegated := crypt.DelegateStatus(o.Users[0], o.Labels, owners)
duration, err := time.ParseDuration(o.Duration)
if err != nil {
jsonStatusError(err)
return jsonStatusError(err)
}
currentTime := time.Now()
ord := order.CreateOrder(o.Name,
Expand Down
37 changes: 26 additions & 11 deletions core/core_test.go
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/cloudflare/redoctober/config"
"github.com/cloudflare/redoctober/passvault"
"github.com/cloudflare/redoctober/persist"
)

func TestCreate(t *testing.T) {
Expand Down Expand Up @@ -97,9 +98,9 @@ func TestSummary(t *testing.T) {
if err != nil {
t.Fatalf("Error getting status, %v", err)
}
if st.Status != PDStateNeverPersist {
if st.Status != persist.Disabled {
t.Fatalf("Persistent delegations should be '%s' but are '%s'",
PDStateNeverPersist, st.Status)
persist.Disabled, st.Status)
}

respJson, err = Summary(createJson)
Expand Down Expand Up @@ -174,7 +175,7 @@ func TestSummary(t *testing.T) {

dataLive, ok := s.Live["Bob"]
if !ok {
t.Fatalf("Error in summary of account, record missing, %v", cache.UserKeys)
t.Fatalf("Error in summary of account, record missing, %v", crypt.LiveSummary())
}
if dataLive.Admin != false {
t.Fatalf("Error in summary of account, record missing")
Expand All @@ -184,7 +185,7 @@ func TestSummary(t *testing.T) {
}

var s1 SummaryData
delegations := cache.GetSummary()
delegations := crypt.LiveSummary()
if len(delegations) == 0 {
t.Fatal("no delegations active")
}
Expand Down Expand Up @@ -230,7 +231,7 @@ func TestSummary(t *testing.T) {
t.Fatal("Bob was removed from the list of users")
}

delegations = cache.GetSummary()
delegations = crypt.LiveSummary()
if len(delegations) != 0 {
t.Fatalf("purge failed to clear delegations (%d delegations remain)", len(delegations))
}
Expand Down Expand Up @@ -470,7 +471,11 @@ func TestEncryptDecrypt(t *testing.T) {
}

// check summary to see if none are delegated
cache.Refresh()
err = crypt.Refresh()
if err != nil {
t.Fatalf("Error in summary: %s", err)
}

respJson, err = Summary(summaryJson)
if err != nil {
t.Fatalf("Error in summary, %v", err)
Expand Down Expand Up @@ -557,7 +562,11 @@ func TestEncryptDecrypt(t *testing.T) {
}

// verify the presence of the two delgations
cache.Refresh()
err = crypt.Refresh()
if err != nil {
t.Fatalf("Error in summary: %s", err)
}

var sum2 SummaryData
respJson, err = Summary(summaryJson)
if err != nil {
Expand Down Expand Up @@ -936,7 +945,11 @@ func TestModify(t *testing.T) {
}

// check summary to see if none are delegated
cache.Refresh()
err = crypt.Refresh()
if err != nil {
t.Fatalf("Error refreshing: %s", err)
}

respJson, err = Summary(summaryJson)
if err != nil {
t.Fatalf("Error in summary, %v", err)
Expand Down Expand Up @@ -1078,6 +1091,7 @@ func TestStatic(t *testing.T) {
if err != nil {
t.Fatalf("Error opening file, %v", err)
}
defer os.Remove("/tmp/db1.json")

_, err = file.Write(diskVault)
if err != nil {
Expand Down Expand Up @@ -1139,9 +1153,10 @@ func TestStatic(t *testing.T) {
t.Fatalf("Error in summary, %v, %v", expected, r.Response)
}

cache.FlushCache()

os.Remove("/tmp/db1.json")
err = crypt.Flush()
if err != nil {
t.Fatalf("Error flushing cache: %s", err)
}
}

func TestValidateName(t *testing.T) {
Expand Down

0 comments on commit 15a8126

Please sign in to comment.