Merge pull request #1463 from hashicorp/b-query-name-alias

Adds a check to make sure query names can't be registered twice.
This commit is contained in:
James Phillips 2015-12-02 09:30:53 -08:00
commit f3e724acbe
2 changed files with 68 additions and 26 deletions

View File

@ -76,6 +76,19 @@ func (s *StateStore) preparedQuerySetTxn(tx *memdb.Txn, idx uint64, query *struc
query.ModifyIndex = idx query.ModifyIndex = idx
} }
// Verify that the query name doesn't already exist, or that we are
// updating the same instance that has this name.
if query.Name != "" {
alias, err := tx.First("prepared-queries", "name", query.Name)
if err != nil {
return fmt.Errorf("failed prepared query lookup: %s", err)
}
if alias != nil && (existing == nil ||
existing.(*structs.PreparedQuery).ID != alias.(*structs.PreparedQuery).ID) {
return fmt.Errorf("name '%s' aliases an existing query name", query.Name)
}
}
// Verify that the name doesn't alias any existing ID. We allow queries // Verify that the name doesn't alias any existing ID. We allow queries
// to be looked up by ID *or* name so we don't want anyone to try to // to be looked up by ID *or* name so we don't want anyone to try to
// register a query with a name equal to some other query's ID in an // register a query with a name equal to some other query's ID in an
@ -86,12 +99,12 @@ func (s *StateStore) preparedQuerySetTxn(tx *memdb.Txn, idx uint64, query *struc
// index will complain if we look up something that's not formatted // index will complain if we look up something that's not formatted
// like one. // like one.
if isUUID(query.Name) { if isUUID(query.Name) {
existing, err := tx.First("prepared-queries", "id", query.Name) alias, err := tx.First("prepared-queries", "id", query.Name)
if err != nil { if err != nil {
return fmt.Errorf("failed prepared query lookup: %s", err) return fmt.Errorf("failed prepared query lookup: %s", err)
} }
if existing != nil { if alias != nil {
return fmt.Errorf("name '%s' aliases an existing query id", query.Name) return fmt.Errorf("name '%s' aliases an existing query ID", query.Name)
} }
} }

View File

@ -175,27 +175,22 @@ func TestStateStore_PreparedQuerySet_PreparedQueryGet(t *testing.T) {
t.Fatalf("bad: %v", actual) t.Fatalf("bad: %v", actual)
} }
// Finally, try to abuse the system by trying to register a query whose // Try to register a query with the same name and make sure it fails.
// name aliases a real query ID. {
evil := &structs.PreparedQuery{ evil := &structs.PreparedQuery{
ID: testUUID(), ID: testUUID(),
Name: query.ID, Name: query.Name,
Service: structs.ServiceQuery{ Service: structs.ServiceQuery{
Service: "redis", Service: "redis",
}, },
} }
err = s.PreparedQuerySet(7, evil) err := s.PreparedQuerySet(7, evil)
if err == nil || !strings.Contains(err.Error(), "aliases an existing query") { if err == nil || !strings.Contains(err.Error(), "aliases an existing query name") {
t.Fatalf("bad: %v", err) t.Fatalf("bad: %v", err)
} }
// Index is not updated if nothing is saved.
if idx := s.maxIndex("prepared-queries"); idx != 6 {
t.Fatalf("bad index: %d", idx)
}
// Sanity check to make sure it's not there. // Sanity check to make sure it's not there.
idx, actual, err = s.PreparedQueryGet(evil.ID) idx, actual, err := s.PreparedQueryGet(evil.ID)
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
@ -207,6 +202,40 @@ func TestStateStore_PreparedQuerySet_PreparedQueryGet(t *testing.T) {
} }
} }
// Try to abuse the system by trying to register a query whose name
// aliases a real query ID.
{
evil := &structs.PreparedQuery{
ID: testUUID(),
Name: query.ID,
Service: structs.ServiceQuery{
Service: "redis",
},
}
err := s.PreparedQuerySet(8, evil)
if err == nil || !strings.Contains(err.Error(), "aliases an existing query ID") {
t.Fatalf("bad: %v", err)
}
// Sanity check to make sure it's not there.
idx, actual, err := s.PreparedQueryGet(evil.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 6 {
t.Fatalf("bad index: %d", idx)
}
if actual != nil {
t.Fatalf("bad: %v", actual)
}
}
// Index is not updated if nothing is saved.
if idx := s.maxIndex("prepared-queries"); idx != 6 {
t.Fatalf("bad index: %d", idx)
}
}
func TestStateStore_PreparedQueryDelete(t *testing.T) { func TestStateStore_PreparedQueryDelete(t *testing.T) {
s := testStateStore(t) s := testStateStore(t)