Sync over

This commit is contained in:
Jeff Mitchell 2017-10-23 16:42:56 -04:00
parent aaa1094240
commit c144f95be0
36 changed files with 521 additions and 167 deletions

View File

@ -33,6 +33,28 @@ func (r ReplicationState) String() string {
return "disabled"
}
func (r ReplicationState) GetDRString() string {
switch {
case r.HasState(ReplicationDRPrimary):
return ReplicationDRPrimary.String()
case r.HasState(ReplicationDRSecondary):
return ReplicationDRSecondary.String()
default:
return ReplicationDisabled.String()
}
}
func (r ReplicationState) GetPerformanceString() string {
switch {
case r.HasState(ReplicationPerformancePrimary):
return ReplicationPerformancePrimary.String()
case r.HasState(ReplicationPerformanceSecondary):
return ReplicationPerformanceSecondary.String()
default:
return ReplicationDisabled.String()
}
}
func (r ReplicationState) HasState(flag ReplicationState) bool { return r&flag != 0 }
func (r *ReplicationState) AddState(flag ReplicationState) { *r |= flag }
func (r *ReplicationState) ClearState(flag ReplicationState) { *r &= ^flag }

View File

@ -0,0 +1,83 @@
package identity
import "github.com/golang/protobuf/ptypes"
func (e *Entity) SentinelGet(key string) (interface{}, error) {
if e == nil {
return nil, nil
}
switch key {
case "aliases":
return e.Aliases, nil
case "id":
return e.ID, nil
case "meta", "metadata":
return e.Metadata, nil
case "name":
return e.Name, nil
case "creation_time":
return ptypes.TimestampString(e.CreationTime), nil
case "last_update_time":
return ptypes.TimestampString(e.LastUpdateTime), nil
case "merged_entity_ids":
return e.MergedEntityIDs, nil
case "policies":
return e.Policies, nil
}
return nil, nil
}
func (p *Alias) SentinelGet(key string) (interface{}, error) {
if p == nil {
return nil, nil
}
switch key {
case "id":
return p.ID, nil
case "mount_type":
return p.MountType, nil
case "mount_accessor":
return p.MountAccessor, nil
case "mount_path":
return p.MountPath, nil
case "meta", "metadata":
return p.Metadata, nil
case "name":
return p.Name, nil
case "creation_time":
return ptypes.TimestampString(p.CreationTime), nil
case "last_update_time":
return ptypes.TimestampString(p.LastUpdateTime), nil
case "merged_from_entity_ids":
return p.MergedFromEntityIDs, nil
}
return nil, nil
}
func (g *Group) SentinelGet(key string) (interface{}, error) {
if g == nil {
return nil, nil
}
switch key {
case "id":
return g.ID, nil
case "name":
return g.Name, nil
case "policies":
return g.Policies, nil
case "parent_group_ids":
return g.ParentGroupIDs, nil
case "member_entity_ids":
return g.MemberEntityIDs, nil
case "meta", "metadata":
return g.Metadata, nil
case "creation_time":
return ptypes.TimestampString(g.CreationTime), nil
case "last_update_time":
return ptypes.TimestampString(g.LastUpdateTime), nil
}
return nil, nil
}

View File

@ -22,7 +22,7 @@ func pathDuoConfig() *framework.Path {
},
"push_info": &framework.FieldSchema{
Type: framework.TypeString,
Description: "A string of URL-encoded key/value pairs that provides additional context about the authentication attemmpt in the Duo Mobile app",
Description: "A string of URL-encoded key/value pairs that provides additional context about the authentication attempt in the Duo Mobile app",
},
},

View File

