open-vault/vault/expiration_test.go

1042 lines
21 KiB
Go
Raw Normal View History

2015-03-13 17:55:54 +00:00
package vault
import (
2016-03-09 21:47:58 +00:00
"fmt"
2015-03-13 17:55:54 +00:00
"reflect"
2015-03-16 21:59:37 +00:00
"sort"
2015-03-13 17:55:54 +00:00
"strings"
"testing"
"time"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/logical"
2016-03-09 21:47:58 +00:00
"github.com/hashicorp/vault/logical/framework"
2015-03-13 17:55:54 +00:00
)
// mockExpiration returns a mock expiration manager
func mockExpiration(t *testing.T) *ExpirationManager {
_, ts, _, _ := TestCoreWithTokenStore(t)
2015-04-10 21:59:49 +00:00
return ts.expiration
2015-03-13 17:55:54 +00:00
}
2015-03-16 22:11:35 +00:00
func TestExpiration_Restore(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "prod/aws/", &MountEntry{UUID: meUUID}, view)
2015-03-16 22:11:35 +00:00
paths := []string{
"prod/aws/foo",
"prod/aws/sub/bar",
"prod/aws/zip",
}
for _, path := range paths {
req := &logical.Request{
Operation: logical.ReadOperation,
Path: path,
}
resp := &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
},
2015-03-16 22:11:35 +00:00
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
_, err := exp.Register(req, resp)
if err != nil {
t.Fatalf("err: %v", err)
}
}
// Stop everything
err = exp.Stop()
2015-03-16 22:11:35 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Restore
err = exp.Restore()
if err != nil {
t.Fatalf("err: %v", err)
}
// Ensure all are reaped
start := time.Now()
for time.Now().Sub(start) < time.Second {
2015-04-29 02:17:45 +00:00
noop.Lock()
less := len(noop.Requests) < 3
noop.Unlock()
if less {
2015-03-16 22:11:35 +00:00
time.Sleep(5 * time.Millisecond)
continue
}
break
}
for _, req := range noop.Requests {
if req.Operation != logical.RevokeOperation {
t.Fatalf("Bad: %v", req)
}
}
}
2015-03-13 17:55:54 +00:00
func TestExpiration_Register(t *testing.T) {
exp := mockExpiration(t)
req := &logical.Request{
Operation: logical.ReadOperation,
2015-03-13 17:55:54 +00:00
Path: "prod/aws/foo",
}
resp := &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: time.Hour,
},
2015-03-13 17:55:54 +00:00
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
id, err := exp.Register(req, resp)
if err != nil {
t.Fatalf("err: %v", err)
}
if !strings.HasPrefix(id, req.Path) {
t.Fatalf("bad: %s", id)
}
if len(id) <= len(req.Path) {
t.Fatalf("bad: %s", id)
}
}
func TestExpiration_RegisterAuth(t *testing.T) {
exp := mockExpiration(t)
root, err := exp.tokenStore.rootToken()
if err != nil {
t.Fatalf("err: %v", err)
}
auth := &logical.Auth{
ClientToken: root.ID,
LeaseOptions: logical.LeaseOptions{
TTL: time.Hour,
},
}
err = exp.RegisterAuth("auth/github/login", auth)
if err != nil {
t.Fatalf("err: %v", err)
}
}
2015-04-08 22:43:26 +00:00
func TestExpiration_RegisterAuth_NoLease(t *testing.T) {
exp := mockExpiration(t)
root, err := exp.tokenStore.rootToken()
2015-04-08 22:43:26 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
auth := &logical.Auth{
ClientToken: root.ID,
}
err = exp.RegisterAuth("auth/github/login", auth)
if err != nil {
t.Fatalf("err: %v", err)
}
// Should not be able to renew, no expiration
2016-02-26 21:44:35 +00:00
_, err = exp.RenewToken(&logical.Request{}, "auth/github/login", root.ID, 0)
if err.Error() != "lease not found or lease is not renewable" {
2015-04-08 22:43:26 +00:00
t.Fatalf("err: %v", err)
}
// Wait and check token is not invalidated
time.Sleep(20 * time.Millisecond)
// Verify token does not get revoked
out, err := exp.tokenStore.Lookup(root.ID)
if err != nil {
t.Fatalf("err: %v", err)
}
if out == nil {
t.Fatalf("missing token")
}
}
2015-03-16 21:59:37 +00:00
func TestExpiration_Revoke(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "prod/aws/", &MountEntry{UUID: meUUID}, view)
2015-03-16 21:59:37 +00:00
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "prod/aws/foo",
}
resp := &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: time.Hour,
},
2015-03-16 21:59:37 +00:00
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
id, err := exp.Register(req, resp)
if err != nil {
t.Fatalf("err: %v", err)
}
if err := exp.Revoke(id); err != nil {
t.Fatalf("err: %v", err)
}
req = noop.Requests[0]
if req.Operation != logical.RevokeOperation {
t.Fatalf("Bad: %v", req)
}
}
func TestExpiration_RevokeOnExpire(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "prod/aws/", &MountEntry{UUID: meUUID}, view)
2015-03-16 21:59:37 +00:00
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "prod/aws/foo",
}
resp := &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
},
2015-03-16 21:59:37 +00:00
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
_, err = exp.Register(req, resp)
2015-03-16 21:59:37 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
start := time.Now()
for time.Now().Sub(start) < time.Second {
2015-04-29 02:17:45 +00:00
req = nil
noop.Lock()
if len(noop.Requests) > 0 {
req = noop.Requests[0]
}
noop.Unlock()
if req == nil {
2015-03-16 21:59:37 +00:00
time.Sleep(5 * time.Millisecond)
continue
}
if req.Operation != logical.RevokeOperation {
t.Fatalf("Bad: %v", req)
}
2015-04-29 02:17:45 +00:00
2015-03-16 21:59:37 +00:00
break
}
}
func TestExpiration_RevokePrefix(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "prod/aws/", &MountEntry{UUID: meUUID}, view)
2015-03-16 21:59:37 +00:00
paths := []string{
"prod/aws/foo",
"prod/aws/sub/bar",
"prod/aws/zip",
}
for _, path := range paths {
req := &logical.Request{
Operation: logical.ReadOperation,
Path: path,
}
resp := &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
},
2015-03-16 21:59:37 +00:00
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
_, err := exp.Register(req, resp)
if err != nil {
t.Fatalf("err: %v", err)
}
}
// Should nuke all the keys
if err := exp.RevokePrefix("prod/aws/"); err != nil {
t.Fatalf("err: %v", err)
}
if len(noop.Requests) != 3 {
2015-04-10 21:48:08 +00:00
t.Fatalf("Bad: %v", noop.Requests)
}
for _, req := range noop.Requests {
if req.Operation != logical.RevokeOperation {
t.Fatalf("Bad: %v", req)
}
}
expect := []string{
"foo",
"sub/bar",
"zip",
}
sort.Strings(noop.Paths)
sort.Strings(expect)
if !reflect.DeepEqual(noop.Paths, expect) {
t.Fatalf("bad: %v", noop.Paths)
}
}
func TestExpiration_RevokeByToken(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "prod/aws/", &MountEntry{UUID: meUUID}, view)
2015-04-10 21:48:08 +00:00
paths := []string{
"prod/aws/foo",
"prod/aws/sub/bar",
"prod/aws/zip",
}
for _, path := range paths {
req := &logical.Request{
Operation: logical.ReadOperation,
Path: path,
ClientToken: "foobarbaz",
}
resp := &logical.Response{
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
2015-04-10 21:48:08 +00:00
},
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
_, err := exp.Register(req, resp)
if err != nil {
t.Fatalf("err: %v", err)
}
}
// Should nuke all the keys
te := &TokenEntry{
ID: "foobarbaz",
}
if err := exp.RevokeByToken(te); err != nil {
2015-04-10 21:48:08 +00:00
t.Fatalf("err: %v", err)
}
if len(noop.Requests) != 3 {
2015-03-16 21:59:37 +00:00
t.Fatalf("Bad: %v", noop.Requests)
}
for _, req := range noop.Requests {
if req.Operation != logical.RevokeOperation {
t.Fatalf("Bad: %v", req)
}
}
expect := []string{
"foo",
"sub/bar",
"zip",
}
sort.Strings(noop.Paths)
sort.Strings(expect)
if !reflect.DeepEqual(noop.Paths, expect) {
t.Fatalf("bad: %v", noop.Paths)
}
}
func TestExpiration_RenewToken(t *testing.T) {
exp := mockExpiration(t)
root, err := exp.tokenStore.rootToken()
if err != nil {
t.Fatalf("err: %v", err)
}
// Register a token
auth := &logical.Auth{
ClientToken: root.ID,
LeaseOptions: logical.LeaseOptions{
TTL: time.Hour,
Renewable: true,
},
}
2015-04-09 21:23:37 +00:00
err = exp.RegisterAuth("auth/token/login", auth)
if err != nil {
t.Fatalf("err: %v", err)
}
// Renew the token
2016-02-26 21:44:35 +00:00
out, err := exp.RenewToken(&logical.Request{}, "auth/token/login", root.ID, 0)
if err != nil {
t.Fatalf("err: %v", err)
}
2016-03-04 20:03:01 +00:00
if auth.ClientToken != out.Auth.ClientToken {
2015-04-06 23:35:39 +00:00
t.Fatalf("Bad: %#v", out)
}
}
2015-04-09 00:03:46 +00:00
func TestExpiration_RenewToken_NotRenewable(t *testing.T) {
exp := mockExpiration(t)
root, err := exp.tokenStore.rootToken()
2015-04-09 00:03:46 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Register a token
auth := &logical.Auth{
ClientToken: root.ID,
LeaseOptions: logical.LeaseOptions{
TTL: time.Hour,
Renewable: false,
},
2015-04-09 00:03:46 +00:00
}
err = exp.RegisterAuth("auth/github/login", auth)
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to renew the token
2016-02-26 21:44:35 +00:00
_, err = exp.RenewToken(&logical.Request{}, "auth/github/login", root.ID, 0)
2015-04-09 00:03:46 +00:00
if err.Error() != "lease is not renewable" {
t.Fatalf("err: %v", err)
}
}
2015-03-16 21:59:37 +00:00
func TestExpiration_Renew(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "prod/aws/", &MountEntry{UUID: meUUID}, view)
2015-03-16 21:59:37 +00:00
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "prod/aws/foo",
}
resp := &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
Renewable: true,
},
2015-03-16 21:59:37 +00:00
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
id, err := exp.Register(req, resp)
if err != nil {
t.Fatalf("err: %v", err)
}
noop.Response = &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
},
2015-03-16 21:59:37 +00:00
},
Data: map[string]interface{}{
"access_key": "123",
"secret_key": "abcd",
},
}
out, err := exp.Renew(id, 0)
if err != nil {
t.Fatalf("err: %v", err)
}
2015-04-29 02:17:45 +00:00
noop.Lock()
defer noop.Unlock()
2015-03-16 21:59:37 +00:00
if !reflect.DeepEqual(out, noop.Response) {
t.Fatalf("Bad: %#v", out)
}
if len(noop.Requests) != 1 {
t.Fatalf("Bad: %#v", noop.Requests)
}
req = noop.Requests[0]
if req.Operation != logical.RenewOperation {
t.Fatalf("Bad: %v", req)
}
}
2015-04-09 00:03:46 +00:00
func TestExpiration_Renew_NotRenewable(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "prod/aws/", &MountEntry{UUID: meUUID}, view)
2015-04-09 00:03:46 +00:00
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "prod/aws/foo",
}
resp := &logical.Response{
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
Renewable: false,
},
2015-04-09 00:03:46 +00:00
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
id, err := exp.Register(req, resp)
if err != nil {
t.Fatalf("err: %v", err)
}
_, err = exp.Renew(id, 0)
if err.Error() != "lease is not renewable" {
t.Fatalf("err: %v", err)
}
2015-04-29 02:17:45 +00:00
noop.Lock()
defer noop.Unlock()
2015-04-09 00:03:46 +00:00
if len(noop.Requests) != 0 {
t.Fatalf("Bad: %#v", noop.Requests)
}
}
2015-03-16 21:59:37 +00:00
func TestExpiration_Renew_RevokeOnExpire(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "prod/aws/", &MountEntry{UUID: meUUID}, view)
2015-03-16 21:59:37 +00:00
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "prod/aws/foo",
}
resp := &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
Renewable: true,
},
2015-03-16 21:59:37 +00:00
},
Data: map[string]interface{}{
"access_key": "xyz",
"secret_key": "abcd",
},
}
id, err := exp.Register(req, resp)
if err != nil {
t.Fatalf("err: %v", err)
}
noop.Response = &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: 20 * time.Millisecond,
},
2015-03-16 21:59:37 +00:00
},
Data: map[string]interface{}{
"access_key": "123",
"secret_key": "abcd",
},
}
_, err = exp.Renew(id, 0)
if err != nil {
t.Fatalf("err: %v", err)
}
start := time.Now()
for time.Now().Sub(start) < time.Second {
2015-04-29 02:17:45 +00:00
req = nil
noop.Lock()
if len(noop.Requests) >= 2 {
req = noop.Requests[1]
}
noop.Unlock()
if req == nil {
2015-03-16 21:59:37 +00:00
time.Sleep(5 * time.Millisecond)
continue
}
if req.Operation != logical.RevokeOperation {
t.Fatalf("Bad: %v", req)
}
break
}
}
func TestExpiration_revokeEntry(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "", &MountEntry{UUID: meUUID}, view)
le := &leaseEntry{
LeaseID: "foo/bar/1234",
Path: "foo/bar",
Data: map[string]interface{}{
"testing": true,
},
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: time.Minute,
},
},
IssueTime: time.Now(),
ExpireTime: time.Now(),
}
err = exp.revokeEntry(le)
if err != nil {
t.Fatalf("err: %v", err)
}
2015-04-29 02:17:45 +00:00
noop.Lock()
defer noop.Unlock()
req := noop.Requests[0]
if req.Operation != logical.RevokeOperation {
t.Fatalf("Bad: %v", req)
}
if req.Path != le.Path {
t.Fatalf("Bad: %v", req)
}
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
if !reflect.DeepEqual(req.Data, le.Data) {
t.Fatalf("Bad: %v", req)
}
}
func TestExpiration_revokeEntry_token(t *testing.T) {
exp := mockExpiration(t)
root, err := exp.tokenStore.rootToken()
if err != nil {
t.Fatalf("err: %v", err)
}
le := &leaseEntry{
LeaseID: "foo/bar/1234",
Auth: &logical.Auth{
ClientToken: root.ID,
LeaseOptions: logical.LeaseOptions{
TTL: time.Minute,
},
},
ClientToken: root.ID,
Path: "foo/bar",
IssueTime: time.Now(),
ExpireTime: time.Now(),
}
if err := exp.persistEntry(le); err != nil {
t.Fatalf("error persisting entry: %v", err)
}
if err := exp.createIndexByToken(le.ClientToken, le.LeaseID); err != nil {
t.Fatalf("error creating secondary index: %v", err)
}
exp.updatePending(le, le.Auth.LeaseTotal())
indexEntry, err := exp.indexByToken(le.ClientToken, le.LeaseID)
if err != nil {
t.Fatalf("err: %v")
}
if indexEntry == nil {
t.Fatalf("err: should have found a secondary index entry")
}
err = exp.revokeEntry(le)
if err != nil {
t.Fatalf("err: %v", err)
}
out, err := exp.tokenStore.Lookup(le.ClientToken)
if err != nil {
t.Fatalf("err: %v", err)
}
if out != nil {
t.Fatalf("bad: %v", out)
}
indexEntry, err = exp.indexByToken(le.ClientToken, le.LeaseID)
if err != nil {
t.Fatalf("err: %v")
}
if indexEntry != nil {
t.Fatalf("err: should not have found a secondary index entry")
}
}
func TestExpiration_renewEntry(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{
Response: &logical.Response{
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
Renewable: true,
TTL: time.Hour,
},
},
Data: map[string]interface{}{
"testing": false,
},
},
}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "logical/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "", &MountEntry{UUID: meUUID}, view)
le := &leaseEntry{
LeaseID: "foo/bar/1234",
Path: "foo/bar",
Data: map[string]interface{}{
"testing": true,
},
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: time.Minute,
},
},
IssueTime: time.Now(),
ExpireTime: time.Now(),
}
2015-03-16 21:59:37 +00:00
resp, err := exp.renewEntry(le, time.Second)
if err != nil {
t.Fatalf("err: %v", err)
}
2015-04-29 02:17:45 +00:00
noop.Lock()
defer noop.Unlock()
if !reflect.DeepEqual(resp, noop.Response) {
t.Fatalf("bad: %#v", resp)
}
req := noop.Requests[0]
if req.Operation != logical.RenewOperation {
t.Fatalf("Bad: %v", req)
}
if req.Path != le.Path {
t.Fatalf("Bad: %v", req)
}
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
if !reflect.DeepEqual(req.Data, le.Data) {
2015-03-16 21:59:37 +00:00
t.Fatalf("Bad: %v", req)
}
if req.Secret.Increment != time.Second {
t.Fatalf("Bad: %v", req)
}
if req.Secret.IssueTime.IsZero() {
t.Fatalf("Bad: %v", req)
}
}
2015-04-10 21:07:06 +00:00
func TestExpiration_renewAuthEntry(t *testing.T) {
exp := mockExpiration(t)
noop := &NoopBackend{
Response: &logical.Response{
Auth: &logical.Auth{
LeaseOptions: logical.LeaseOptions{
Renewable: true,
TTL: time.Hour,
2015-04-10 21:07:06 +00:00
},
},
},
}
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "auth/foo/")
meUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
exp.router.Mount(noop, "auth/foo/", &MountEntry{UUID: meUUID}, view)
2015-04-10 21:07:06 +00:00
le := &leaseEntry{
LeaseID: "auth/foo/1234",
Path: "auth/foo/login",
Auth: &logical.Auth{
LeaseOptions: logical.LeaseOptions{
Renewable: true,
TTL: time.Minute,
2015-04-10 21:07:06 +00:00
},
2015-05-09 18:39:54 +00:00
InternalData: map[string]interface{}{
"MySecret": "secret",
},
2015-04-10 21:07:06 +00:00
},
IssueTime: time.Now(),
ExpireTime: time.Now().Add(time.Minute),
}
2016-02-26 21:44:35 +00:00
resp, err := exp.renewAuthEntry(&logical.Request{}, le, time.Second)
2015-04-10 21:07:06 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2015-04-29 02:17:45 +00:00
noop.Lock()
defer noop.Unlock()
2015-04-10 21:07:06 +00:00
if !reflect.DeepEqual(resp, noop.Response) {
t.Fatalf("bad: %#v", resp)
}
req := noop.Requests[0]
if req.Operation != logical.RenewOperation {
t.Fatalf("Bad: %v", req)
}
if req.Path != "login" {
t.Fatalf("Bad: %v", req)
}
if req.Auth.Increment != time.Second {
2015-04-10 21:07:06 +00:00
t.Fatalf("Bad: %v", req)
}
if req.Auth.IssueTime.IsZero() {
2015-04-10 21:07:06 +00:00
t.Fatalf("Bad: %v", req)
}
2015-05-09 18:39:54 +00:00
if req.Auth.InternalData["MySecret"] != "secret" {
t.Fatalf("Bad: %v", req)
}
2015-04-10 21:07:06 +00:00
}
func TestExpiration_PersistLoadDelete(t *testing.T) {
exp := mockExpiration(t)
le := &leaseEntry{
LeaseID: "foo/bar/1234",
Path: "foo/bar",
Data: map[string]interface{}{
"testing": true,
},
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: time.Minute,
},
},
IssueTime: time.Now().UTC(),
ExpireTime: time.Now().UTC(),
LastRenewalTime: time.Time{}.UTC(),
}
if err := exp.persistEntry(le); err != nil {
t.Fatalf("err: %v", err)
}
out, err := exp.loadEntry("foo/bar/1234")
if err != nil {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(out, le) {
t.Fatalf("\nout: %#v\nexpect: %#v\n", out, le)
}
err = exp.deleteEntry("foo/bar/1234")
if err != nil {
t.Fatalf("err: %v", err)
}
out, err = exp.loadEntry("foo/bar/1234")
if err != nil {
t.Fatalf("err: %v", err)
}
if out != nil {
t.Fatalf("out: %#v", out)
}
}
2015-03-13 17:55:54 +00:00
func TestLeaseEntry(t *testing.T) {
le := &leaseEntry{
LeaseID: "foo/bar/1234",
2015-03-13 17:55:54 +00:00
Path: "foo/bar",
Data: map[string]interface{}{
"testing": true,
},
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Secret: &logical.Secret{
LeaseOptions: logical.LeaseOptions{
TTL: time.Minute,
},
2015-03-13 17:55:54 +00:00
},
2015-04-29 01:12:57 +00:00
IssueTime: time.Now().UTC(),
ExpireTime: time.Now().UTC(),
2015-03-13 17:55:54 +00:00
}
enc, err := le.encode()
if err != nil {
t.Fatalf("err: %v", err)
}
out, err := decodeLeaseEntry(enc)
if err != nil {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(out.Data, le.Data) {
t.Fatalf("got: %#v, expect %#v", out, le)
}
}
2016-03-09 21:47:58 +00:00
func TestExpiration_RevokeForce(t *testing.T) {
core, _, _, root := TestCoreWithTokenStore(t)
core.logicalBackends["badrenew"] = badRenewFactory
me := &MountEntry{
Path: "badrenew/",
Type: "badrenew",
}
err := core.mount(me)
if err != nil {
t.Fatal(err)
}
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "badrenew/creds",
ClientToken: root,
}
resp, err := core.HandleRequest(req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("response was nil")
}
if resp.Secret == nil {
t.Fatalf("response secret was nil, response was %#v", *resp)
}
req.Operation = logical.UpdateOperation
req.Path = "sys/revoke-prefix/badrenew/creds"
resp, err = core.HandleRequest(req)
if err == nil {
t.Fatal("expected error")
}
req.Path = "sys/revoke-force/badrenew/creds"
resp, err = core.HandleRequest(req)
if err != nil {
t.Fatalf("got error: %s", err)
}
}
func badRenewFactory(conf *logical.BackendConfig) (logical.Backend, error) {
be := &framework.Backend{
Paths: []*framework.Path{
&framework.Path{
Pattern: "creds",
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: func(*logical.Request, *framework.FieldData) (*logical.Response, error) {
resp := &logical.Response{
Secret: &logical.Secret{
InternalData: map[string]interface{}{
"secret_type": "badRenewBackend",
},
},
}
resp.Secret.TTL = time.Second * 30
return resp, nil
},
},
},
},
Secrets: []*framework.Secret{
&framework.Secret{
Type: "badRenewBackend",
Revoke: func(*logical.Request, *framework.FieldData) (*logical.Response, error) {
return nil, fmt.Errorf("always errors")
},
},
},
}
return be.Setup(conf)
}