2018-07-25 02:02:27 +00:00
|
|
|
package auth
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-01-09 22:56:34 +00:00
|
|
|
"net/http"
|
2018-07-25 02:02:27 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2021-02-23 20:04:21 +00:00
|
|
|
"github.com/hashicorp/go-hclog"
|
2018-07-25 02:02:27 +00:00
|
|
|
"github.com/hashicorp/vault/api"
|
|
|
|
"github.com/hashicorp/vault/builtin/credential/userpass"
|
|
|
|
vaulthttp "github.com/hashicorp/vault/http"
|
2019-04-13 07:44:06 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/logging"
|
2019-04-12 21:54:35 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
2018-07-25 02:02:27 +00:00
|
|
|
"github.com/hashicorp/vault/vault"
|
|
|
|
)
|
|
|
|
|
|
|
|
type userpassTestMethod struct{}
|
|
|
|
|
|
|
|
func newUserpassTestMethod(t *testing.T, client *api.Client) AuthMethod {
|
|
|
|
err := client.Sys().EnableAuthWithOptions("userpass", &api.EnableAuthOptions{
|
|
|
|
Type: "userpass",
|
|
|
|
Config: api.AuthConfigInput{
|
|
|
|
DefaultLeaseTTL: "1s",
|
|
|
|
MaxLeaseTTL: "3s",
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &userpassTestMethod{}
|
|
|
|
}
|
|
|
|
|
2020-01-09 22:56:34 +00:00
|
|
|
func (u *userpassTestMethod) Authenticate(_ context.Context, client *api.Client) (string, http.Header, map[string]interface{}, error) {
|
2018-07-25 02:02:27 +00:00
|
|
|
_, err := client.Logical().Write("auth/userpass/users/foo", map[string]interface{}{
|
|
|
|
"password": "bar",
|
|
|
|
})
|
|
|
|
if err != nil {
|
2020-01-09 22:56:34 +00:00
|
|
|
return "", nil, nil, err
|
2018-07-25 02:02:27 +00:00
|
|
|
}
|
2020-01-09 22:56:34 +00:00
|
|
|
return "auth/userpass/login/foo", nil, map[string]interface{}{
|
2018-07-25 02:02:27 +00:00
|
|
|
"password": "bar",
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *userpassTestMethod) NewCreds() chan struct{} {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *userpassTestMethod) CredSuccess() {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *userpassTestMethod) Shutdown() {
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAuthHandler(t *testing.T) {
|
|
|
|
logger := logging.NewVaultLogger(hclog.Trace)
|
|
|
|
coreConfig := &vault.CoreConfig{
|
|
|
|
Logger: logger,
|
|
|
|
CredentialBackends: map[string]logical.Factory{
|
|
|
|
"userpass": userpass.Factory,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
|
|
|
|
HandlerFunc: vaulthttp.Handler,
|
|
|
|
})
|
|
|
|
cluster.Start()
|
|
|
|
defer cluster.Cleanup()
|
|
|
|
|
|
|
|
vault.TestWaitActive(t, cluster.Cores[0].Core)
|
|
|
|
client := cluster.Cores[0].Client
|
|
|
|
|
|
|
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
|
|
|
|
|
|
|
ah := NewAuthHandler(&AuthHandlerConfig{
|
|
|
|
Logger: logger.Named("auth.handler"),
|
|
|
|
Client: client,
|
|
|
|
})
|
|
|
|
|
|
|
|
am := newUserpassTestMethod(t, client)
|
2020-09-30 01:03:09 +00:00
|
|
|
errCh := make(chan error)
|
|
|
|
go func() {
|
|
|
|
errCh <- ah.Run(ctx, am)
|
|
|
|
}()
|
2018-07-25 02:02:27 +00:00
|
|
|
|
|
|
|
// Consume tokens so we don't block
|
|
|
|
stopTime := time.Now().Add(5 * time.Second)
|
|
|
|
closed := false
|
|
|
|
consumption:
|
|
|
|
for {
|
|
|
|
select {
|
2020-09-30 01:03:09 +00:00
|
|
|
case err := <-errCh:
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
break consumption
|
2018-07-25 02:02:27 +00:00
|
|
|
case <-ah.OutputCh:
|
Vault Agent Template (#7652)
* Vault Agent Template: parse templates (#7540)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* Update command/agent/config/config.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* return the decode error instead of swallowing it
* Update command/agent/config/config_test.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* go mod tidy
* change error checking style
* Add agent template doc
* TemplateServer: render secrets with Consul Template (#7621)
* add template config parsing, but it's wrong b/c it's not using mapstructure
* parsing consul templates in agent config
* add additional test to configuration parsing, to cover basics
* another test fixture, rework simple test into table
* refactor into table test
* rename test
* remove flattenKeys and add other test fixture
* add template package
* WIP: add runner
* fix panic, actually copy templates, etc
* rework how the config.Vault is created and enable reading from the environment
* this was supposed to be a part of the prior commit
* move/add methods to testhelpers for converting some values to pointers
* use new methods in testhelpers
* add an unblock channel to block agent until a template has been rendered
* add note
* unblock if there are no templates
* cleanups
* go mod tidy
* remove dead code
* simple test to starT
* add simple, empty templates test
* Update package doc, error logs, and add missing close() on channel
* update code comment to be clear what I'm referring to
* have template.NewServer return a (<- chan) type, even though it's a normal chan, as a better practice to enforce reading only
* Update command/agent.go
Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>
* update with test
* Add README and doc.go to the command/agent directory (#7503)
* Add README and doc.go to the command/agent directory
* Add link to website
* address feedback for agent.go
* updated with feedback from Calvin
* Rework template.Server to export the unblock channel, and remove it from the NewServer function
* apply feedback from Nick
* fix/restructure rendering test
* Add pointerutil package for converting types to their pointers
* Remove pointer helper methods; use sdk/helper/pointerutil instead
* update newRunnerConfig to use pointerutil and empty strings
* only wait for unblock if template server is initialized
* drain the token channel in this test
* conditionally send on channel
2019-10-18 21:21:46 +00:00
|
|
|
case <-ah.TemplateTokenCh:
|
|
|
|
// Nothing
|
2018-07-25 02:02:27 +00:00
|
|
|
case <-time.After(stopTime.Sub(time.Now())):
|
|
|
|
if !closed {
|
|
|
|
cancelFunc()
|
|
|
|
closed = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-23 20:04:21 +00:00
|
|
|
|
2021-03-03 22:15:18 +00:00
|
|
|
func TestAgentBackoff(t *testing.T) {
|
|
|
|
max := 1024 * time.Second
|
|
|
|
backoff := newAgentBackoff(max)
|
|
|
|
|
|
|
|
// Test initial value
|
|
|
|
if backoff.current != initialBackoff {
|
|
|
|
t.Fatalf("expected 1s initial backoff, got: %v", backoff.current)
|
2021-02-23 20:04:21 +00:00
|
|
|
}
|
|
|
|
|
2021-03-03 22:15:18 +00:00
|
|
|
// Test that backoff values are in expected range (75-100% of 2*previous)
|
|
|
|
for i := 0; i < 9; i++ {
|
|
|
|
old := backoff.current
|
|
|
|
backoff.next()
|
2021-02-23 20:04:21 +00:00
|
|
|
|
2021-03-03 22:15:18 +00:00
|
|
|
expMax := 2 * old
|
|
|
|
expMin := 3 * expMax / 4
|
|
|
|
|
|
|
|
if backoff.current < expMin || backoff.current > expMax {
|
|
|
|
t.Fatalf("expected backoff in range %v to %v, got: %v", expMin, expMax, backoff)
|
2021-02-23 20:04:21 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-03 22:15:18 +00:00
|
|
|
|
|
|
|
// Test that backoff is capped
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
backoff.next()
|
|
|
|
if backoff.current > max {
|
|
|
|
t.Fatalf("backoff exceeded max of 100s: %v", backoff)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test reset
|
|
|
|
backoff.reset()
|
|
|
|
if backoff.current != initialBackoff {
|
|
|
|
t.Fatalf("expected 1s backoff after reset, got: %v", backoff.current)
|
|
|
|
}
|
2021-02-23 20:04:21 +00:00
|
|
|
}
|