@ -30,8 +30,8 @@ var _ = math.Inf
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Item struct {
ID string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Message *google_protobuf.Any `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
ID string `sentinel:"" protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
Message *google_protobuf.Any `sentinel:"" protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
}
func (m *Item) Reset() { *m = Item{} }
@ -54,8 +54,8 @@ func (m *Item) GetMessage() *google_protobuf.Any {
}
type Bucket struct {
Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
Items []*Item `protobuf:"bytes,2,rep,name=items" json:"items,omitempty"`
Key string `sentinel:"" protobuf:"bytes,1,opt,name=key" json:"key,omitempty"`
Items []*Item `sentinel:"" protobuf:"bytes,2,rep,name=items" json:"items,omitempty"`
}
func (m *Bucket) Reset() { *m = Bucket{} }

View File

@ -11,5 +11,5 @@ type Connection struct {
RemoteAddr string `json:"remote_addr"`
// ConnState is the TLS connection state if applicable.
ConnState *tls.ConnectionState
ConnState *tls.ConnectionState `sentinel:""`
}

View File

@ -16,9 +16,11 @@ const (
// TypeSlice represents a slice of any type
TypeSlice
// TypeStringSlice is a helper for TypeSlice that returns a sanitized
// slice of strings
TypeStringSlice
// TypeCommaStringSlice is a helper for TypeSlice that returns a sanitized
// slice of strings and also supports parsing a comma-separated list in
// a string field

View File

@ -1,6 +1,8 @@
package logical
import "time"
import (
"time"
)
// LeaseOptions is an embeddable struct to capture common lease
// settings between a Secret and Auth

View File

@ -117,4 +117,9 @@ type Paths struct {
// LocalStorage are paths (prefixes) that are local to this instance; this
// indicates that these paths should not be replicated
LocalStorage []string
// SealWrapStorage are storage paths that, when using a capable seal,
// should be seal wrapped with extra encryption. It is exact matching
// unless it ends with '/' in which case it will be treated as a prefix.
SealWrapStorage []string
}

View File

@ -26,7 +26,6 @@ func (b *backend) pathInternalUpdate(
b.internal = value
// Return the secret
return nil, nil
}
func (b *backend) pathInternalRead(
@ -37,5 +36,4 @@ func (b *backend) pathInternalRead(
"value": b.internal,
},
}, nil
}

View File

@ -3,6 +3,7 @@ package logical
import (
"errors"
"fmt"
"strings"
"time"
)
@ -11,23 +12,41 @@ import (
type RequestWrapInfo struct {
// Setting to non-zero specifies that the response should be wrapped.
// Specifies the desired TTL of the wrapping token.
TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"`
TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl" sentinel:""`
// The format to use for the wrapped response; if not specified it's a bare
// token
Format string `json:"format" structs:"format" mapstructure:"format"`
Format string `json:"format" structs:"format" mapstructure:"format" sentinel:""`
}
// Request is a struct that stores the parameters and context
// of a request being made to Vault. It is used to abstract
// the details of the higher level request protocol from the handlers.
func (r *RequestWrapInfo) SentinelGet(key string) (interface{}, error) {
if r == nil {
return nil, nil
}
switch key {
case "ttl":
return r.TTL, nil
case "ttl_seconds":
return int64(r.TTL.Seconds()), nil
}
return nil, nil
}
// Request is a struct that stores the parameters and context of a request
// being made to Vault. It is used to abstract the details of the higher level
// request protocol from the handlers.
//
// Note: Many of these have Sentinel disabled because they are values populated
// by the router after policy checks; the token namespace would be the right
// place to access them via Sentinel
type Request struct {
// Id is the uuid associated with each request
ID string `json:"id" structs:"id" mapstructure:"id"`
ID string `json:"id" structs:"id" mapstructure:"id" sentinel:""`
// If set, the name given to the replication secondary where this request
// originated
ReplicationCluster string `json:"replication_cluster" structs:"replication_cluster" mapstructure:"replication_cluster"`
ReplicationCluster string `json:"replication_cluster" structs:"replication_cluster" mapstructure:"replication_cluster" sentinel:""`
// Operation is the requested operation type
Operation Operation `json:"operation" structs:"operation" mapstructure:"operation"`
@ -36,26 +55,26 @@ type Request struct {
// routing. As an example, if the original request path is "prod/aws/foo"
// and the AWS logical backend is mounted at "prod/aws/", then the
// final path is "foo" since the mount prefix is trimmed.
Path string `json:"path" structs:"path" mapstructure:"path"`
Path string `json:"path" structs:"path" mapstructure:"path" sentinel:""`
// Request data is an opaque map that must have string keys.
Data map[string]interface{} `json:"map" structs:"data" mapstructure:"data"`
// Storage can be used to durably store and retrieve state.
Storage Storage `json:"-"`
Storage Storage `json:"-" sentinel:""`
// Secret will be non-nil only for Revoke and Renew operations
// to represent the secret that was returned prior.
Secret *Secret `json:"secret" structs:"secret" mapstructure:"secret"`
Secret *Secret `json:"secret" structs:"secret" mapstructure:"secret" sentinel:""`
// Auth will be non-nil only for Renew operations
// to represent the auth that was returned prior.
Auth *Auth `json:"auth" structs:"auth" mapstructure:"auth"`
Auth *Auth `json:"auth" structs:"auth" mapstructure:"auth" sentinel:""`
// Headers will contain the http headers from the request. This value will
// be used in the audit broker to ensure we are auditing only the allowed
// headers.
Headers map[string][]string `json:"headers" structs:"headers" mapstructure:"headers"`
Headers map[string][]string `json:"headers" structs:"headers" mapstructure:"headers" sentinel:""`
// Connection will be non-nil only for credential providers to
// inspect the connection information and potentially use it for
@ -66,45 +85,58 @@ type Request struct {
// can be verified and ACLs applied. This value is passed
// through to the logical backends but after being salted and
// hashed.
ClientToken string `json:"client_token" structs:"client_token" mapstructure:"client_token"`
ClientToken string `json:"client_token" structs:"client_token" mapstructure:"client_token" sentinel:""`
// ClientTokenAccessor is provided to the core so that the it can get
// logged as part of request audit logging.
ClientTokenAccessor string `json:"client_token_accessor" structs:"client_token_accessor" mapstructure:"client_token_accessor"`
ClientTokenAccessor string `json:"client_token_accessor" structs:"client_token_accessor" mapstructure:"client_token_accessor" sentinel:""`
// DisplayName is provided to the logical backend to help associate
// dynamic secrets with the source entity. This is not a sensitive
// name, but is useful for operators.
DisplayName string `json:"display_name" structs:"display_name" mapstructure:"display_name"`
DisplayName string `json:"display_name" structs:"display_name" mapstructure:"display_name" sentinel:""`
// MountPoint is provided so that a logical backend can generate
// paths relative to itself. The `Path` is effectively the client
// request path with the MountPoint trimmed off.
MountPoint string `json:"mount_point" structs:"mount_point" mapstructure:"mount_point"`
MountPoint string `json:"mount_point" structs:"mount_point" mapstructure:"mount_point" sentinel:""`
// MountType is provided so that a logical backend can make decisions
// based on the specific mount type (e.g., if a mount type has different
// aliases, generating different defaults depending on the alias)
MountType string `json:"mount_type" structs:"mount_type" mapstructure:"mount_type"`
MountType string `json:"mount_type" structs:"mount_type" mapstructure:"mount_type" sentinel:""`
// MountAccessor is provided so that identities returned by the authentication
// backends can be tied to the mount it belongs to.
MountAccessor string `json:"mount_accessor" structs:"mount_accessor" mapstructure:"mount_accessor"`
MountAccessor string `json:"mount_accessor" structs:"mount_accessor" mapstructure:"mount_accessor" sentinel:""`
// WrapInfo contains requested response wrapping parameters
WrapInfo *RequestWrapInfo `json:"wrap_info" structs:"wrap_info" mapstructure:"wrap_info"`
WrapInfo *RequestWrapInfo `json:"wrap_info" structs:"wrap_info" mapstructure:"wrap_info" sentinel:""`
// ClientTokenRemainingUses represents the allowed number of uses left on the
// token supplied
ClientTokenRemainingUses int `json:"client_token_remaining_uses" structs:"client_token_remaining_uses" mapstructure:"client_token_remaining_uses"`
// MFACreds holds the parsed MFA information supplied over the API as part of
// X-Vault-MFA header
MFACreds MFACreds `json:"mfa_creds" structs:"mfa_creds" mapstructure:"mfa_creds" sentinel:""`
// EntityID is the identity of the caller extracted out of the token used
// to make this request
EntityID string `json:"entity_id" structs:"entity_id" mapstructure:"entity_id"`
EntityID string `json:"entity_id" structs:"entity_id" mapstructure:"entity_id" sentinel:""`
// PolicyOverride indicates that the requestor wishes to override
// soft-mandatory Sentinel policies
PolicyOverride bool `json:"policy_override" structs:"policy_override" mapstructure:"policy_override"`
// Whether the request is unauthenticated, as in, had no client token
// attached. Useful in some situations where the client token is not made
// accessible.
Unauthenticated bool `json:"unauthenticated" structs:"unauthenticated" mapstructure:"unauthenticated"`
// For replication, contains the last WAL on the remote side after handling
// the request, used for best-effort avoidance of stale read-after-write
lastRemoteWAL uint64
lastRemoteWAL uint64 `sentinel:""`
}
// Get returns a data field and guards for nil Data
@ -126,6 +158,24 @@ func (r *Request) GoString() string {
return fmt.Sprintf("*%#v", *r)
}
func (r *Request) SentinelGet(key string) (interface{}, error) {
switch key {
case "path":
// Sanitize it here so that it's consistent in policies
return strings.TrimPrefix(r.Path, "/"), nil
case "wrapping", "wrap_info":
// If the pointer is nil accessing the wrap info is considered
// "undefined" so this allows us to instead discover a TTL of zero
if r.WrapInfo == nil {
return &RequestWrapInfo{}, nil
}
return r.WrapInfo, nil
}
return nil, nil
}
func (r *Request) LastRemoteWAL() uint64 {
return r.lastRemoteWAL
}

View File

@ -9,12 +9,12 @@ type Secret struct {
// InternalData is JSON-encodable data that is stored with the secret.
// This will be sent back during a Renew/Revoke for storing internal data
// used for those operations.
InternalData map[string]interface{} `json:"internal_data"`
InternalData map[string]interface{} `json:"internal_data" sentinel:""`
// LeaseID is the ID returned to the user to manage this secret.
// This is generated by Vault core. Any set value will be ignored.
// For requests, this will always be blank.
LeaseID string
LeaseID string `sentinel:""`
}
func (s *Secret) Validate() error {

View File

@ -23,8 +23,9 @@ type Storage interface {
// StorageEntry is the entry for an item in a Storage implementation.
type StorageEntry struct {
Key string
Value []byte
Key string
Value []byte
SealWrap bool
}
// DecodeJSON decodes the 'Value' present in StorageEntry.
@ -94,6 +95,10 @@ func CollectKeys(view ClearableView) ([]string, error) {
// ClearView is used to delete all the keys in a view
func ClearView(view ClearableView) error {
if view == nil {
return nil
}
// Collect all the keys
keys, err := CollectKeys(view)
if err != nil {

View File

@ -8,9 +8,9 @@ import (
)
// This logic was pulled from the http package so that it can be used for
// encoding wrapped responses as well. It simply translates the logical request
// to an http response, with the values we want and omitting the values we
// don't.
// encoding wrapped responses as well. It simply translates the logical
// response to an http response, with the values we want and omitting the
// values we don't.
func LogicalResponseToHTTPResponse(input *Response) *HTTPResponse {
httpResp := &HTTPResponse{
Data: input.Data,

View File

@ -4,10 +4,12 @@ import (
"bufio"
"flag"
"io"
"os"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/token"
"github.com/hashicorp/vault/helper/flag-slice"
"github.com/mitchellh/cli"
)
@ -34,6 +36,9 @@ var (
"s", "m", or "h"; if no suffix is specified it will
be parsed as seconds. May also be specified via
VAULT_WRAP_TTL.
-policy-override Indicates that any soft-mandatory Sentinel policies
be overridden.
`
}
)
@ -48,13 +53,15 @@ type Meta struct {
ForceAddress string // Address to force for API clients
// These are set by the command line flags.
flagAddress string
flagCACert string
flagCAPath string
flagClientCert string
flagClientKey string
flagWrapTTL string
flagInsecure bool
flagAddress string
flagCACert string
flagCAPath string
flagClientCert string
flagClientKey string
flagWrapTTL string
flagInsecure bool
flagMFA []string
flagPolicyOverride bool
// Queried if no token can be found
TokenHelper TokenHelperFunc
@ -105,6 +112,22 @@ func (m *Meta) Client() (*api.Client, error) {
client.SetWrappingLookupFunc(m.DefaultWrappingLookupFunc)
var mfaCreds []string
// Extract the MFA credentials from environment variable first
if os.Getenv(api.EnvVaultMFA) != "" {
mfaCreds = []string{os.Getenv(api.EnvVaultMFA)}
}
// If CLI MFA flags were supplied, prefer that over environment variable
if len(m.flagMFA) != 0 {
mfaCreds = m.flagMFA
}
client.SetMFACreds(mfaCreds)
client.SetPolicyOverride(m.flagPolicyOverride)
// If we have a token directly, then set that
token := m.ClientToken
@ -154,6 +177,8 @@ func (m *Meta) FlagSet(n string, fs FlagSetFlags) *flag.FlagSet {
f.StringVar(&m.flagWrapTTL, "wrap-ttl", "", "")
f.BoolVar(&m.flagInsecure, "insecure", false, "")
f.BoolVar(&m.flagInsecure, "tls-skip-verify", false, "")
f.BoolVar(&m.flagPolicyOverride, "policy-override", false, "")
f.Var((*sliceflag.StringFlag)(&m.flagMFA), "mfa", "")
}
// Create an io.Writer that writes to our Ui properly for errors.

View File

@ -18,7 +18,7 @@ func TestFlagSet(t *testing.T) {
},
{
FlagSetServer,
[]string{"address", "ca-cert", "ca-path", "client-cert", "client-key", "insecure", "tls-skip-verify", "wrap-ttl"},
[]string{"address", "ca-cert", "ca-path", "client-cert", "client-key", "insecure", "mfa", "policy-override", "tls-skip-verify", "wrap-ttl"},
},
}

View File

@ -136,7 +136,7 @@ func (c *Cache) List(prefix string) ([]string, error) {
return c.backend.List(prefix)
}
func (c *TransactionalCache) Transaction(txns []TxnEntry) error {
func (c *TransactionalCache) Transaction(txns []*TxnEntry) error {
// Lock the world
for _, lock := range c.locks {
lock.Lock()

View File

@ -196,7 +196,7 @@ func (c *CockroachDBBackend) List(prefix string) ([]string, error) {
}
// Transaction is used to run multiple entries via a transaction
func (c *CockroachDBBackend) Transaction(txns []physical.TxnEntry) error {
func (c *CockroachDBBackend) Transaction(txns []*physical.TxnEntry) error {
defer metrics.MeasureSince([]string{"cockroachdb", "transaction"}, time.Now())
if len(txns) == 0 {
return nil
@ -210,7 +210,7 @@ func (c *CockroachDBBackend) Transaction(txns []physical.TxnEntry) error {
})
}
func (c *CockroachDBBackend) transaction(tx *sql.Tx, txns []physical.TxnEntry) error {
func (c *CockroachDBBackend) transaction(tx *sql.Tx, txns []*physical.TxnEntry) error {
deleteStmt, err := tx.Prepare(c.rawStatements["delete"])
if err != nil {
return err

View File

@ -303,7 +303,7 @@ func setupTLSConfig(conf map[string]string) (*tls.Config, error) {
}
// Used to run multiple entries via a transaction
func (c *ConsulBackend) Transaction(txns []physical.TxnEntry) error {
func (c *ConsulBackend) Transaction(txns []*physical.TxnEntry) error {
if len(txns) == 0 {
return nil
}
@ -334,7 +334,7 @@ func (c *ConsulBackend) Transaction(txns []physical.TxnEntry) error {
if err != nil {
return err
}
if ok {
if ok && len(resp.Errors) == 0 {
return nil
}

View File

@ -273,7 +273,7 @@ func (b *FileBackend) validatePath(path string) error {
return nil
}
func (b *TransactionalFileBackend) Transaction(txns []physical.TxnEntry) error {
func (b *TransactionalFileBackend) Transaction(txns []*physical.TxnEntry) error {
b.permitPool.Acquire()
defer b.permitPool.Release()

View File

@ -132,7 +132,7 @@ func (i *InmemBackend) ListInternal(prefix string) ([]string, error) {
}
// Implements the transaction interface
func (t *TransactionalInmemBackend) Transaction(txns []physical.TxnEntry) error {
func (t *TransactionalInmemBackend) Transaction(txns []*physical.TxnEntry) error {
t.permitPool.Acquire()
defer t.permitPool.Release()

View File

@ -54,7 +54,7 @@ func (f *faultyPseudo) List(prefix string) ([]string, error) {
return f.underlying.List(prefix)
}
func (f *faultyPseudo) Transaction(txns []physical.TxnEntry) error {
func (f *faultyPseudo) Transaction(txns []*physical.TxnEntry) error {
f.underlying.permitPool.Acquire()
defer f.underlying.permitPool.Release()

View File

@ -84,7 +84,7 @@ func (l *LatencyInjector) List(prefix string) ([]string, error) {
}
// Transaction is a latent transaction request
func (l *TransactionalLatencyInjector) Transaction(txns []TxnEntry) error {
func (l *TransactionalLatencyInjector) Transaction(txns []*TxnEntry) error {
l.addLatency()
return l.Transactional.Transaction(txns)
}

View File

@ -110,6 +110,7 @@ type Lock interface {
type Entry struct {
Key string
Value []byte
SealWrap bool `json:"seal_wrap,omitempty"`
}
// Factory is the factory function to create a physical backend.

View File

@ -0,0 +1,36 @@
package physical
// PhysicalAccess is a wrapper around physical.Backend that allows Core to
// expose its physical storage operations through PhysicalAccess() while
// restricting the ability to modify Core.physical itself.
type PhysicalAccess struct {
physical Backend
}
var _ Backend = (*PhysicalAccess)(nil)
func NewPhysicalAccess(physical Backend) *PhysicalAccess {
return &PhysicalAccess{physical: physical}
}
func (p *PhysicalAccess) Put(entry *Entry) error {
return p.physical.Put(entry)
}
func (p *PhysicalAccess) Get(key string) (*Entry, error) {
return p.physical.Get(key)
}
func (p *PhysicalAccess) Delete(key string) error {
return p.physical.Delete(key)
}
func (p *PhysicalAccess) List(prefix string) ([]string, error) {
return p.physical.List(prefix)
}
func (p *PhysicalAccess) Purge() {
if purgeable, ok := p.physical.(Purgable); ok {
purgeable.Purge()
}
}

View File

@ -8,6 +8,7 @@ import (
)
func ExerciseBackend(t *testing.T, b Backend) {
t.Helper()
// Should be empty
keys, err := b.List("")
if err != nil {
@ -196,6 +197,7 @@ func ExerciseBackend(t *testing.T, b Backend) {
}
func ExerciseBackend_ListPrefix(t *testing.T, b Backend) {
t.Helper()
e1 := &Entry{Key: "foo", Value: []byte("test")}
e2 := &Entry{Key: "foo/bar", Value: []byte("test")}
e3 := &Entry{Key: "foo/bar/baz", Value: []byte("test")}
@ -266,6 +268,7 @@ func ExerciseBackend_ListPrefix(t *testing.T, b Backend) {
}
func ExerciseHABackend(t *testing.T, b HABackend, b2 HABackend) {
t.Helper()
// Get the lock
lock, err := b.LockWith("foo", "bar")
if err != nil {
@ -342,6 +345,7 @@ func ExerciseHABackend(t *testing.T, b HABackend, b2 HABackend) {
}
func ExerciseTransactionalBackend(t *testing.T, b Backend) {
t.Helper()
tb, ok := b.(Transactional)
if !ok {
t.Fatal("Not a transactional backend")
@ -395,7 +399,8 @@ func ExerciseTransactionalBackend(t *testing.T, b Backend) {
}
}
func SetupTestingTransactions(t *testing.T, b Backend) []TxnEntry {
func SetupTestingTransactions(t *testing.T, b Backend) []*TxnEntry {
t.Helper()
// Add a few keys so that we test rollback with deletion
if err := b.Put(&Entry{
Key: "foo",
@ -420,34 +425,34 @@ func SetupTestingTransactions(t *testing.T, b Backend) []TxnEntry {
t.Fatal(err)
}
txns := []TxnEntry{
TxnEntry{
txns := []*TxnEntry{
&TxnEntry{
Operation: PutOperation,
Entry: &Entry{
Key: "foo",
Value: []byte("bar2"),
},
},
TxnEntry{
&TxnEntry{
Operation: DeleteOperation,
Entry: &Entry{
Key: "deleteme",
},
},
TxnEntry{
&TxnEntry{
Operation: PutOperation,
Entry: &Entry{
Key: "foo",
Value: []byte("bar3"),
},
},
TxnEntry{
&TxnEntry{
Operation: DeleteOperation,
Entry: &Entry{
Key: "deleteme2",
},
},
TxnEntry{
&TxnEntry{
Operation: PutOperation,
Entry: &Entry{
Key: "zip",

View File

@ -1,6 +1,8 @@
package physical
import multierror "github.com/hashicorp/go-multierror"
import (
multierror "github.com/hashicorp/go-multierror"
)
// TxnEntry is an operation that takes atomically as part of
// a transactional update. Only supported by Transactional backends.
@ -14,7 +16,7 @@ type TxnEntry struct {
// required for some features such as replication.
type Transactional interface {
// The function to run a transaction
Transaction([]TxnEntry) error
Transaction([]*TxnEntry) error
}
type PseudoTransactional interface {
@ -27,8 +29,8 @@ type PseudoTransactional interface {
}
// Implements the transaction interface
func GenericTransactionHandler(t PseudoTransactional, txns []TxnEntry) (retErr error) {
rollbackStack := make([]TxnEntry, 0, len(txns))
func GenericTransactionHandler(t PseudoTransactional, txns []*TxnEntry) (retErr error) {
rollbackStack := make([]*TxnEntry, 0, len(txns))
var dirty bool
// We walk the transactions in order; each successful operation goes into a
@ -47,11 +49,12 @@ TxnWalk:
// Nothing to delete or roll back
continue
}
rollbackEntry := TxnEntry{
rollbackEntry := &TxnEntry{
Operation: PutOperation,
Entry: &Entry{
Key: entry.Key,
Value: entry.Value,
Key: entry.Key,
Value: entry.Value,
SealWrap: entry.SealWrap,
},
}
err = t.DeleteInternal(txn.Entry.Key)
@ -60,7 +63,7 @@ TxnWalk:
dirty = true
break TxnWalk
}
rollbackStack = append([]TxnEntry{rollbackEntry}, rollbackStack...)
rollbackStack = append([]*TxnEntry{rollbackEntry}, rollbackStack...)
case PutOperation:
entry, err := t.GetInternal(txn.Entry.Key)
@ -70,30 +73,32 @@ TxnWalk:
break TxnWalk
}
// Nothing existed so in fact rolling back requires a delete
var rollbackEntry TxnEntry
var rollbackEntry *TxnEntry
if entry == nil {
rollbackEntry = TxnEntry{
rollbackEntry = &TxnEntry{
Operation: DeleteOperation,
Entry: &Entry{
Key: txn.Entry.Key,
},
}
} else {
rollbackEntry = TxnEntry{
rollbackEntry = &TxnEntry{
Operation: PutOperation,
Entry: &Entry{
Key: entry.Key,
Value: entry.Value,
Key: entry.Key,
Value: entry.Value,
SealWrap: entry.SealWrap,
},
}
}
err = t.PutInternal(txn.Entry)
if err != nil {
retErr = multierror.Append(retErr, err)
dirty = true
break TxnWalk
}
rollbackStack = append([]TxnEntry{rollbackEntry}, rollbackStack...)
rollbackStack = append([]*TxnEntry{rollbackEntry}, rollbackStack...)
}
}

View File

@ -23,6 +23,25 @@ type ACL struct {
root bool
}
type PolicyCheckOpts struct {
RootPrivsRequired bool
Unauth bool
}
type AuthResults struct {
ACLResults *ACLResults
Allowed bool
RootPrivs bool
Error *multierror.Error
}
type ACLResults struct {
Allowed bool
RootPrivs bool
IsRoot bool
MFAMethods []string
}
// New is used to construct a policy based ACL from a set of policies.
func NewACL(policies []*Policy) (*ACL, error) {
// Initialize
@ -38,6 +57,13 @@ func NewACL(policies []*Policy) (*ACL, error) {
if policy == nil {
continue
}
switch policy.Type {
case PolicyTypeACL:
default:
return nil, fmt.Errorf("unable to parse policy (wrong type)")
}
// Check if this is root
if policy.Name == "root" {
a.root = true
@ -61,7 +87,7 @@ func NewACL(policies []*Policy) (*ACL, error) {
}
// these are the ones already in the tree
existingPerms := raw.(*Permissions)
existingPerms := raw.(*ACLPermissions)
switch {
case existingPerms.CapabilitiesBitmap&DenyCapabilityInt > 0:
@ -142,7 +168,6 @@ func NewACL(policies []*Policy) (*ACL, error) {
INSERT:
tree.Insert(pc.Prefix, existingPerms)
}
}
return a, nil
@ -159,7 +184,7 @@ func (a *ACL) Capabilities(path string) (pathCapabilities []string) {
raw, ok := a.exactRules.Get(path)
if ok {
perm := raw.(*Permissions)
perm := raw.(*ACLPermissions)
capabilities = perm.CapabilitiesBitmap
goto CHECK
}
@ -169,7 +194,7 @@ func (a *ACL) Capabilities(path string) (pathCapabilities []string) {
if !ok {
return []string{DenyCapability}
} else {
perm := raw.(*Permissions)
perm := raw.(*ACLPermissions)
capabilities = perm.CapabilitiesBitmap
}
@ -201,29 +226,33 @@ CHECK:
return
}
// AllowOperation is used to check if the given operation is permitted. The
// first bool indicates if an op is allowed, the second whether sudo priviliges
// exist for that op and path.
func (a *ACL) AllowOperation(req *logical.Request) (bool, bool) {
// AllowOperation is used to check if the given operation is permitted.
func (a *ACL) AllowOperation(req *logical.Request) (ret *ACLResults) {
ret = new(ACLResults)
// Fast-path root
if a.root {
return true, true
ret.Allowed = true
ret.RootPrivs = true
ret.IsRoot = true
return
}
op := req.Operation
path := req.Path
// Help is always allowed
if op == logical.HelpOperation {
return true, false
ret.Allowed = true
return
}
var permissions *Permissions
var permissions *ACLPermissions
// Find an exact matching rule, look for glob if no match
var capabilities uint32
raw, ok := a.exactRules.Get(path)
if ok {
permissions = raw.(*Permissions)
permissions = raw.(*ACLPermissions)
capabilities = permissions.CapabilitiesBitmap
goto CHECK
}
@ -231,9 +260,9 @@ func (a *ACL) AllowOperation(req *logical.Request) (bool, bool) {
// Find a glob rule, default deny if no match
_, raw, ok = a.globRules.LongestPrefix(path)
if !ok {
return false, false
return
} else {
permissions = raw.(*Permissions)
permissions = raw.(*ACLPermissions)
capabilities = permissions.CapabilitiesBitmap
}
@ -241,7 +270,8 @@ CHECK:
// Check if the minimum permissions are met
// If "deny" has been explicitly set, only deny will be in the map, so we
// only need to check for the existence of other values
sudo := capabilities&SudoCapabilityInt > 0
ret.RootPrivs = capabilities&SudoCapabilityInt > 0
operationAllowed := false
switch op {
case logical.ReadOperation:
@ -261,21 +291,21 @@ CHECK:
operationAllowed = capabilities&UpdateCapabilityInt > 0
default:
return false, false
return
}
if !operationAllowed {
return false, sudo
return
}
if permissions.MaxWrappingTTL > 0 {
if req.WrapInfo == nil || req.WrapInfo.TTL > permissions.MaxWrappingTTL {
return false, sudo
return
}
}
if permissions.MinWrappingTTL > 0 {
if req.WrapInfo == nil || req.WrapInfo.TTL < permissions.MinWrappingTTL {
return false, sudo
return
}
}
// This situation can happen because of merging, even though in a single
@ -283,7 +313,7 @@ CHECK:
if permissions.MinWrappingTTL != 0 &&
permissions.MaxWrappingTTL != 0 &&
permissions.MaxWrappingTTL < permissions.MinWrappingTTL {
return false, sudo
return
}
// Only check parameter permissions for operations that can modify
@ -291,7 +321,8 @@ CHECK:
if op == logical.UpdateOperation || op == logical.CreateOperation {
// If there are no data fields, allow
if len(req.Data) == 0 {
return true, sudo
ret.Allowed = true
return
}
if len(permissions.DeniedParameters) == 0 {
@ -300,7 +331,7 @@ CHECK:
// Check if all parameters have been denied
if _, ok := permissions.DeniedParameters["*"]; ok {
return false, sudo
return
}
for parameter, value := range req.Data {
@ -308,7 +339,7 @@ CHECK:
if valueSlice, ok := permissions.DeniedParameters[strings.ToLower(parameter)]; ok {
// If the value exists in denied values slice, deny
if valueInParameterList(value, valueSlice) {
return false, sudo
return
}
}
}
@ -316,30 +347,59 @@ CHECK:
ALLOWED_PARAMETERS:
// If we don't have any allowed parameters set, allow
if len(permissions.AllowedParameters) == 0 {
return true, sudo
ret.Allowed = true
return
}
_, allowedAll := permissions.AllowedParameters["*"]
if len(permissions.AllowedParameters) == 1 && allowedAll {
return true, sudo
ret.Allowed = true
return
}
for parameter, value := range req.Data {
valueSlice, ok := permissions.AllowedParameters[strings.ToLower(parameter)]
// Requested parameter is not in allowed list
if !ok && !allowedAll {
return false, sudo
return
}
// If the value doesn't exists in the allowed values slice,
// deny
if ok && !valueInParameterList(value, valueSlice) {
return false, sudo
return
}
}
}
return true, sudo
ret.Allowed = true
return
}
func (c *Core) performPolicyChecks(acl *ACL, te *TokenEntry, req *logical.Request, inEntity *identity.Entity, opts *PolicyCheckOpts) (ret *AuthResults) {
ret = new(AuthResults)
// First, perform normal ACL checks if requested. The only time no ACL
// should be applied is if we are only processing EGPs against a login
// path in which case opts.Unauth will be set.
if acl != nil && !opts.Unauth {
ret.ACLResults = acl.AllowOperation(req)
ret.RootPrivs = ret.ACLResults.RootPrivs
// Root is always allowed; skip Sentinel/MFA checks
if ret.ACLResults.IsRoot {
//c.logger.Warn("policy: token is root, skipping checks")
ret.Allowed = true
return
}
if !ret.ACLResults.Allowed {
return
}
if !ret.RootPrivs && opts.RootPrivsRequired {
return
}
}
ret.Allowed = true
return
}
func valueInParameterList(v interface{}, list []interface{}) bool {

View File

@ -23,7 +23,7 @@ func TestACL_Capabilities(t *testing.T) {
t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected)
}
policies, err := Parse(aclPolicy)
policies, err := ParseACLPolicy(aclPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -64,17 +64,17 @@ func TestACL_Root(t *testing.T) {
request := new(logical.Request)
request.Operation = logical.UpdateOperation
request.Path = "sys/mount/foo"
allowed, rootPrivs := acl.AllowOperation(request)
if !rootPrivs {
authResults := acl.AllowOperation(request)
if !authResults.RootPrivs {
t.Fatalf("expected root")
}
if !allowed {
if !authResults.Allowed {
t.Fatalf("expected permissions")
}
}
func TestACL_Single(t *testing.T) {
policy, err := Parse(aclPolicy)
policy, err := ParseACLPolicy(aclPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -89,8 +89,8 @@ func TestACL_Single(t *testing.T) {
request := new(logical.Request)
request.Operation = logical.ReadOperation
request.Path = "sys/mount/foo"
_, rootPrivs := acl.AllowOperation(request)
if rootPrivs {
authResults := acl.AllowOperation(request)
if authResults.RootPrivs {
t.Fatalf("unexpected root")
}
@ -128,23 +128,23 @@ func TestACL_Single(t *testing.T) {
request := new(logical.Request)
request.Operation = tc.op
request.Path = tc.path
allowed, rootPrivs := acl.AllowOperation(request)
if allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
authResults := acl.AllowOperation(request)
if authResults.Allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
}
if rootPrivs != tc.rootPrivs {
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
if authResults.RootPrivs != tc.rootPrivs {
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
}
}
}
func TestACL_Layered(t *testing.T) {
policy1, err := Parse(aclPolicy)
policy1, err := ParseACLPolicy(aclPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}
policy2, err := Parse(aclPolicy2)
policy2, err := ParseACLPolicy(aclPolicy2)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -162,8 +162,8 @@ func testLayeredACL(t *testing.T, acl *ACL) {
request := new(logical.Request)
request.Operation = logical.ReadOperation
request.Path = "sys/mount/foo"
_, rootPrivs := acl.AllowOperation(request)
if rootPrivs {
authResults := acl.AllowOperation(request)
if authResults.RootPrivs {
t.Fatalf("unexpected root")
}
@ -206,18 +206,18 @@ func testLayeredACL(t *testing.T, acl *ACL) {
request := new(logical.Request)
request.Operation = tc.op
request.Path = tc.path
allowed, rootPrivs := acl.AllowOperation(request)
if allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
authResults := acl.AllowOperation(request)
if authResults.Allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
}
if rootPrivs != tc.rootPrivs {
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
if authResults.RootPrivs != tc.rootPrivs {
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
}
}
}
func TestACL_PolicyMerge(t *testing.T) {
policy, err := Parse(mergingPolicies)
policy, err := ParseACLPolicy(mergingPolicies)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -256,7 +256,7 @@ func TestACL_PolicyMerge(t *testing.T) {
t.Fatalf("Could not find acl entry for path %s", tc.path)
}
p := raw.(*Permissions)
p := raw.(*ACLPermissions)
if !reflect.DeepEqual(tc.allowed, p.AllowedParameters) {
t.Fatalf("Allowed paramaters did not match, Expected: %#v, Got: %#v", tc.allowed, p.AllowedParameters)
}
@ -273,7 +273,7 @@ func TestACL_PolicyMerge(t *testing.T) {
}
func TestACL_AllowOperation(t *testing.T) {
policy, err := Parse(permissionsPolicy)
policy, err := ParseACLPolicy(permissionsPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -333,16 +333,16 @@ func TestACL_AllowOperation(t *testing.T) {
}
for _, op := range toperations {
request.Operation = op
allowed, _ := acl.AllowOperation(&request)
if allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v", tc, allowed)
authResults := acl.AllowOperation(&request)
if authResults.Allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v", tc, authResults.Allowed)
}
}
}
}
func TestACL_ValuePermissions(t *testing.T) {
policy, err := Parse(valuePermissionsPolicy)
policy, err := ParseACLPolicy(valuePermissionsPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -408,9 +408,9 @@ func TestACL_ValuePermissions(t *testing.T) {
}
for _, op := range toperations {
request.Operation = op
allowed, _ := acl.AllowOperation(&request)
if allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v", tc, allowed)
authResults := acl.AllowOperation(&request)
if authResults.Allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v", tc, authResults.Allowed)
}
}
}
@ -418,7 +418,7 @@ func TestACL_ValuePermissions(t *testing.T) {
// NOTE: this test doesn't catch any races ATM
func TestACL_CreationRace(t *testing.T) {
policy, err := Parse(valuePermissionsPolicy)
policy, err := ParseACLPolicy(valuePermissionsPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}

View File

@ -95,6 +95,8 @@ func (c *Core) enableCredential(entry *MountEntry) error {
}
viewPath := credentialBarrierPrefix + entry.UUID + "/"
view := NewBarrierView(c.barrier, viewPath)
var err error
var backend logical.Backend
sysView := c.mountEntrySysView(entry)
conf := make(map[string]string)
if entry.Config.PluginName != "" {
@ -102,7 +104,7 @@ func (c *Core) enableCredential(entry *MountEntry) error {
}
// Create the new backend
backend, err := c.newCredentialBackend(entry.Type, sysView, view, conf)
backend, err = c.newCredentialBackend(entry.Type, sysView, view, conf)
if err != nil {
return err
}
@ -155,7 +157,7 @@ func (c *Core) disableCredential(path string) error {
// Store the view for this backend
fullPath := credentialRoutePrefix + path
view := c.router.MatchingStorageView(fullPath)
view := c.router.MatchingStorageByAPIPath(fullPath)
if view == nil {
return fmt.Errorf("no matching backend %s", fullPath)
}
@ -170,14 +172,13 @@ func (c *Core) disableCredential(path string) error {
return err
}
// Revoke credentials from this path
if err := c.expiration.RevokePrefix(fullPath); err != nil {
return err
}
// Call cleanup function if it exists
backend := c.router.MatchingBackend(fullPath)
if backend != nil {
// Revoke credentials from this path
if err := c.expiration.RevokePrefix(fullPath); err != nil {
return err
}
// Call cleanup function if it exists
backend.Cleanup()
}
@ -186,11 +187,14 @@ func (c *Core) disableCredential(path string) error {
return err
}
// Clear the data in the view
if view != nil {
switch {
case entry.Local, !c.replicationState.HasState(consts.ReplicationPerformanceSecondary):
// Have writable storage, remove the whole thing
if err := logical.ClearView(view); err != nil {
c.logger.Error("core: failed to clear view for path being unmounted", "error", err, "path", path)
return err
}
}
// Remove the mount table entry
@ -226,6 +230,27 @@ func (c *Core) removeCredEntry(path string) error {
return nil
}
// remountCredEntryForce takes a copy of the mount entry for the path and fully
// unmounts and remounts the backend to pick up any changes, such as filtered
// paths
func (c *Core) remountCredEntryForce(path string) error {
fullPath := credentialRoutePrefix + path
me := c.router.MatchingMountEntry(fullPath)
if me == nil {
return fmt.Errorf("cannot find mount for path '%s'", path)
}
me, err := me.Clone()
if err != nil {
return err
}
if err := c.disableCredential(path); err != nil {
return err
}
return c.enableCredential(me)
}
// taintCredEntry is used to mark an entry in the auth table as tainted
func (c *Core) taintCredEntry(path string) error {
c.authLock.Lock()
@ -398,9 +423,9 @@ func (c *Core) persistAuth(table *MountTable, localOnly bool) error {
// setupCredentials is invoked after we've loaded the auth table to
// initialize the credential backends and setup the router
func (c *Core) setupCredentials() error {
var view *BarrierView
var err error
var persistNeeded bool
var view *BarrierView
c.authLock.Lock()
defer c.authLock.Unlock()
@ -416,13 +441,13 @@ func (c *Core) setupCredentials() error {
// Create a barrier view using the UUID
viewPath := credentialBarrierPrefix + entry.UUID + "/"
view = NewBarrierView(c.barrier, viewPath)
// Initialize the backend
sysView := c.mountEntrySysView(entry)
conf := make(map[string]string)
if entry.Config.PluginName != "" {
conf["plugin_name"] = entry.Config.PluginName
}
// Initialize the backend
backend, err = c.newCredentialBackend(entry.Type, sysView, view, conf)
if err != nil {
c.logger.Error("core: failed to create credential entry", "path", entry.Path, "error", err)
@ -439,8 +464,9 @@ func (c *Core) setupCredentials() error {
}
// Check for the correct backend type
if entry.Type == "plugin" && backend.Type() != logical.TypeCredential {
return fmt.Errorf("cannot mount '%s' of type '%s' as an auth backend", entry.Config.PluginName, backend.Type())
backendType := backend.Type()
if entry.Type == "plugin" && backendType != logical.TypeCredential {
return fmt.Errorf("cannot mount '%s' of type '%s' as an auth backend", entry.Config.PluginName, backendType)
}
if err := backend.Initialize(); err != nil {

View File

@ -294,7 +294,7 @@ func TestCore_DisableCredential_Cleanup(t *testing.T) {
}
// Store the view
view := c.router.MatchingStorageView("auth/foo/")
view := c.router.MatchingStorageByAPIPath("auth/foo/")
// Inject data
se := &logical.StorageEntry{

View File

@ -160,15 +160,17 @@ type BarrierEncryptor interface {
// Entry is used to represent data stored by the security barrier
type Entry struct {
Key string
Value []byte
Key string
Value []byte
SealWrap bool
}
// Logical turns the Entry into a logical storage entry.
func (e *Entry) Logical() *logical.StorageEntry {
return &logical.StorageEntry{
Key: e.Key,
Value: e.Value,
Key: e.Key,
Value: e.Value,
SealWrap: e.SealWrap,
}
}

22
vault/barrier_access.go Normal file
View File

@ -0,0 +1,22 @@
package vault
// BarrierEncryptorAccess is a wrapper around BarrierEncryptor that allows Core
// to expose its barrier encrypt/decrypt operations through BarrierEncryptorAccess()
// while restricting the ability to modify Core.barrier itself.
type BarrierEncryptorAccess struct {
barrierEncryptor BarrierEncryptor
}
var _ BarrierEncryptor = (*BarrierEncryptorAccess)(nil)
func NewBarrierEncryptorAccess(barrierEncryptor BarrierEncryptor) *BarrierEncryptorAccess {
return &BarrierEncryptorAccess{barrierEncryptor: barrierEncryptor}
}
func (b *BarrierEncryptorAccess) Encrypt(key string, plaintext []byte) ([]byte, error) {
return b.barrierEncryptor.Encrypt(key, plaintext)
}
func (b *BarrierEncryptorAccess) Decrypt(key string, ciphertext []byte) ([]byte, error) {
return b.barrierEncryptor.Decrypt(key, ciphertext)
}

View File

@ -490,8 +490,9 @@ func (b *AESGCMBarrier) CreateUpgrade(term uint32) error {
value := b.encrypt(key, prevTerm, primary, buf)
// Create upgrade key
pe := &physical.Entry{
Key: key,
Value: value,
Key: key,
Value: value,
SealWrap: true,
}
return b.backend.Put(pe)
}
@ -642,8 +643,9 @@ func (b *AESGCMBarrier) Put(entry *Entry) error {
}
pe := &physical.Entry{
Key: entry.Key,
Value: b.encrypt(entry.Key, term, primary, entry.Value),
Key: entry.Key,
Value: b.encrypt(entry.Key, term, primary, entry.Value),
SealWrap: entry.SealWrap,
}
return b.backend.Put(pe)
}
@ -673,8 +675,9 @@ func (b *AESGCMBarrier) Get(key string) (*Entry, error) {
// Wrap in a logical entry
entry := &Entry{
Key: key,
Value: plain,
Key: key,
Value: plain,
SealWrap: pe.SealWrap,
}
return entry, nil
}

View File

@ -66,8 +66,9 @@ func (v *BarrierView) Get(key string) (*logical.StorageEntry, error) {
}
return &logical.StorageEntry{
Key: entry.Key,
Value: entry.Value,
Key: entry.Key,
Value: entry.Value,
SealWrap: entry.SealWrap,
}, nil
}
@ -84,8 +85,9 @@ func (v *BarrierView) Put(entry *logical.StorageEntry) error {
}
nested := &Entry{
Key: expandedKey,
Value: entry.Value,
Key: expandedKey,
Value: entry.Value,
SealWrap: entry.SealWrap,
}
return v.barrier.Put(nested)
}

View File

@ -30,7 +30,7 @@ func (c *Core) Capabilities(token, path string) ([]string, error) {
var policies []*Policy
for _, tePolicy := range te.Policies {
policy, err := c.policyStore.GetPolicy(tePolicy)
policy, err := c.policyStore.GetPolicy(tePolicy, PolicyTypeToken)
if err != nil {
return nil, err
}

View File

@ -18,7 +18,7 @@ func TestCapabilities(t *testing.T) {
}
// Create a policy
policy, _ := Parse(aclPolicy)
policy, _ := ParseACLPolicy(aclPolicy)
err = c.policyStore.SetPolicy(policy)
if err != nil {
t.Fatalf("err: %v", err)