Merge pull request #1227 from hashicorp/issue-477
Don't renew cert-based tokens if the policies have changed.
This commit is contained in:
commit
3e3621841d
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
logicaltest "github.com/hashicorp/vault/logical/testing"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
@ -383,3 +384,122 @@ func testConnState(t *testing.T, certPath, keyPath, rootCertPath string) tls.Con
|
|||
connState := serverConn.(*tls.Conn).ConnectionState()
|
||||
return connState
|
||||
}
|
||||
|
||||
func Test_Renew(t *testing.T) {
|
||||
storage := &logical.InmemStorage{}
|
||||
|
||||
lb, err := Factory(&logical.BackendConfig{
|
||||
System: &logical.StaticSystemView{
|
||||
DefaultLeaseTTLVal: 300 * time.Second,
|
||||
MaxLeaseTTLVal: 1800 * time.Second,
|
||||
},
|
||||
StorageView: storage,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error: %s", err)
|
||||
}
|
||||
|
||||
b := lb.(*backend)
|
||||
connState := testConnState(t, "test-fixtures/keys/cert.pem",
|
||||
"test-fixtures/keys/key.pem", "test-fixtures/root/rootcacert.pem")
|
||||
ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
req := &logical.Request{
|
||||
Connection: &logical.Connection{
|
||||
ConnState: &connState,
|
||||
},
|
||||
Storage: storage,
|
||||
Auth: &logical.Auth{},
|
||||
}
|
||||
|
||||
fd := &framework.FieldData{
|
||||
Raw: map[string]interface{}{
|
||||
"name": "test",
|
||||
"certificate": ca,
|
||||
"policies": "foo,bar",
|
||||
},
|
||||
Schema: pathCerts(b).Fields,
|
||||
}
|
||||
|
||||
resp, err := b.pathCertWrite(req, fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err = b.pathLogin(req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req.Auth.InternalData = resp.Auth.InternalData
|
||||
req.Auth.Metadata = resp.Auth.Metadata
|
||||
req.Auth.LeaseOptions = resp.Auth.LeaseOptions
|
||||
req.Auth.IssueTime = time.Now()
|
||||
|
||||
// Normal renewal
|
||||
resp, err = b.pathLoginRenew(req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatal("got nil response from renew")
|
||||
}
|
||||
if resp.IsError() {
|
||||
t.Fatalf("got error: %#v", *resp)
|
||||
}
|
||||
|
||||
// Change the policies -- this should fail
|
||||
fd.Raw["policies"] = "zip,zap"
|
||||
resp, err = b.pathCertWrite(req, fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err = b.pathLoginRenew(req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatal("got nil response from renew")
|
||||
}
|
||||
if !resp.IsError() {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
// Put the policies back, this shold be okay
|
||||
fd.Raw["policies"] = "bar,foo"
|
||||
resp, err = b.pathCertWrite(req, fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err = b.pathLoginRenew(req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatal("got nil response from renew")
|
||||
}
|
||||
if resp.IsError() {
|
||||
t.Fatal("got error: %#v", *resp)
|
||||
}
|
||||
|
||||
// Delete CA, make sure we can't renew
|
||||
resp, err = b.pathCertDelete(req, fd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err = b.pathLoginRenew(req, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatal("got nil response from renew")
|
||||
}
|
||||
if !resp.IsError() {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/vault/helper/certutil"
|
||||
|
@ -58,12 +59,16 @@ func (b *backend) pathLogin(
|
|||
skid := base64.StdEncoding.EncodeToString(clientCerts[0].SubjectKeyId)
|
||||
akid := base64.StdEncoding.EncodeToString(clientCerts[0].AuthorityKeyId)
|
||||
|
||||
// We want to sort here so we can check properly during renewal)
|
||||
sort.Strings(matched.Entry.Policies)
|
||||
|
||||
// Generate a response
|
||||
resp := &logical.Response{
|
||||
Auth: &logical.Auth{
|
||||
InternalData: map[string]interface{}{
|
||||
"subject_key_id": skid,
|
||||
"authority_key_id": akid,
|
||||
"policies": strings.Join(matched.Entry.Policies, ","),
|
||||
},
|
||||
Policies: matched.Entry.Policies,
|
||||
DisplayName: matched.Entry.DisplayName,
|
||||
|
@ -127,6 +132,12 @@ func (b *backend) pathLoginRenew(
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
policies := cert.Policies
|
||||
sort.Strings(policies)
|
||||
if strings.Join(policies, ",") != req.Auth.InternalData["policies"] {
|
||||
return logical.ErrorResponse("policies have changed, not renewing"), nil
|
||||
}
|
||||
|
||||
return framework.LeaseExtend(cert.TTL, 0, b.System())(req, d)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue