disallow token use if entity is invalid (#4791)
This commit is contained in:
parent
961d24d89a
commit
0d8f424ab4
|
@ -44,6 +44,11 @@ func (c *Core) Capabilities(ctx context.Context, token, path string) ([]string,
|
|||
}
|
||||
|
||||
if entity != nil && entity.Disabled {
|
||||
c.logger.Warn("permission denied as the entity on the token is disabled")
|
||||
return nil, logical.ErrPermissionDenied
|
||||
}
|
||||
if te != nil && te.EntityID != "" && entity == nil {
|
||||
c.logger.Warn("permission denied as the entity on the token is invalid")
|
||||
return nil, logical.ErrPermissionDenied
|
||||
}
|
||||
|
||||
|
|
|
@ -1003,7 +1003,6 @@ func (c *Core) sealInitCommon(ctx context.Context, req *logical.Request) (retErr
|
|||
return retErr
|
||||
}
|
||||
|
||||
// Validate the token is a root token
|
||||
acl, te, entity, identityPolicies, err := c.fetchACLTokenEntryAndEntity(req)
|
||||
if err != nil {
|
||||
retErr = multierror.Append(retErr, err)
|
||||
|
@ -1037,6 +1036,13 @@ func (c *Core) sealInitCommon(ctx context.Context, req *logical.Request) (retErr
|
|||
}
|
||||
|
||||
if entity != nil && entity.Disabled {
|
||||
c.logger.Warn("permission denied as the entity on the token is disabled")
|
||||
retErr = multierror.Append(retErr, logical.ErrPermissionDenied)
|
||||
c.stateLock.RUnlock()
|
||||
return retErr
|
||||
}
|
||||
if te != nil && te.EntityID != "" && entity == nil {
|
||||
c.logger.Warn("permission denied as the entity on the token is invalid")
|
||||
retErr = multierror.Append(retErr, logical.ErrPermissionDenied)
|
||||
c.stateLock.RUnlock()
|
||||
return retErr
|
||||
|
|
|
@ -192,6 +192,14 @@ func (c *Core) StepDown(req *logical.Request) (retErr error) {
|
|||
}
|
||||
|
||||
if entity != nil && entity.Disabled {
|
||||
c.logger.Warn("permission denied as the entity on the token is disabled")
|
||||
retErr = multierror.Append(retErr, logical.ErrPermissionDenied)
|
||||
c.stateLock.RUnlock()
|
||||
return retErr
|
||||
}
|
||||
|
||||
if te != nil && te.EntityID != "" && entity == nil {
|
||||
c.logger.Warn("permission denied as the entity on the token is invalid")
|
||||
retErr = multierror.Append(retErr, logical.ErrPermissionDenied)
|
||||
c.stateLock.RUnlock()
|
||||
return retErr
|
||||
|
|
|
@ -311,10 +311,10 @@ func testIdentityStoreWithGithubAuth(t *testing.T) (*IdentityStore, string, *Cor
|
|||
return is, ghA, c
|
||||
}
|
||||
|
||||
// testIdentityStoreWithGithubAuth returns an instance of identity store which
|
||||
// is mounted by default. This function also enables the github auth backend to
|
||||
// assist with testing aliases and entities that require an valid mount
|
||||
// accessor of an auth backend.
|
||||
// testIdentityStoreWithGithubAuthRoot returns an instance of identity store
|
||||
// which is mounted by default. This function also enables the github auth
|
||||
// backend to assist with testing aliases and entities that require an valid
|
||||
// mount accessor of an auth backend.
|
||||
func testIdentityStoreWithGithubAuthRoot(t *testing.T) (*IdentityStore, string, *Core, string) {
|
||||
// Add github credential factory to core config
|
||||
err := AddTestCredentialBackend("github", credGithub.Factory)
|
||||
|
@ -336,13 +336,7 @@ func testIdentityStoreWithGithubAuthRoot(t *testing.T) (*IdentityStore, string,
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Identity store will be mounted by now, just fetch it from router
|
||||
identitystore := c.router.MatchingBackend("identity/")
|
||||
if identitystore == nil {
|
||||
t.Fatalf("failed to fetch identity store from router")
|
||||
}
|
||||
|
||||
return identitystore.(*IdentityStore), meGH.Accessor, c, root
|
||||
return c.identityStore, meGH.Accessor, c, root
|
||||
}
|
||||
|
||||
func TestIdentityStore_MetadataKeyRegex(t *testing.T) {
|
||||
|
|
|
@ -1456,6 +1456,9 @@ func (b *SystemBackend) handleCapabilities(ctx context.Context, req *logical.Req
|
|||
for _, path := range paths {
|
||||
pathCap, err := b.Core.Capabilities(ctx, token, path)
|
||||
if err != nil {
|
||||
if !strings.HasSuffix(req.Path, "capabilities-self") && errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
||||
return nil, &logical.StatusBadRequest{Err: "invalid token"}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
ret.Data[path] = pathCap
|
||||
|
@ -3476,15 +3479,20 @@ func (b *SystemBackend) pathInternalUIMountsRead(ctx context.Context, req *logic
|
|||
isAuthed = true
|
||||
|
||||
var entity *identity.Entity
|
||||
var te *logical.TokenEntry
|
||||
// Load the ACL policies so we can walk the prefix for this mount
|
||||
acl, _, entity, _, err = b.Core.fetchACLTokenEntryAndEntity(req)
|
||||
acl, te, entity, _, err = b.Core.fetchACLTokenEntryAndEntity(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entity != nil && entity.Disabled {
|
||||
b.logger.Warn("permission denied as the entity on the token is disabled")
|
||||
return nil, logical.ErrPermissionDenied
|
||||
}
|
||||
if te != nil && te.EntityID != "" && entity == nil {
|
||||
b.logger.Warn("permission denied as the entity on the token is invalid")
|
||||
return nil, logical.ErrPermissionDenied
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hasAccess := func(me *MountEntry) bool {
|
||||
|
@ -3558,13 +3566,18 @@ func (b *SystemBackend) pathInternalUIMountRead(ctx context.Context, req *logica
|
|||
resp.Data["path"] = me.Path
|
||||
|
||||
// Load the ACL policies so we can walk the prefix for this mount
|
||||
acl, _, entity, _, err := b.Core.fetchACLTokenEntryAndEntity(req)
|
||||
acl, te, entity, _, err := b.Core.fetchACLTokenEntryAndEntity(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entity != nil && entity.Disabled {
|
||||
b.logger.Warn("permission denied as the entity on the token is disabled")
|
||||
return errResp, logical.ErrPermissionDenied
|
||||
}
|
||||
if te != nil && te.EntityID != "" && entity == nil {
|
||||
b.logger.Warn("permission denied as the entity on the token is invalid")
|
||||
return nil, logical.ErrPermissionDenied
|
||||
}
|
||||
|
||||
if !hasMountAccess(acl, me.Path) {
|
||||
return errResp, logical.ErrPermissionDenied
|
||||
|
@ -3579,12 +3592,17 @@ func (b *SystemBackend) pathInternalUIResultantACL(ctx context.Context, req *log
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
acl, _, entity, _, err := b.Core.fetchACLTokenEntryAndEntity(req)
|
||||
acl, te, entity, _, err := b.Core.fetchACLTokenEntryAndEntity(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entity != nil && entity.Disabled {
|
||||
b.logger.Warn("permission denied as the entity on the token is disabled")
|
||||
return logical.ErrorResponse(logical.ErrPermissionDenied.Error()), nil
|
||||
}
|
||||
if te != nil && te.EntityID != "" && entity == nil {
|
||||
b.logger.Warn("permission denied as the entity on the token is invalid")
|
||||
return logical.ErrorResponse(logical.ErrPermissionDenied.Error()), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -170,6 +170,11 @@ func (c *Core) checkToken(ctx context.Context, req *logical.Request, unauth bool
|
|||
}
|
||||
|
||||
if entity != nil && entity.Disabled {
|
||||
c.logger.Warn("permission denied as the entity on the token is disabled")
|
||||
return nil, te, logical.ErrPermissionDenied
|
||||
}
|
||||
if te != nil && te.EntityID != "" && entity == nil {
|
||||
c.logger.Warn("permission denied as the entity on the token is invalid")
|
||||
return nil, te, logical.ErrPermissionDenied
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import (
|
|||
"github.com/hashicorp/vault/physical"
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
|
||||
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
|
||||
physInmem "github.com/hashicorp/vault/physical/inmem"
|
||||
)
|
||||
|
||||
|
@ -84,6 +85,30 @@ oOyBJU/HMVvBfv4g+OVFLVgSwwm6owwsouZ0+D/LasbuHqYyqYqdyPJQYzWA2Y+F
|
|||
`
|
||||
)
|
||||
|
||||
func testCoreWithUserpassAuthRoot(t testing.T) (*Core, string, string) {
|
||||
// Add userpass credential factory to core config
|
||||
err := AddTestCredentialBackend("userpass", credUserpass.Factory)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c, _, root := TestCoreUnsealed(t)
|
||||
|
||||
meGH := &MountEntry{
|
||||
Table: credentialTableType,
|
||||
Path: "userpass/",
|
||||
Type: "userpass",
|
||||
Description: "userpass auth",
|
||||
}
|
||||
|
||||
err = c.enableCredential(context.Background(), meGH)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return c, meGH.Accessor, root
|
||||
}
|
||||
|
||||
// TestCore returns a pure in-memory, uninitialized core for testing.
|
||||
func TestCore(t testing.T) *Core {
|
||||
return TestCoreWithSeal(t, nil, false)
|
||||
|
|
|
@ -35,6 +35,73 @@ type TokenEntryOld struct {
|
|||
Period time.Duration
|
||||
}
|
||||
|
||||
func TestTokenStore_TokenInvalidEntityID(t *testing.T) {
|
||||
c, _, root := testCoreWithUserpassAuthRoot(t)
|
||||
|
||||
// Add a user to the userpass backend
|
||||
resp, err := c.HandleRequest(&logical.Request{
|
||||
Path: "auth/userpass/users/testuser",
|
||||
Operation: logical.UpdateOperation,
|
||||
Data: map[string]interface{}{
|
||||
"password": "testpassword",
|
||||
},
|
||||
ClientToken: root,
|
||||
})
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err: %v\nresp: %#v", err, resp)
|
||||
}
|
||||
|
||||
// Perform a userpass login. This will also create an entity for the logged
|
||||
// in user.
|
||||
resp, err = c.HandleRequest(&logical.Request{
|
||||
Path: "auth/userpass/login/testuser",
|
||||
Operation: logical.UpdateOperation,
|
||||
Data: map[string]interface{}{
|
||||
"password": "testpassword",
|
||||
},
|
||||
Connection: &logical.Connection{
|
||||
RemoteAddr: "127.0.0.1",
|
||||
},
|
||||
})
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err: %v\nresp: %#v", err, resp)
|
||||
}
|
||||
|
||||
token := resp.Auth.ClientToken
|
||||
|
||||
// Make sure that the token is usable by invoking lookup-self
|
||||
resp, err = c.HandleRequest(&logical.Request{
|
||||
Path: "auth/token/lookup-self",
|
||||
Operation: logical.ReadOperation,
|
||||
ClientToken: token,
|
||||
})
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err: %v\nresp: %#v", err, resp)
|
||||
}
|
||||
|
||||
// Delete the entity to which the token belongs to
|
||||
entityID := resp.Data["entity_id"].(string)
|
||||
|
||||
resp, err = c.HandleRequest(&logical.Request{
|
||||
Path: "identity/entity/id/" + entityID,
|
||||
Operation: logical.DeleteOperation,
|
||||
ClientToken: root,
|
||||
})
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err: %v\nresp: %#v", err, resp)
|
||||
}
|
||||
|
||||
// Make sure that the token is usable
|
||||
resp, err = c.HandleRequest(&logical.Request{
|
||||
Path: "auth/token/lookup-self",
|
||||
Operation: logical.ReadOperation,
|
||||
ClientToken: token,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatalf("expected error due to token being invalid when its entity is invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenStore_TokenEntryUpgrade(t *testing.T) {
|
||||
var err error
|
||||
c, _, _ := TestCoreUnsealed(t)
|
||||
|
|
Loading…
Reference in New Issue