Security context
High· 8.2GHSA-fp52-qw33-mfmw CVE-2020-16250CWE-290CWE-345Published Aug 2, 2021

Authentication Bypass by Spoofing and Insufficient Verification of Data Authenticity in Hashicorp Vault

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

0.8.1 → fixed in 1.2.51.3.0 → fixed in 1.3.81.4.0 → fixed in 1.4.41.5.0 → fixed in 1.5.1

Details

HashiCorp Vault and Vault Enterprise versions 0.7.1 and newer, when configured with the AWS IAM auth method, may be vulnerable to authentication bypass. Fixed in 1.2.5, 1.3.8, 1.4.4, and 1.5.1..

The fix

Release delta 1.3.0 → 1.3.8 (contains the fix)

· Dec 2, 2019, 06:13 PM+20811525compare
command/agent_test.go+268 44
@@ -224,7 +224,7 @@ cache {
}
*/
-func TestExitAfterAuth(t *testing.T) {
+func TestAgent_ExitAfterAuth(t *testing.T) {
logger := logging.NewVaultLogger(hclog.Trace)
coreConfig := &vault.CoreConfig{
Logger: logger,
@@ -381,19 +381,6 @@ auto_auth {
}
func TestAgent_RequireRequestHeader(t *testing.T) {
-
- // makeTempFile creates a temp file and populates it.
- makeTempFile := func(name, contents string) string {
- f, err := ioutil.TempFile("", name)
- if err != nil {
- t.Fatal(err)
- }
- path := f.Name()
- f.WriteString(contents)
- f.Close()
- return path
- }
-
// newApiClient creates an *api.Client.
newApiClient := func(addr string, includeVaultRequestHeader bool) *api.Client {
conf := api.DefaultConfig()
@@ -468,13 +455,13 @@ func TestAgent_RequireRequestHeader(t *testing.T) {
secretID := data["secret_id"].(string)
// Write the RoleID and SecretID to temp files
- roleIDPath := makeTempFile("role_id.txt", roleID+"\n")
- secretIDPath := makeTempFile("secret_id.txt", secretID+"\n")
+ roleIDPath := makeTempFile(t, "role_id.txt", roleID+"\n")
+ secretIDPath := makeTempFile(t, "secret_id.txt", secretID+"\n")
defer os.Remove(roleIDPath)
defer os.Remove(secretIDPath)
// Get a temp file path we can use for the sink
- sinkPath := makeTempFile("sink.txt", "")
+ sinkPath := makeTempFile(t, "sink.txt", "")
defer os.Remove(sinkPath)
// Create a config file
@@ -515,7 +502,7 @@ listener "tcp" {
}
`
config = fmt.Sprintf(config, roleIDPath, secretIDPath, sinkPath)
- configPath := makeTempFile("config.hcl", config)
+ configPath := makeTempFile(t, "config.hcl", config)
defer os.Remove(configPath)
// Start the agent
@@ -598,22 +585,7 @@ listener "tcp" {
}
// TestAgent_Template tests rendering templates
-func TestAgent_Template(t *testing.T) {
- //----------------------------------------------------
- // Pre-test setup
- //----------------------------------------------------
- // makeTempFile creates a temp file and populates it.
- makeTempFile := func(name, contents string) string {
- f, err := ioutil.TempFile("", name)
- if err != nil {
- t.Fatal(err)
- }
- path := f.Name()
- f.WriteString(contents)
- f.Close()
- return path
- }
-
+func TestAgent_Template_Basic(t *testing.T) {
//----------------------------------------------------
// Start the server and agent
//----------------------------------------------------
@@ -673,8 +645,8 @@ func TestAgent_Template(t *testing.T) {
secretID := data["secret_id"].(string)
// Write the RoleID and SecretID to temp files
- roleIDPath := makeTempFile("role_id.txt", roleID+"\n")
- secretIDPath := makeTempFile("secret_id.txt", secretID+"\n")
+ roleIDPath := makeTempFile(t, "role_id.txt", roleID+"\n")
+ secretIDPath := makeTempFile(t, "secret_id.txt", secretID+"\n")
defer os.Remove(roleIDPath)
defer os.Remove(secretIDPath)
@@ -695,8 +667,19 @@ func TestAgent_Template(t *testing.T) {
}`)
request(t, serverClient, req, 200)
+ // populate another secret
+ req = serverClient.NewRequest("POST", "/v1/secret/data/otherapp")
+ req.BodyBytes = []byte(`{
+ "data": {
+ "username": "barstuff",
+ "password": "zap",
+ "cert": "something"
+ }
+ }`)
+ request(t, serverClient, req, 200)
+
// Get a temp file path we can use for the sink
- sinkPath := makeTempFile("sink.txt", "")
+ sinkPath := makeTempFile(t, "sink.txt", "")
defer os.Remove(sinkPath)
// make a temp directory to hold renders. Each test will create a temp dir
@@ -719,15 +702,15 @@ func TestAgent_Template(t *testing.T) {
"one": {
templateCount: 1,
},
- "one_exit": {
+ "one_with_exit": {
templateCount: 1,
exitAfterAuth: true,
},
"many": {
templateCount: 15,
},
- "many_exit": {
- templateCount: 15,
+ "many_with_exit": {
+ templateCount: 13,
exitAfterAuth: true,
},
}
@@ -737,7 +720,7 @@ func TestAgent_Template(t *testing.T) {
// make some template files
var templatePaths []string
for i := 0; i < tc.templateCount; i++ {
- path := makeTempFile(fmt.Sprintf("render_%d", i), templateContents)
+ path := makeTempFile(t, fmt.Sprintf("render_%d", i), templateContents(i))
templatePaths = append(templatePaths, path)
}
@@ -794,7 +777,7 @@ auto_auth {
templateConfig := strings.Join(templateConfigStrings, " ")
config = fmt.Sprintf(config, serverClient.Address(), roleIDPath, secretIDPath, sinkPath, templateConfig, exitAfterAuth)
- configPath := makeTempFile("config.hcl", config)
+ configPath := makeTempFile(t, "config.hcl", config)
defer os.Remove(configPath)
// Start the agent
@@ -848,13 +831,256 @@ auto_auth {
}
}
-var templateContents = `{{ with secret "secret/myapp"}}
+// TestAgent_Template_ExitCounter tests that Vault Agent correctly renders all
+// templates before exiting when the configuration uses exit_after_auth. This is
+// similar to TestAgent_Template_Basic, but differs by using a consistent number
+// of secrets from multiple sources, where as the basic test could possibly
+// generate a random number of secrets, but all using the same source. This test
+// reproduces https://github.com/hashicorp/vault/issues/7883
+func TestAgent_Template_ExitCounter(t *testing.T) {
+ //----------------------------------------------------
+ // Start the server and agent
+ //----------------------------------------------------
+ logger := logging.NewVaultLogger(hclog.Trace)
+ cluster := vault.NewTestCluster(t,
+ &vault.CoreConfig{
+ Logger: logger,
+ CredentialBackends: map[string]logical.Factory{
+ "approle": credAppRole.Factory,
+ },
+ LogicalBackends: map[string]logical.Factory{
+ "kv": logicalKv.Factory,
+ },
+ },
+ &vault.TestClusterOptions{
+ HandlerFunc: vaulthttp.Handler,
+ })
+ cluster.Start()
+ defer cluster.Cleanup()
+
+ vault.TestWaitActive(t, cluster.Cores[0].Core)
+ serverClient := cluster.Cores[0].Client
+
+ // Enable the approle auth method
+ req := serverClient.NewRequest("POST", "/v1/sys/auth/approle")
+ req.BodyBytes = []byte(`{
+ "type": "approle"
+ }`)
+ request(t, serverClient, req, 204)
+
+ // give test-role permissions to read the kv secret
+ req = serverClient.NewRequest("PUT", "/v1/sys/policy/myapp-read")
+ req.BodyBytes = []byte(`{
+ "policy": "path \"secret/*\" { capabilities = [\"read\", \"list\"] }"
+ }`)
+ request(t, serverClient, req, 204)
+
+ // Create a named role
+ req = serverClient.NewRequest("PUT", "/v1/auth/approle/role/test-role")
+ req.BodyBytes = []byte(`{
+ "token_ttl": "5m",
+ "token_policies":"default,myapp-read",
+ "policies":"default,myapp-read"
+ }`)
+ request(t, serverClient, req, 204)
+
+ // Fetch the RoleID of the named role
+ req = serverClient.NewRequest("GET", "/v1/auth/approle/role/test-role/role-id")
+ body := request(t, serverClient, req, 200)
+ data := body["data"].(map[string]interface{})
+ roleID := data["role_id"].(string)
+
+ // Get a SecretID issued against the named role
+ req = serverClient.NewRequest("PUT", "/v1/auth/approle/role/test-role/secret-id")
+ body = request(t, serverClient, req, 200)
+ data = body["data"].(map[string]interface{})
+ secretID := data["secret_id"].(string)
+
+ // Write the RoleID and SecretID to temp files
+ roleIDPath := makeTempFile(t, "role_id.txt", roleID+"\n")
+ secretIDPath := makeTempFile(t, "secret_id.txt", secretID+"\n")
+ defer os.Remove(roleIDPath)
+ defer os.Remove(secretIDPath)
+
+ // setup the kv secrets
+ req = serverClient.NewRequest("POST", "/v1/sys/mounts/secret/tune")
+ req.BodyBytes = []byte(`{
+ "options": {"version": "2"}
+ }`)
+ request(t, serverClient, req, 200)
+
+ // populate a secret
+ req = serverClient.NewRequest("POST", "/v1/secret/data/myapp")
+ req.BodyBytes = []byte(`{
+ "data": {
+ "username": "bar",
+ "password": "zap"
+ }
+ }`)
+ request(t, serverClient, req, 200)
+
+ // populate another secret
+ req = serverClient.NewRequest("POST", "/v1/secret/data/myapp2")
+ req.BodyBytes = []byte(`{
+ "data": {
+ "username": "barstuff",
+ "password": "zap"
+ }
+ }`)
+ request(t, serverClient, req, 200)
+
+ // populate another, another secret
+ req = serverClient.NewRequest("POST", "/v1/secret/data/otherapp")
+ req.BodyBytes = []byte(`{
+ "data": {
+ "username": "barstuff",
+ "password": "zap",
+ "cert": "something"
+ }
+ }`)
+ request(t, serverClient, req, 200)
+
+ // Get a temp file path we can use for the sink
+ sinkPath := makeTempFile(t, "sink.txt", "")
+ defer os.Remove(sinkPath)
+
+ // make a temp directory to hold renders. Each test will create a temp dir
+ // inside this one
+ tmpDirRoot, err := ioutil.TempDir("", "agent-test-renders")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpDirRoot)
+
+ // create temp dir for this test run
+ tmpDir, err := ioutil.TempDir(tmpDirRoot, "agent-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Create a config file
+ config := `
+vault {
+ address = "%s"
+ tls_skip_verify = true
+}
+
+auto_auth {
+ method "approle" {
+ mount_path = "auth/approle"
+ config = {
+ role_id_file_path = "%s"
+ secret_id_file_path = "%s"
+ remove_secret_id_file_after_reading = false
+ }
+ }
+
+ sink "file" {
+ config = {
+ path = "%s"
+ }
+ }
+}
+
+template {
+ contents = "{{ with secret \"secret/myapp\" }}{{ range $k, $v := .Data.data }}{{ $v }}{{ end }}{{ end }}"
+ destination = "%s/render-pass.txt"
+}
+
+template {
+ contents = "{{ with secret \"secret/myapp2\" }}{{ .Data.data.username}}{{ end }}"
+ destination = "%s/render-user.txt"
+}
+
+template {
+ contents = <<EOF
+{{ with secret "secret/otherapp"}}
+{
+{{ if .Data.data.username}}"username":"{{ .Data.data.username}}",{{ end }}
+{{ if .Data.data.password }}"password":"{{ .Data.data.password }}",{{ end }}
+{{ .Data.data.cert }}
+}
+{{ end }}
+EOF
+ destination = "%s/render-other.txt"
+ }
+
+exit_after_auth = true
+`
+
+ config = fmt.Sprintf(config, serverClient.Address(), roleIDPath, secretIDPath, sinkPath, tmpDir, tmpDir, tmpDir)
+ configPath := makeTempFile(t, "config.hcl", config)
+ defer os.Remove(configPath)
+
+ // Start the agent
+ ui, cmd := testAgentCommand(t, logger)
+ cmd.client = serverClient
+ cmd.startedCh = make(chan struct{})
+
+ wg := &sync.WaitGroup{}
+ wg.Add(1)
+ go func() {
+ code := cmd.Run([]string{"-config", configPath})
+ if code != 0 {
+ t.Errorf("non-zero return code when running agent: %d", code)
+ t.Logf("STDOUT from agent:\n%s", ui.OutputWriter.String())
+ t.Logf("STDERR from agent:\n%s", ui.ErrorWriter.String())
+ }
+ wg.Done()
+ }()
+
+ select {
+ case <-cmd.startedCh:
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout")
+ }
+
+ wg.Wait()
+
+ //----------------------------------------------------
+ // Perform the tests
+ //----------------------------------------------------
+
+ files, err := ioutil.ReadDir(tmpDir)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(files) != 3 {
+ t.Fatalf("expected (%d) templates, got (%d)", 3, len(files))
+ }
+}
+
+// a slice of template options
+var templates = []string{
+ `{{ with secret "secret/otherapp"}}
{
{{ if .Data.data.username}}"username":"{{ .Data.data.username}}",{{ end }}
{{ if .Data.data.password }}"password":"{{ .Data.data.password }}",{{ end }}
-{{ if .Data.metadata.version}}"version":"{{ .Data.metadata.version }}"{{ end }}
+{{ .Data.data.cert }}
+}
+{{ end }}`,
+ `{{ with secret "secret/myapp"}}
+{
+{{ if .Data.data.username}}"username":"{{ .Data.data.username}}",{{ end }}
+{{ if .Data.data.password }}"password":"{{ .Data.data.password }}",{{ end }}
+}
+{{ end }}`,
+ `{{ with secret "secret/myapp"}}
+{
+{{ if .Data.data.password }}"password":"{{ .Data.data.password }}",{{ end }}
+}
+{{ end }}`,
+}
+
+// templateContents returns a template from the above templates slice. Each
+// invocation with incrementing seed will return "the next" template, and loop.
+// This ensures as we use multiple templates that we have a increasing number of
+// sources before we reuse a template.
… diff truncated
go.sum+30 40
@@ -310,8 +310,6 @@ github.com/hashicorp/go-raftchunking v0.6.3-0.20191002164813-7e9e8525653a h1:Fmn
github.com/hashicorp/go-raftchunking v0.6.3-0.20191002164813-7e9e8525653a/go.mod h1:xbXnmKqX9/+RhPkJ4zrEx4738HacP72aaUPlT2RZ4sU=
github.com/hashicorp/go-retryablehttp v0.5.3 h1:QlWt0KvWT0lq8MFppF9tsJGF+ynG7ztc2KIPhzRGk7s=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
-github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE=
-github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.6.2 h1:bHM2aVXwBtBJWxHtkSrWuI4umABCUczs52eiUS9nSiw=
github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY=
github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI=
@@ -358,46 +356,38 @@ github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k=
github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
-github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2-0.20190814210027-93970f08f2ec h1:HXVE8h6RXFsPJgwWpE+5CscsgekqtX4nhDlZGV9jEe4=
-github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2-0.20190814210027-93970f08f2ec/go.mod h1:TYFfVFgKF9x92T7uXouI9rLPkNnyXo/KkNcj5t+mjdM=
-github.com/hashicorp/vault-plugin-auth-azure v0.5.2-0.20190814210035-08e00d801115 h1:E57y918o+c+NoI5k7ohbpZu7vRm1XZKZfC5VQVpJvDI=
-github.com/hashicorp/vault-plugin-auth-azure v0.5.2-0.20190814210035-08e00d801115/go.mod h1:sRhTnkcbjJgPeES0ddCTq8S2waSakyMiWLUwO5J/Wjk=
-github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190814210042-090ec2ed93ce h1:X8umWdCqSVk/75ZjEBDxYL+V8i+jK3KbJbFoyOryCww=
-github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190814210042-090ec2ed93ce/go.mod h1:WstOCHERNbk2dblnY5MV9Qeh/hzTSQpVs5xPuyAzlBo=
-github.com/hashicorp/vault-plugin-auth-cf v0.0.0-20190821162840-1c2205826fee h1:gJG1PJGiqi+0M0HTYlwDyV5CyetLhFl9DxyMJre5H9Y=
-github.com/hashicorp/vault-plugin-auth-cf v0.0.0-20190821162840-1c2205826fee/go.mod h1:zOag32+pm1R4FFNhXMLP506Oesjoai3gHEEpxqUaTr0=
+github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2 h1:pbFGwo6fxDBZZpqB2MFUaeZac5DTeZH1KOC1CqbRWog=
+github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2/go.mod h1:ZQ2jCwUqeEQgRKV3cvrQeaJhPZpaXpdSvNPrHIVgIAI=
+github.com/hashicorp/vault-plugin-auth-azure v0.5.2 h1:cuR30u+vQr4sw5bcBvOzcSbQRkgKfCD5NGzHYvpfskE=
+github.com/hashicorp/vault-plugin-auth-azure v0.5.2/go.mod h1:9p4tzXBC1xsH3Sh1xesqxJbh/FIyTrEtFt9VmtqAN6Q=
+github.com/hashicorp/vault-plugin-auth-centrify v0.5.2 h1:/rCF+N+Mi3NQiUkgQKcTP30y7BaG6sPyRdvFcG2owAU=
+github.com/hashicorp/vault-plugin-auth-centrify v0.5.2/go.mod h1:cJcz5bF49lq6Gig4pGVC6u845Z8DeQikcf8FqRc4jNs=
+github.com/hashicorp/vault-plugin-auth-cf v0.5.1 h1:jhRZMYpFEGnKHHMeIAUf6WkJtyXhE1qVxQUDSgAjl6c=
+github.com/hashicorp/vault-plugin-auth-cf v0.5.1/go.mod h1:x90U1gj89OLDZ8D5HyzJx3aQkRYN59Na5YKmp/6rco4=
github.com/hashicorp/vault-plugin-auth-gcp v0.5.1 h1:8DR00s+Wmc21i3sfzvsqW88VMdf6NI2ue+onGoHshww=
github.com/hashicorp/vault-plugin-auth-gcp v0.5.1/go.mod h1:eLj92eX8MPI4vY1jaazVLF2sVbSAJ3LRHLRhF/pUmlI=
-github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190814210049-1ccb3dc10102 h1:RTHVdxCDwxTq/4zZFkV+b8zexkSU5EOXkY2D/kAvyFU=
-github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190814210049-1ccb3dc10102/go.mod h1:j0hMnnTD44zXGQhLM1jarYDaTmSp6OPiOzgFQ6mNgzc=
-github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190930204802-acfd134850c2 h1:gtpqHauSoJCxZStLVWKMQcsdW61EewJSoegMrZLQ/GU=
-github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190930204802-acfd134850c2/go.mod h1:j0hMnnTD44zXGQhLM1jarYDaTmSp6OPiOzgFQ6mNgzc=
-github.com/hashicorp/vault-plugin-auth-jwt v0.5.2-0.20191010173058-65cf93bad3f2 h1:Oi9HO9/JItId2XYLEoTIW9Wcfg5sblxxO5Nr7ln1jnk=
-github.com/hashicorp/vault-plugin-auth-jwt v0.5.2-0.20191010173058-65cf93bad3f2/go.mod h1:Ti2NPndKhSGpSL6gWg11n7TkmuI7318BIPeojayIVRU=
-github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190826163451-8461c66275a9 h1:PjbIf3mlPBJopQSJstQAhVbdGTVZ/W35RZtm/GCOTUs=
-github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190826163451-8461c66275a9/go.mod h1:qkrONCr71ckSCTItJQ1j9uet/faieZJ5c7+GZugTm7s=
-github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190925162726-2e5b0b8184e6 h1:WgxwYXCuZJtU/oIDah4A99+MuqzzL/oGQu9421IYZ6M=
-github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190925162726-2e5b0b8184e6/go.mod h1:qkrONCr71ckSCTItJQ1j9uet/faieZJ5c7+GZugTm7s=
-github.com/hashicorp/vault-plugin-auth-oci v0.0.0-20190904175623-97c0c0187c5c h1:z6LQZvs1OtoVy2XgbgNhiDgp0U62Xbstn7/cgNZvh6g=
-github.com/hashicorp/vault-plugin-auth-oci v0.0.0-20190904175623-97c0c0187c5c/go.mod h1:YAl51RsYRihPbSdnug1NsvutzbRVfrZ12FjEIvSiOTs=
-github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190814210117-e079e01fbb93 h1:kXTV1ImOPgDGZxAlbEQfiXgnZY/34vfgnZVhI/tscmg=
-github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190814210117-e079e01fbb93/go.mod h1:N9XpfMXjeLHBgUd8iy4avOC4mCSqUC7B/R8AtCYhcfE=
-github.com/hashicorp/vault-plugin-secrets-ad v0.6.1-0.20191108162300-8f4121d78b9c h1:NmrWRlk/nbqxtK59yexgb1o8jSW7WsgYf5t7kqteb7o=
-github.com/hashicorp/vault-plugin-secrets-ad v0.6.1-0.20191108162300-8f4121d78b9c/go.mod h1:Nmxv/d6tFm0lr8gbFIF+Hj+0xYcBiyfEwX2FscpbhbQ=
-github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2-0.20190814210129-4d18bec92f56 h1:PGE26//x1eiAbZ1ExffhKa4y9xgDKLd9BHDZRkOzbEY=
-github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2-0.20190814210129-4d18bec92f56/go.mod h1:hJ42zFd3bHyE8O2liBUG+VPY0JxdMrj51TOwVGViUIU=
-github.com/hashicorp/vault-plugin-secrets-azure v0.5.2 h1:8Jz4kl0D4+DPpP13jbIrysv1RYogUBucxC4D5xPBkiA=
-github.com/hashicorp/vault-plugin-secrets-azure v0.5.2/go.mod h1:SBc53adxMmf+o8zqRbqYvq+nuSrz8OHYmgmPfxVMJEo=
-github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20190814210141-d2086ff79b04 h1:2FLjwVqpWueSoxaNdcC2Za7RX8FNp8Xt8pF/03dinV4=
-github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20190814210141-d2086ff79b04/go.mod h1:Sc+ba3kscakE5a/pi8JJhWvXWok3cpt1P77DApmUuDc=
-github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20190926185807-2bf1d3b105ac h1:ULcFIOOFykOSrJvY3yWqDLsgcj/SuUqhY7aZ5yQ7rkM=
-github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20190926185807-2bf1d3b105ac/go.mod h1:Sc+ba3kscakE5a/pi8JJhWvXWok3cpt1P77DApmUuDc=
-github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20191112195538-3c798536d157 h1:fXpYB9aF6Jgv0tZFjh46GqEkH7jIiGAwkD9Gkh2RuDw=
-github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20191112195538-3c798536d157/go.mod h1:Sc+ba3kscakE5a/pi8JJhWvXWok3cpt1P77DApmUuDc=
-github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2-0.20190814210149-315cdbf5de6e h1:RjQBOFneGwxhHsymNtbEUJXAjMO74GlZcmUrGqJnYxY=
-github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2-0.20190814210149-315cdbf5de6e/go.mod h1:5prAHuCcBiyv+xfGBviTVYeDQUhmQYN7WrxC2gMRWeQ=
-github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20191017213228-e8cf7060a4d0 h1:w4qR/yfqWOYmncR1HK1CVU7iHkqgcf0USWtbp/fTHM4=
-github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20191017213228-e8cf7060a4d0/go.mod h1:H0VKQagsJoK9o2qpULMgbspuWVnFe3G4S/K7f0Dr8qY=
+github.com/hashicorp/vault-plugin-auth-gcp v0.5.2 h1:gT3e9WtQgPSQ18OUmypWgVY5PprAP8dz43LukpM6Fjc=
+github.com/hashicorp/vault-plugin-auth-gcp v0.5.2/go.mod h1:m6/j2v39uW8ySJMKFJ2yJWQwdOTMm38OdWg13BDHxNI=
+github.com/hashicorp/vault-plugin-auth-jwt v0.5.2 h1:Lxg0wXPDozw0RzrrMIyjVR3uP1W39dCsoTJdiXhanTE=
+github.com/hashicorp/vault-plugin-auth-jwt v0.5.2/go.mod h1:VeOgz0liki/TdfyBswtxkR8U5Y+TFbYLCjDn0aYaXnk=
+github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2 h1:f6Yz2pZeSoYtmyS44H7wjos4DEYbjZ0cNXHvtOoonuo=
+github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2/go.mod h1:G9xJFyWhM5XShypzT61iL9G09NOIk0W6v1CWpMw3yg4=
+github.com/hashicorp/vault-plugin-auth-oci v0.5.1 h1:s5pDsJ5i/x5dCfN97DnfYxeEewhqtS1OUmiB5Onjkis=
+github.com/hashicorp/vault-plugin-auth-oci v0.5.1/go.mod h1:qUNrM2pJrDiUggpcvow+XijfBvz07I8NBh12bow6+0I=
+github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.1 h1:vCP8cK8EJJvVJT6zpAeFFxRy6BkH/Gq7WcC2ipQxpbg=
+github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.1/go.mod h1:+aUooVrNgF5ObHmZl8fbhbvNPGyU1Ea4ZZlhZufis24=
+github.com/hashicorp/vault-plugin-secrets-ad v0.6.1 h1:I4w2sfa8tFHg/HziHnvj0fTAw8JV9myUsk1i/ueTNM8=
+github.com/hashicorp/vault-plugin-secrets-ad v0.6.1/go.mod h1:FIFIFIUzEWws4r6UzwliiovDQAgLVgMHLDdwW7tNEuc=
+github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2 h1:oMAvyda+W6Ou6sCG52xafw7AAw6h4Q2mGFcwZ2W2F78=
+github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2/go.mod h1:B8uObFozrSvTMgARKc65iseZ/ZF5DVvJrsKVgby2kUg=
+github.com/hashicorp/vault-plugin-secrets-azure v0.5.3 h1:+r5y4tEEJnxRXHfbUjVzCMgSguEo+JC4sgbO40qYJpc=
+github.com/hashicorp/vault-plugin-secrets-azure v0.5.3/go.mod h1:Cdq5CCORnUwSdMaSibfZROV1GtyQLjCpgvb4C0Yq+/4=
+github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3 h1:nhCWkov7THRVNcN6OLSO/Fen6mfEOmV8am0Eg1ifDZw=
+github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3/go.mod h1:ROwzd9SvCe1uEfctIFqeQrB5eFRTDZRm5Sj6QSjb57A=
+github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2 h1:2VJGxQc/1BCVMrAZOXkd8MRXIzmAAXs2WWZeSS37/Sg=
+github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2/go.mod h1:x2BJuGSlrPIYEqStVrIDHqw4OXxupHVSSjjSSDO8f9g=
+github.com/hashicorp/vault-plugin-secrets-kv v0.5.2 h1:WfShI2FpNS3/mjWOdpj1jUYLPAA2HwnsU6PyjbqiNuY=
+github.com/hashicorp/vault-plugin-secrets-kv v0.5.2/go.mod h1:gXIHqmBr4NZRw9PMWsLndpxjmcwDWivGXKyhKofEkx8=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
vault/external_tests/policy/no_default_test.go+108 14
@@ -1,21 +1,20 @@
package policy
-// This is TODO once tokenhelper is added to ldaputil
-/*
-
import (
"testing"
+ "time"
"github.com/go-test/deep"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/credential/ldap"
+ ldaphelper "github.com/hashicorp/vault/helper/testhelpers/ldap"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
)
-func TestNoDefaultPolicy(t *testing.T) {
+func TestPolicy_NoDefaultPolicy(t *testing.T) {
var err error
coreConfig := &vault.CoreConfig{
DisableMlock: true,
@@ -47,12 +46,17 @@ func TestNoDefaultPolicy(t *testing.T) {
}
// Configure LDAP auth backend
- secret, err := client.Logical().Write("auth/ldap/config", map[string]interface{}{
- "url": "ldap://ldap.forumsys.com",
- "userattr": "uid",
- "userdn": "dc=example,dc=com",
- "groupdn": "dc=example,dc=com",
- "binddn": "cn=read-only-admin,dc=example,dc=com",
+ cleanup, cfg := ldaphelper.PrepareTestContainer(t, "latest")
+ defer cleanup()
+
+ _, err = client.Logical().Write("auth/ldap/config", map[string]interface{}{
+ "url": cfg.Url,
+ "userattr": cfg.UserAttr,
+ "userdn": cfg.UserDN,
+ "groupdn": cfg.GroupDN,
+ "groupattr": cfg.GroupAttr,
+ "binddn": cfg.BindDN,
+ "bindpass": cfg.BindPassword,
"token_no_default_policy": true,
})
if err != nil {
@@ -60,7 +64,7 @@ func TestNoDefaultPolicy(t *testing.T) {
}
// Create a local user in LDAP
- secret, err = client.Logical().Write("auth/ldap/users/tesla", map[string]interface{}{
+ secret, err := client.Logical().Write("auth/ldap/users/hermes conrad", map[string]interface{}{
"policies": "foo",
})
if err != nil {
@@ -68,8 +72,8 @@ func TestNoDefaultPolicy(t *testing.T) {
}
// Login with LDAP and create a token
- secret, err = client.Logical().Write("auth/ldap/login/tesla", map[string]interface{}{
- "password": "password",
+ secret, err = client.Logical().Write("auth/ldap/login/hermes conrad", map[string]interface{}{
+ "password": "hermes",
})
if err != nil {
t.Fatal(err)
@@ -86,4 +90,94 @@ func TestNoDefaultPolicy(t *testing.T) {
t.Fatal(diff)
}
}
-*/
+
+func TestPolicy_NoConfiguredPolicy(t *testing.T) {
+ var err error
+ coreConfig := &vault.CoreConfig{
+ DisableMlock: true,
+ DisableCache: true,
+ Logger: hclog.NewNullLogger(),
+ CredentialBackends: map[string]logical.Factory{
+ "ldap": ldap.Factory,
+ },
+ }
+
+ cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
+ HandlerFunc: vaulthttp.Handler,
+ })
+
+ cluster.Start()
+ defer cluster.Cleanup()
+
+ cores := cluster.Cores
+
+ vault.TestWaitActive(t, cores[0].Core)
+
+ client := cores[0].Client
+
+ err = client.Sys().EnableAuthWithOptions("ldap", &api.EnableAuthOptions{
+ Type: "ldap",
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Configure LDAP auth backend
+ cleanup, cfg := ldaphelper.PrepareTestContainer(t, "latest")
+ defer cleanup()
+
+ _, err = client.Logical().Write("auth/ldap/config", map[string]interface{}{
+ "url": cfg.Url,
+ "userattr": cfg.UserAttr,
+ "userdn": cfg.UserDN,
+ "groupdn": cfg.GroupDN,
+ "groupattr": cfg.GroupAttr,
+ "binddn": cfg.BindDN,
+ "bindpass": cfg.BindPassword,
+ "token_ttl": "24h",
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Create a local user in LDAP without any policies configured
+ secret, err := client.Logical().Write("auth/ldap/users/hermes conrad", map[string]interface{}{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Login with LDAP and create a token
+ secret, err = client.Logical().Write("auth/ldap/login/hermes conrad", map[string]interface{}{
+ "password": "hermes",
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ token := secret.Auth.ClientToken
+
+ // Lookup the token to get the entity ID
+ secret, err = client.Auth().Token().Lookup(token)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if diff := deep.Equal(secret.Data["policies"], []interface{}{"default"}); diff != nil {
+ t.Fatal(diff)
+ }
+
+ // Renew the token with an increment of 2 hours to ensure that lease renewal
+ // occurred and can be checked against the default lease duration with a
+ // big enough delta.
+ secret, err = client.Logical().Write("auth/token/renew", map[string]interface{}{
+ "token": token,
+ "increment": "2h",
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Verify that the lease renewal extended the duration properly.
+ if float64(secret.Auth.LeaseDuration) < (1 * time.Hour).Seconds() {
+ t.Fatalf("failed to renew lease, got: %v", secret.Auth.LeaseDuration)
+ }
+}
vulnerability (#8029) (#8166)
ui/package.json | 3 ++-
ui/yarn.lock | 13 ++++---------
2 files changed, 6 insertions(+), 10 deletions(-)
go.mod+17 18
@@ -70,23 +70,23 @@ require (
github.com/hashicorp/nomad/api v0.0.0-20190412184103-1c38ced33adf
github.com/hashicorp/raft v1.1.2-0.20191002163536-9c6bd3e3eb17
github.com/hashicorp/raft-snapshot v1.0.2-0.20190827162939-8117efcc5aab
- github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2-0.20190814210027-93970f08f2ec
- github.com/hashicorp/vault-plugin-auth-azure v0.5.2-0.20190814210035-08e00d801115
- github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190814210042-090ec2ed93ce
- github.com/hashicorp/vault-plugin-auth-cf v0.0.0-20190821162840-1c2205826fee
- github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190930204802-acfd134850c2
- github.com/hashicorp/vault-plugin-auth-jwt v0.5.2-0.20191010173058-65cf93bad3f2
- github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190925162726-2e5b0b8184e6
- github.com/hashicorp/vault-plugin-auth-oci v0.0.0-20190904175623-97c0c0187c5c
- github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190814210117-e079e01fbb93
- github.com/hashicorp/vault-plugin-secrets-ad v0.6.1-0.20191108162300-8f4121d78b9c
- github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2-0.20190814210129-4d18bec92f56
- github.com/hashicorp/vault-plugin-secrets-azure v0.5.2
- github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20191112195538-3c798536d157
- github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2-0.20190814210149-315cdbf5de6e
- github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20191017213228-e8cf7060a4d0
- github.com/hashicorp/vault/api v1.0.5-0.20191108163347-bdd38fca2cff
- github.com/hashicorp/vault/sdk v0.1.14-0.20191112033314-390e96e22eb2
+ github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2
+ github.com/hashicorp/vault-plugin-auth-azure v0.5.2
+ github.com/hashicorp/vault-plugin-auth-centrify v0.5.2
+ github.com/hashicorp/vault-plugin-auth-cf v0.5.1
+ github.com/hashicorp/vault-plugin-auth-gcp v0.5.2
+ github.com/hashicorp/vault-plugin-auth-jwt v0.5.2
+ github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2
+ github.com/hashicorp/vault-plugin-auth-oci v0.5.1
+ github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.1
+ github.com/hashicorp/vault-plugin-secrets-ad v0.6.1
+ github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2
+ github.com/hashicorp/vault-plugin-secrets-azure v0.5.3
+ github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3
+ github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2
+ github.com/hashicorp/vault-plugin-secrets-kv v0.5.2
+ github.com/hashicorp/vault/api v1.0.5-0.20191216174727-9d51b36f3ae4
+ github.com/hashicorp/vault/sdk v0.1.14-0.20191216174727-9d51b36f3ae4
github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
github.com/jackc/pgx v3.3.0+incompatible // indirect
@@ -95,7 +95,6 @@ require (
github.com/joyent/triton-go v0.0.0-20190112182421-51ffac552869
github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f
github.com/kr/pretty v0.1.0
- github.com/kr/pty v1.1.3 // indirect
github.com/kr/text v0.1.0
github.com/lib/pq v1.2.0
github.com/mattn/go-colorable v0.1.2
vendor/modules.txt+17 17
@@ -361,51 +361,51 @@ github.com/hashicorp/raft
github.com/hashicorp/raft-snapshot
# github.com/hashicorp/serf v0.8.3
github.com/hashicorp/serf/coordinate
-# github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2-0.20190814210027-93970f08f2ec
+# github.com/hashicorp/vault-plugin-auth-alicloud v0.5.2
github.com/hashicorp/vault-plugin-auth-alicloud
github.com/hashicorp/vault-plugin-auth-alicloud/tools
-# github.com/hashicorp/vault-plugin-auth-azure v0.5.2-0.20190814210035-08e00d801115
+# github.com/hashicorp/vault-plugin-auth-azure v0.5.2
github.com/hashicorp/vault-plugin-auth-azure
-# github.com/hashicorp/vault-plugin-auth-centrify v0.5.2-0.20190814210042-090ec2ed93ce
+# github.com/hashicorp/vault-plugin-auth-centrify v0.5.2
github.com/hashicorp/vault-plugin-auth-centrify
-# github.com/hashicorp/vault-plugin-auth-cf v0.0.0-20190821162840-1c2205826fee
+# github.com/hashicorp/vault-plugin-auth-cf v0.5.1
github.com/hashicorp/vault-plugin-auth-cf
github.com/hashicorp/vault-plugin-auth-cf/signatures
github.com/hashicorp/vault-plugin-auth-cf/models
github.com/hashicorp/vault-plugin-auth-cf/util
github.com/hashicorp/vault-plugin-auth-cf/testing/certificates
github.com/hashicorp/vault-plugin-auth-cf/testing/cf
-# github.com/hashicorp/vault-plugin-auth-gcp v0.5.2-0.20190930204802-acfd134850c2
+# github.com/hashicorp/vault-plugin-auth-gcp v0.5.2
github.com/hashicorp/vault-plugin-auth-gcp/plugin
github.com/hashicorp/vault-plugin-auth-gcp/plugin/cache
-# github.com/hashicorp/vault-plugin-auth-jwt v0.5.2-0.20191010173058-65cf93bad3f2
+# github.com/hashicorp/vault-plugin-auth-jwt v0.5.2
github.com/hashicorp/vault-plugin-auth-jwt
-# github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2-0.20190925162726-2e5b0b8184e6
+# github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.2
github.com/hashicorp/vault-plugin-auth-kubernetes
-# github.com/hashicorp/vault-plugin-auth-oci v0.0.0-20190904175623-97c0c0187c5c
+# github.com/hashicorp/vault-plugin-auth-oci v0.5.1
github.com/hashicorp/vault-plugin-auth-oci
-# github.com/hashicorp/vault-plugin-database-elasticsearch v0.0.0-20190814210117-e079e01fbb93
+# github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.1
github.com/hashicorp/vault-plugin-database-elasticsearch
-# github.com/hashicorp/vault-plugin-secrets-ad v0.6.1-0.20191108162300-8f4121d78b9c
+# github.com/hashicorp/vault-plugin-secrets-ad v0.6.1
github.com/hashicorp/vault-plugin-secrets-ad/plugin
github.com/hashicorp/vault-plugin-secrets-ad/plugin/client
github.com/hashicorp/vault-plugin-secrets-ad/plugin/util
-# github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2-0.20190814210129-4d18bec92f56
+# github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.2
github.com/hashicorp/vault-plugin-secrets-alicloud
github.com/hashicorp/vault-plugin-secrets-alicloud/clients
-# github.com/hashicorp/vault-plugin-secrets-azure v0.5.2
+# github.com/hashicorp/vault-plugin-secrets-azure v0.5.3
github.com/hashicorp/vault-plugin-secrets-azure
-# github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3-0.20191112195538-3c798536d157
+# github.com/hashicorp/vault-plugin-secrets-gcp v0.5.3
github.com/hashicorp/vault-plugin-secrets-gcp/plugin
github.com/hashicorp/vault-plugin-secrets-gcp/plugin/iamutil
github.com/hashicorp/vault-plugin-secrets-gcp/plugin/util
-# github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2-0.20190814210149-315cdbf5de6e
+# github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.2
github.com/hashicorp/vault-plugin-secrets-gcpkms
-# github.com/hashicorp/vault-plugin-secrets-kv v0.5.2-0.20191017213228-e8cf7060a4d0
+# github.com/hashicorp/vault-plugin-secrets-kv v0.5.2
github.com/hashicorp/vault-plugin-secrets-kv
-# github.com/hashicorp/vault/api v1.0.5-0.20191108163347-bdd38fca2cff => ./api
+# github.com/hashicorp/vault/api v1.0.5-0.20191216174727-9d51b36f3ae4 => ./api
github.com/hashicorp/vault/api
-# github.com/hashicorp/vault/sdk v0.1.14-0.20191112033314-390e96e22eb2 => ./sdk
+# github.com/hashicorp/vault/sdk v0.1.14-0.20191216174727-9d51b36f3ae4 => ./sdk
github.com/hashicorp/vault/sdk/helper/salt
github.com/hashicorp/vault/sdk/helper/strutil
github.com/hashicorp/vault/sdk/helper/wrapping
sdk/helper/ldaputil/client.go | 7 ++++---
sdk/helper/ldaputil/client_test.go | 20 +++++++++++++++++++
.../vault/sdk/helper/ldaputil/client.go | 7 ++++---
3 files changed, 28 insertions(+), 6 deletions(-)
vendor/github.com/google/go-github/github/gen-accessors.go+0 332
@@ -1,332 +0,0 @@
-// Copyright 2017 The go-github AUTHORS. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// gen-accessors generates accessor methods for structs with pointer fields.
-//
-// It is meant to be used by the go-github authors in conjunction with the
-// go generate tool before sending a commit to GitHub.
-package main
-
-import (
- "bytes"
- "flag"
- "fmt"
- "go/ast"
- "go/format"
- "go/parser"
- "go/token"
- "io/ioutil"
- "log"
- "os"
- "sort"
- "strings"
- "text/template"
-)
-
-const (
- fileSuffix = "-accessors.go"
-)
-
-var (
- verbose = flag.Bool("v", false, "Print verbose log messages")
-
- sourceTmpl = template.Must(template.New("source").Parse(source))
-
- // blacklistStructMethod lists "struct.method" combos to skip.
- blacklistStructMethod = map[string]bool{
- "RepositoryContent.GetContent": true,
- "Client.GetBaseURL": true,
- "Client.GetUploadURL": true,
- "ErrorResponse.GetResponse": true,
- "RateLimitError.GetResponse": true,
- "AbuseRateLimitError.GetResponse": true,
- }
- // blacklistStruct lists structs to skip.
- blacklistStruct = map[string]bool{
- "Client": true,
- }
-)
-
-func logf(fmt string, args ...interface{}) {
- if *verbose {
- log.Printf(fmt, args...)
- }
-}
-
-func main() {
- flag.Parse()
- fset := token.NewFileSet()
-
- pkgs, err := parser.ParseDir(fset, ".", sourceFilter, 0)
- if err != nil {
- log.Fatal(err)
- return
- }
-
- for pkgName, pkg := range pkgs {
- t := &templateData{
- filename: pkgName + fileSuffix,
- Year: 2017,
- Package: pkgName,
- Imports: map[string]string{},
- }
- for filename, f := range pkg.Files {
- logf("Processing %v...", filename)
- if err := t.processAST(f); err != nil {
- log.Fatal(err)
- }
- }
- if err := t.dump(); err != nil {
- log.Fatal(err)
- }
- }
- logf("Done.")
-}
-
-func (t *templateData) processAST(f *ast.File) error {
- for _, decl := range f.Decls {
- gd, ok := decl.(*ast.GenDecl)
- if !ok {
- continue
- }
- for _, spec := range gd.Specs {
- ts, ok := spec.(*ast.TypeSpec)
- if !ok {
- continue
- }
- // Skip unexported identifiers.
- if !ts.Name.IsExported() {
- logf("Struct %v is unexported; skipping.", ts.Name)
- continue
- }
- // Check if the struct is blacklisted.
- if blacklistStruct[ts.Name.Name] {
- logf("Struct %v is blacklisted; skipping.", ts.Name)
- continue
- }
- st, ok := ts.Type.(*ast.StructType)
- if !ok {
- continue
- }
- for _, field := range st.Fields.List {
- se, ok := field.Type.(*ast.StarExpr)
- if len(field.Names) == 0 || !ok {
- continue
- }
-
- fieldName := field.Names[0]
- // Skip unexported identifiers.
- if !fieldName.IsExported() {
- logf("Field %v is unexported; skipping.", fieldName)
- continue
- }
- // Check if "struct.method" is blacklisted.
- if key := fmt.Sprintf("%v.Get%v", ts.Name, fieldName); blacklistStructMethod[key] {
- logf("Method %v is blacklisted; skipping.", key)
- continue
- }
-
- switch x := se.X.(type) {
- case *ast.ArrayType:
- t.addArrayType(x, ts.Name.String(), fieldName.String())
- case *ast.Ident:
- t.addIdent(x, ts.Name.String(), fieldName.String())
- case *ast.MapType:
- t.addMapType(x, ts.Name.String(), fieldName.String())
- case *ast.SelectorExpr:
- t.addSelectorExpr(x, ts.Name.String(), fieldName.String())
- default:
- logf("processAST: type %q, field %q, unknown %T: %+v", ts.Name, fieldName, x, x)
- }
- }
- }
- }
- return nil
-}
-
-func sourceFilter(fi os.FileInfo) bool {
- return !strings.HasSuffix(fi.Name(), "_test.go") && !strings.HasSuffix(fi.Name(), fileSuffix)
-}
-
-func (t *templateData) dump() error {
- if len(t.Getters) == 0 {
- logf("No getters for %v; skipping.", t.filename)
- return nil
- }
-
- // Sort getters by ReceiverType.FieldName.
- sort.Sort(byName(t.Getters))
-
- var buf bytes.Buffer
- if err := sourceTmpl.Execute(&buf, t); err != nil {
- return err
- }
- clean, err := format.Source(buf.Bytes())
- if err != nil {
- return err
- }
-
- logf("Writing %v...", t.filename)
- return ioutil.WriteFile(t.filename, clean, 0644)
-}
-
-func newGetter(receiverType, fieldName, fieldType, zeroValue string, namedStruct bool) *getter {
- return &getter{
- sortVal: strings.ToLower(receiverType) + "." + strings.ToLower(fieldName),
- ReceiverVar: strings.ToLower(receiverType[:1]),
- ReceiverType: receiverType,
- FieldName: fieldName,
- FieldType: fieldType,
- ZeroValue: zeroValue,
- NamedStruct: namedStruct,
- }
-}
-
-func (t *templateData) addArrayType(x *ast.ArrayType, receiverType, fieldName string) {
- var eltType string
- switch elt := x.Elt.(type) {
- case *ast.Ident:
- eltType = elt.String()
- default:
- logf("addArrayType: type %q, field %q: unknown elt type: %T %+v; skipping.", receiverType, fieldName, elt, elt)
- return
- }
-
- t.Getters = append(t.Getters, newGetter(receiverType, fieldName, "[]"+eltType, "nil", false))
-}
-
-func (t *templateData) addIdent(x *ast.Ident, receiverType, fieldName string) {
- var zeroValue string
- var namedStruct = false
- switch x.String() {
- case "int", "int64":
- zeroValue = "0"
- case "string":
- zeroValue = `""`
- case "bool":
- zeroValue = "false"
- case "Timestamp":
- zeroValue = "Timestamp{}"
- default:
- zeroValue = "nil"
- namedStruct = true
- }
-
- t.Getters = append(t.Getters, newGetter(receiverType, fieldName, x.String(), zeroValue, namedStruct))
-}
-
-func (t *templateData) addMapType(x *ast.MapType, receiverType, fieldName string) {
- var keyType string
- switch key := x.Key.(type) {
- case *ast.Ident:
- keyType = key.String()
- default:
- logf("addMapType: type %q, field %q: unknown key type: %T %+v; skipping.", receiverType, fieldName, key, key)
- return
- }
-
- var valueType string
- switch value := x.Value.(type) {
- case *ast.Ident:
- valueType = value.String()
- default:
- logf("addMapType: type %q, field %q: unknown value type: %T %+v; skipping.", receiverType, fieldName, value, value)
- return
- }
-
- fieldType := fmt.Sprintf("map[%v]%v", keyType, valueType)
- zeroValue := fmt.Sprintf("map[%v]%v{}", keyType, valueType)
- t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue, false))
-}
-
-func (t *templateData) addSelectorExpr(x *ast.SelectorExpr, receiverType, fieldName string) {
- if strings.ToLower(fieldName[:1]) == fieldName[:1] { // Non-exported field.
- return
- }
-
- var xX string
- if xx, ok := x.X.(*ast.Ident); ok {
- xX = xx.String()
- }
-
- switch xX {
- case "time", "json":
- if xX == "json" {
- t.Imports["encoding/json"] = "encoding/json"
- } else {
- t.Imports[xX] = xX
- }
- fieldType := fmt.Sprintf("%v.%v", xX, x.Sel.Name)
- zeroValue := fmt.Sprintf("%v.%v{}", xX, x.Sel.Name)
- if xX == "time" && x.Sel.Name == "Duration" {
- zeroValue = "0"
- }
- t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue, false))
- default:
- logf("addSelectorExpr: xX %q, type %q, field %q: unknown x=%+v; skipping.", xX, receiverType, fieldName, x)
- }
-}
-
-type templateData struct {
- filename string
- Year int
- Package string
- Imports map[string]string
- Getters []*getter
-}
-
-type getter struct {
- sortVal string // Lower-case version of "ReceiverType.FieldName".
- ReceiverVar string // The one-letter variable name to match the ReceiverType.
- ReceiverType string
- FieldName string
- FieldType string
- ZeroValue string
- NamedStruct bool // Getter for named struct.
-}
-
-type byName []*getter
-
-func (b byName) Len() int { return len(b) }
-func (b byName) Less(i, j int) bool { return b[i].sortVal < b[j].sortVal }
-func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
-
-const source = `// Copyright {{.Year}} The go-github AUTHORS. All rights reserved.
-//
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Code generated by gen-accessors; DO NOT EDIT.
-
-package {{.Package}}
-{{with .Imports}}
-import (
- {{- range . -}}
- "{{.}}"
- {{end -}}
-)
-{{end}}
-{{range .Getters}}
-{{if .NamedStruct}}
-// Get{{.FieldName}} returns the {{.FieldName}} field.
-func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() *{{.FieldType}} {
- if {{.ReceiverVar}} == nil {
- return {{.ZeroValue}}
- }
- return {{.ReceiverVar}}.{{.FieldName}}
-}
-{{else}}
-// Get{{.FieldName}} returns the {{.FieldName}} field if it's non-nil, zero value otherwise.
-func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() {{.FieldType}} {
- if {{.ReceiverVar}} == nil || {{.ReceiverVar}}.{{.FieldName}} == nil {
- return {{.ZeroValue}}
- }
- return *{{.ReceiverVar}}.{{.FieldName}}
-}
-{{end}}
-{{end}}
-`
command/agent.go+21 4
@@ -61,8 +61,9 @@ type AgentCommand struct {
startedCh chan (struct{}) // for tests
- flagConfigs []string
- flagLogLevel string
+ flagConfigs []string
+ flagLogLevel string
+ flagExitAfterAuth bool
flagTestVerifyOnly bool
flagCombineLogs bool
@@ -115,6 +116,15 @@ func (c *AgentCommand) Flags() *FlagSets {
"\"trace\", \"debug\", \"info\", \"warn\", and \"err\".",
})
+ f.BoolVar(&BoolVar{
+ Name: "exit-after-auth",
+ Target: &c.flagExitAfterAuth,
+ Default: false,
+ Usage: "If set to true, the agent will exit with code 0 after a single " +
+ "successful auth, where success means that a token was retrieved and " +
+ "all sinks successfully wrote it",
+ })
+
// Internal-only flags to follow.
//
// Why hello there little source code reader! Welcome to the Vault source
@@ -223,6 +233,13 @@ func (c *AgentCommand) Run(args []string) int {
config.Vault = new(agentConfig.Vault)
}
+ exitAfterAuth := config.ExitAfterAuth
+ f.Visit(func(fl *flag.Flag) {
+ if fl.Name == "exit-after-auth" {
+ exitAfterAuth = c.flagExitAfterAuth
+ }
+ })
+
c.setStringFlag(f, config.Vault.Address, &StringVar{
Name: flagNameAddress,
Target: &c.flagAddress,
@@ -524,7 +541,7 @@ func (c *AgentCommand) Run(args []string) int {
ss := sink.NewSinkServer(&sink.SinkServerConfig{
Logger: c.logger.Named("sink.server"),
Client: client,
- ExitAfterAuth: config.ExitAfterAuth,
+ ExitAfterAuth: exitAfterAuth,
})
ssDoneCh = ss.DoneCh
@@ -534,7 +551,7 @@ func (c *AgentCommand) Run(args []string) int {
LogWriter: c.logWriter,
VaultConf: config.Vault,
Namespace: namespace,
- ExitAfterAuth: config.ExitAfterAuth,
+ ExitAfterAuth: exitAfterAuth,
})
tsDoneCh = ts.DoneCh
builtin/credential/aws/path_config_client_test.go+19 1
@@ -44,6 +44,7 @@ func TestBackend_pathConfigClient(t *testing.T) {
data := map[string]interface{}{
"sts_endpoint": "https://my-custom-sts-endpoint.example.com",
+ "sts_region": "us-east-2",
"iam_server_id_header_value": "vault_server_identification_314159",
}
resp, err = b.HandleRequest(context.Background(), &logical.Request{
@@ -52,7 +53,6 @@ func TestBackend_pathConfigClient(t *testing.T) {
Data: data,
Storage: storage,
})
-
if err != nil {
t.Fatal(err)
}
@@ -75,8 +75,18 @@ func TestBackend_pathConfigClient(t *testing.T) {
t.Fatalf("expected iam_server_id_header_value: '%#v'; returned iam_server_id_header_value: '%#v'",
data["iam_server_id_header_value"], resp.Data["iam_server_id_header_value"])
}
+ if resp.Data["sts_endpoint"] != data["sts_endpoint"] {
+ t.Fatalf("expected sts_endpoint: '%#v'; returned sts_endpoint: '%#v'",
+ data["sts_endpoint"], resp.Data["sts_endpoint"])
+ }
+ if resp.Data["sts_region"] != data["sts_region"] {
+ t.Fatalf("expected sts_region: '%#v'; returned sts_region: '%#v'",
+ data["sts_region"], resp.Data["sts_region"])
+ }
data = map[string]interface{}{
+ "sts_endpoint": "https://my-custom-sts-endpoint2.example.com",
+ "sts_region": "us-west-1",
"iam_server_id_header_value": "vault_server_identification_2718281",
}
resp, err = b.HandleRequest(context.Background(), &logical.Request{
@@ -108,4 +118,12 @@ func TestBackend_pathConfigClient(t *testing.T) {
t.Fatalf("expected iam_server_id_header_value: '%#v'; returned iam_server_id_header_value: '%#v'",
data["iam_server_id_header_value"], resp.Data["iam_server_id_header_value"])
}
+ if resp.Data["sts_endpoint"] != data["sts_endpoint"] {
+ t.Fatalf("expected sts_endpoint: '%#v'; returned sts_endpoint: '%#v'",
+ data["sts_endpoint"], resp.Data["sts_endpoint"])
+ }
+ if resp.Data["sts_region"] != data["sts_region"] {
+ t.Fatalf("expected sts_region: '%#v'; returned sts_region: '%#v'",
+ data["sts_region"], resp.Data["sts_region"])
+ }
}
command/agent_test.go+40 11
@@ -225,6 +225,16 @@ cache {
*/
func TestAgent_ExitAfterAuth(t *testing.T) {
+ t.Run("via_config", func(t *testing.T) {
+ testAgentExitAfterAuth(t, false)
+ })
+
+ t.Run("via_flag", func(t *testing.T) {
+ testAgentExitAfterAuth(t, true)
+ })
+}
+
+func testAgentExitAfterAuth(t *testing.T, viaFlag bool) {
logger := logging.NewVaultLogger(hclog.Trace)
coreConfig := &vault.CoreConfig{
Logger: logger,
@@ -313,8 +323,13 @@ func TestAgent_ExitAfterAuth(t *testing.T) {
logger.Trace("wrote test jwt", "path", in)
}
+ exitAfterAuthTemplText := "exit_after_auth = true"
+ if viaFlag {
+ exitAfterAuthTemplText = ""
+ }
+
config := `
-exit_after_auth = true
+%s
auto_auth {
method {
@@ -340,23 +355,37 @@ auto_auth {
}
`
- config = fmt.Sprintf(config, in, sink1, sink2)
+ config = fmt.Sprintf(config, exitAfterAuthTemplText, in, sink1, sink2)
if err := ioutil.WriteFile(conf, []byte(config), 0600); err != nil {
t.Fatal(err)
} else {
logger.Trace("wrote test config", "path", conf)
}
- // If this hangs forever until the test times out, exit-after-auth isn't
- // working
- ui, cmd := testAgentCommand(t, logger)
- cmd.client = client
+ doneCh := make(chan struct{})
+ go func() {
+ ui, cmd := testAgentCommand(t, logger)
+ cmd.client = client
- code := cmd.Run([]string{"-config", conf})
- if code != 0 {
- t.Errorf("expected %d to be %d", code, 0)
- t.Logf("output from agent:\n%s", ui.OutputWriter.String())
- t.Logf("error from agent:\n%s", ui.ErrorWriter.String())
+ args := []string{"-config", conf}
+ if viaFlag {
+ args = append(args, "-exit-after-auth")
+ }
+
+ code := cmd.Run(args)
+ if code != 0 {
+ t.Errorf("expected %d to be %d", code, 0)
+ t.Logf("output from agent:\n%s", ui.OutputWriter.String())
+ t.Logf("error from agent:\n%s", ui.ErrorWriter.String())
+ }
+ close(doneCh)
+ }()
+
+ select {
+ case <-doneCh:
+ break
+ case <-time.After(1 * time.Minute):
+ t.Fatal("timeout reached while waiting for agent to exit")
}
sink1Bytes, err := ioutil.ReadFile(sink1)
(#7909) (#7982)
builtin/credential/ldap/backend_test.go | 6 +++
helper/testhelpers/ldap/ldaphelper.go | 1 +
sdk/helper/ldaputil/client.go | 9 +++-
sdk/helper/ldaputil/config.go | 11 +++++
sdk/helper/ldaputil/config_test.go | 43 ++++++++++++-------
sdk/helper/ldaputil/connection.go | 2 +
.../vault/sdk/helper/ldaputil/client.go | 9 +++-
.../vault/sdk/helper/ldaputil/config.go | 11 +++++
.../vault/sdk/helper/ldaputil/connection.go | 2 +
.../vault/sdk/helper/tlsutil/tlsutil.go | 3 ++
10 files changed, 80 insertions(+), 17 deletions(-)
builtin/credential/aws/path_role_test.go+87 0
@@ -2,11 +2,14 @@ package awsauth
import (
"context"
+ "os"
"reflect"
"strings"
"testing"
"github.com/go-test/deep"
+ "github.com/hashicorp/vault/helper/awsutil"
+ vlttesting "github.com/hashicorp/vault/helper/testhelpers/logical"
"github.com/hashicorp/vault/sdk/helper/policyutil"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/hashicorp/vault/sdk/logical"
@@ -986,6 +989,90 @@ func TestAwsVersion(t *testing.T) {
}
}
+// This test was used to reproduce https://github.com/hashicorp/vault/issues/7418
+// and verify its fix.
+// Please run it at least 3 times to ensure that passing tests are due to actually
+// passing, rather than the region being randomly chosen tying to the one in the
+// test through luck.
+func TestRoleResolutionWithSTSEndpointConfigured(t *testing.T) {
+ if enabled := os.Getenv(vlttesting.TestEnvVar); enabled == "" {
+ t.Skip()
+ }
+
+ /* ARN of an AWS role that Vault can query during testing.
+ This role should exist in your current AWS account and your credentials
+ should have iam:GetRole permissions to query it.
+ */
+ assumableRoleArn := os.Getenv("AWS_ASSUMABLE_ROLE_ARN")
+ if assumableRoleArn == "" {
+ t.Skip("skipping because AWS_ASSUMABLE_ROLE_ARN is unset")
+ }
+
+ // Ensure aws credentials are available locally for testing.
+ credsConfig := &awsutil.CredentialsConfig{}
+ credsChain, err := credsConfig.GenerateCredentialChain()
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = credsChain.Get()
+ if err != nil {
+ t.SkipNow()
+ }
+
+ config := logical.TestBackendConfig()
+ storage := &logical.InmemStorage{}
+ config.StorageView = storage
+
+ b, err := Backend(config)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = b.Setup(context.Background(), config)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // configure the client with an sts endpoint that should be used in creating the role
+ data := map[string]interface{}{
+ "sts_endpoint": "https://sts.eu-west-1.amazonaws.com",
+ // Note - if you comment this out, you can reproduce the error shown
+ // in the linked GH issue above. This essentially reproduces the problem
+ // we had when we didn't have an sts_region field.
+ "sts_region": "eu-west-1",
+ }
+ resp, err := b.HandleRequest(context.Background(), &logical.Request{
+ Operation: logical.CreateOperation,
+ Path: "config/client",
+ Data: data,
+ Storage: storage,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp != nil && resp.IsError() {
+ t.Fatalf("failed to create the role entry; resp: %#v", resp)
+ }
+
+ data = map[string]interface{}{
+ "auth_type": iamAuthType,
+ "bound_iam_principal_arn": assumableRoleArn,
+ "resolve_aws_unique_ids": true,
+ }
+ resp, err = b.HandleRequest(context.Background(), &logical.Request{
+ Operation: logical.CreateOperation,
+ Path: "role/MyRoleName",
+ Data: data,
+ Storage: storage,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp != nil && resp.IsError() {
+ t.Fatalf("failed to create the role entry; resp: %#v", resp)
+ }
+}
+
func resolveArnToFakeUniqueId(_ context.Context, _ logical.Storage, _ string) (string, error) {
return "FakeUniqueId1", nil
}
(#8043)
vault/identity_store.go | 4 +-
vault/identity_store_oidc.go | 135 ++++++++++++++++++++++++------
vault/identity_store_oidc_test.go | 32 +++++--
3 files changed, 138 insertions(+), 33 deletions(-)
ui/app/models/secret.js+6 0
@@ -13,6 +13,12 @@ export default DS.Model.extend(KeyMixin, {
renewable: attr('boolean'),
secretData: attr('object'),
+ secretKeyAndValue: computed('secretData', function() {
+ const data = this.get('secretData');
+ return Object.keys(data).map(key => {
+ return { key, value: data[key] };
+ });
+ }),
dataAsJSONString: computed('secretData', function() {
return JSON.stringify(this.get('secretData'), null, 2);
vault/identity_store_oidc.go+108 27
@@ -8,6 +8,7 @@ import (
"crypto/rsa"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"net/url"
"strings"
@@ -90,6 +91,8 @@ type oidcCache struct {
c *cache.Cache
}
+var errNilNamespace = errors.New("nil namespace in oidc cache request")
+
const (
issuerPath = "identity/oidc"
oidcTokensPrefix = "oidc_tokens/"
@@ -111,7 +114,7 @@ var supportedAlgs = []string{
}
// pseudo-namespace for cache items that don't belong to any real namespace.
-var nilNamespace = &namespace.Namespace{ID: "__NIL_NAMESPACE"}
+var noNamespace = &namespace.Namespace{ID: "__NO_NAMESPACE"}
func oidcPaths(i *IdentityStore) []*framework.Path {
return []*framework.Path{
@@ -370,7 +373,9 @@ func (i *IdentityStore) pathOIDCUpdateConfig(ctx context.Context, req *logical.R
return nil, err
}
- i.oidcCache.Flush(ns)
+ if err := i.oidcCache.Flush(ns); err != nil {
+ return nil, err
+ }
return resp, nil
}
@@ -381,7 +386,12 @@ func (i *IdentityStore) getOIDCConfig(ctx context.Context, s logical.Storage) (*
return nil, err
}
- if v, ok := i.oidcCache.Get(ns, "config"); ok {
+ v, ok, err := i.oidcCache.Get(ns, "config")
+ if err != nil {
+ return nil, err
+ }
+
+ if ok {
return v.(*oidcConfig), nil
}
@@ -404,7 +414,9 @@ func (i *IdentityStore) getOIDCConfig(ctx context.Context, s logical.Storage) (*
c.effectiveIssuer += "/v1/" + ns.Path + issuerPath
- i.oidcCache.SetDefault(ns, "config", &c)
+ if err := i.oidcCache.SetDefault(ns, "config", &c); err != nil {
+ return nil, err
+ }
return &c, nil
}
@@ -416,8 +428,6 @@ func (i *IdentityStore) pathOIDCCreateUpdateKey(ctx context.Context, req *logica
return nil, err
}
- defer i.oidcCache.Flush(ns)
-
name := d.Get("name").(string)
i.oidcLock.Lock()
@@ -494,6 +504,10 @@ func (i *IdentityStore) pathOIDCCreateUpdateKey(ctx context.Context, req *logica
}
}
+ if err := i.oidcCache.Flush(ns); err != nil {
+ return nil, err
+ }
+
// store named key
entry, err := logical.StorageEntryJSON(namedKeyConfigPath+name, key)
if err != nil {
@@ -590,7 +604,9 @@ func (i *IdentityStore) pathOIDCDeleteKey(ctx context.Context, req *logical.Requ
return nil, err
}
- i.oidcCache.Flush(ns)
+ if err := i.oidcCache.Flush(ns); err != nil {
+ return nil, err
+ }
return nil, nil
}
@@ -645,7 +661,9 @@ func (i *IdentityStore) pathOIDCRotateKey(ctx context.Context, req *logical.Requ
return nil, err
}
- i.oidcCache.Flush(ns)
+ if err := i.oidcCache.Flush(ns); err != nil {
+ return nil, err
+ }
return nil, nil
}
@@ -683,7 +701,12 @@ func (i *IdentityStore) pathOIDCGenerateToken(ctx context.Context, req *logical.
var key *namedKey
- if keyRaw, found := i.oidcCache.Get(ns, "namedKeys/"+role.Key); found {
+ keyRaw, found, err := i.oidcCache.Get(ns, "namedKeys/"+role.Key)
+ if err != nil {
+ return nil, err
+ }
+
+ if found {
key = keyRaw.(*namedKey)
} else {
entry, _ := req.Storage.Get(ctx, namedKeyConfigPath+role.Key)
@@ -695,7 +718,9 @@ func (i *IdentityStore) pathOIDCGenerateToken(ctx context.Context, req *logical.
return nil, err
}
- i.oidcCache.SetDefault(ns, "namedKeys/"+role.Key, key)
+ if err := i.oidcCache.SetDefault(ns, "namedKeys/"+role.Key, key); err != nil {
+ return nil, err
+ }
}
// Validate that the role is allowed to sign with its key (the key could have been updated)
if !strutil.StrListContains(key.AllowedClientIDs, "*") && !strutil.StrListContains(key.AllowedClientIDs, role.ClientID) {
@@ -923,7 +948,10 @@ func (i *IdentityStore) pathOIDCCreateUpdateRole(ctx context.Context, req *logic
return nil, err
}
- i.oidcCache.Flush(ns)
+ if err := i.oidcCache.Flush(ns); err != nil {
+ return nil, err
+ }
+
return nil, nil
}
@@ -994,7 +1022,12 @@ func (i *IdentityStore) pathOIDCDiscovery(ctx context.Context, req *logical.Requ
return nil, err
}
- if v, ok := i.oidcCache.Get(ns, "discoveryResponse"); ok {
+ v, ok, err := i.oidcCache.Get(ns, "discoveryResponse")
+ if err != nil {
+ return nil, err
+ }
+
+ if ok {
data = v.([]byte)
} else {
c, err := i.getOIDCConfig(ctx, req.Storage)
@@ -1015,7 +1048,9 @@ func (i *IdentityStore) pathOIDCDiscovery(ctx context.Context, req *logical.Requ
return nil, err
}
- i.oidcCache.SetDefault(ns, "discoveryResponse", data)
+ if err := i.oidcCache.SetDefault(ns, "discoveryResponse", data); err != nil {
+ return nil, err
+ }
}
resp := &logical.Response{
@@ -1040,7 +1075,12 @@ func (i *IdentityStore) pathOIDCReadPublicKeys(ctx context.Context, req *logical
return nil, err
}
- if v, ok := i.oidcCache.Get(ns, "jwksResponse"); ok {
+ v, ok, err := i.oidcCache.Get(ns, "jwksResponse")
+ if err != nil {
+ return nil, err
+ }
+
+ if ok {
data = v.([]byte)
} else {
jwks, err := i.generatePublicJWKS(ctx, req.Storage)
@@ -1053,7 +1093,9 @@ func (i *IdentityStore) pathOIDCReadPublicKeys(ctx context.Context, req *logical
return nil, err
}
- i.oidcCache.SetDefault(ns, "jwksResponse", data)
+ if err := i.oidcCache.SetDefault(ns, "jwksResponse", data); err != nil {
+ return nil, err
+ }
}
resp := &logical.Response{
@@ -1072,7 +1114,12 @@ func (i *IdentityStore) pathOIDCReadPublicKeys(ctx context.Context, req *logical
return nil, err
}
if len(keys) > 0 {
- if v, ok := i.oidcCache.Get(nilNamespace, "nextRun"); ok {
+ v, ok, err := i.oidcCache.Get(noNamespace, "nextRun")
+ if err != nil {
+ return nil, err
+ }
+
+ if ok {
now := time.Now()
expireAt := v.(time.Time)
if expireAt.After(now) {
@@ -1311,7 +1358,12 @@ func (i *IdentityStore) generatePublicJWKS(ctx context.Context, s logical.Storag
return nil, err
}
- if jwksRaw, ok := i.oidcCache.Get(ns, "jwks"); ok {
+ jwksRaw, ok, err := i.oidcCache.Get(ns, "jwks")
+ if err != nil {
+ return nil, err
+ }
+
+ if ok {
return jwksRaw.(*jose.JSONWebKeySet), nil
}
@@ -1336,7 +1388,9 @@ func (i *IdentityStore) generatePublicJWKS(ctx context.Context, s logical.Storag
jwks.Keys = append(jwks.Keys, *key)
}
- i.oidcCache.SetDefault(ns, "jwks", jwks)
+ if err := i.oidcCache.SetDefault(ns, "jwks", jwks); err != nil {
+ return nil, err
+ }
return jwks, nil
}
@@ -1435,7 +1489,9 @@ func (i *IdentityStore) expireOIDCPublicKeys(ctx context.Context, s logical.Stor
}
if didUpdate {
- i.oidcCache.Flush(ns)
+ if err := i.oidcCache.Flush(ns); err != nil {
+ i.Logger().Error("error flushing oidc cache", "error", err)
+ }
}
return nextExpiration, nil
@@ -1501,7 +1557,13 @@ func (i *IdentityStore) oidcPeriodicFunc(ctx context.Context) {
nsPaths := i.listNamespacePaths()
- if v, ok := i.oidcCache.Get(nilNamespace, "nextRun"); ok {
+ v, ok, err := i.oidcCache.Get(noNamespace, "nextRun")
+ if err != nil {
+ i.Logger().Error("error reading oidc cache", "err", err)
+ return
+ }
+
+ if ok {
nextRun = v.(time.Time)
}
@@ -1531,7 +1593,9 @@ func (i *IdentityStore) oidcPeriodicFunc(ctx context.Context) {
i.Logger().Warn("error expiring OIDC public keys", "err", err)
}
- i.oidcCache.Flush(nilNamespace)
+ if err := i.oidcCache.Flush(noNamespace); err != nil {
+ i.Logger().Error("error flushing oidc cache", "err", err)
+ }
// re-run at the soonest expiration or rotation time
if nextRotation.Before(nextRun) {
@@ -1542,7 +1606,9 @@ func (i *IdentityStore) oidcPeriodicFunc(ctx context.Context) {
nextRun = nextExpiration
}
}
- i.oidcCache.SetDefault(nilNamespace, "nextRun", nextRun)
+ if err := i.oidcCache.SetDefault(noNamespace, "nextRun", nextRun); err != nil {
+ i.Logger().Error("error setting oidc cache", "err", err)
+ }
}
}
@@ -1556,20 +1622,35 @@ func (c *oidcCache) nskey(ns *namespace.Namespace, key string) string {
return fmt.Sprintf("v0:%s:%s", ns.ID, key)
}
-func (c *oidcCache) Get(ns *namespace.Namespace, key string) (interface{}, bool) {
- return c.c.Get(c.nskey(ns, key))
+func (c *oidcCache) Get(ns *namespace.Namespace, key string) (interface{}, bool, error) {
+ if ns == nil {
+ return nil, false, errNilNamespace
+ }
+ v, found := c.c.Get(c.nskey(ns, key))
+ return v, found, nil
}
-func (c *oidcCache) SetDefault(ns *namespace.Namespace, key string, obj interface{}) {
+func (c *oidcCache) SetDefault(ns *namespace.Namespace, key string, obj interface{}) error {
+ if ns == nil {
+ return errNilNamespace
+ }
c.c.SetDefault(c.nskey(ns, key), obj)
+
+ return nil
}
-func (c *oidcCache) Flush(ns *namespace.Namespace) {
+func (c *oidcCache) Flush(ns *namespace.Namespace) error {
+ if ns == nil {
+ return errNilNamespace
+ }
+
for itemKey := range c.c.Items() {
- if isTargetNamespacedKey(itemKey, []string{nilNamespace.ID, ns.ID}) {
+ if isTargetNamespacedKey(itemKey, []string{noNamespace.ID, ns.ID}) {
c.c.Delete(itemKey)
}
}
+
+ return nil
}
// isTargetNamespacedKey returns true for a properly constructed namespaced key (<version>:<nsID>:<key>)
plugins/database/mysql/mysql_test.go+44 73
@@ -3,69 +3,22 @@ package mysql
import (
"context"
"database/sql"
- "fmt"
- "os"
"strings"
"testing"
"time"
stdmysql "github.com/go-sql-driver/mysql"
- "github.com/hashicorp/vault/helper/testhelpers/docker"
+ mysqlhelper "github.com/hashicorp/vault/helper/testhelpers/mysql"
"github.com/hashicorp/vault/sdk/database/dbplugin"
"github.com/hashicorp/vault/sdk/database/helper/credsutil"
"github.com/hashicorp/vault/sdk/database/helper/dbutil"
"github.com/hashicorp/vault/sdk/helper/strutil"
- "github.com/ory/dockertest"
)
var _ dbplugin.Database = (*MySQL)(nil)
-func prepareMySQLTestContainer(t *testing.T, legacy bool) (cleanup func(), retURL string) {
- if os.Getenv("MYSQL_URL") != "" {
- return func() {}, os.Getenv("MYSQL_URL")
- }
-
- pool, err := dockertest.NewPool("")
- if err != nil {
- t.Fatalf("Failed to connect to docker: %s", err)
- }
-
- imageVersion := "5.7"
- if legacy {
- imageVersion = "5.6"
- }
-
- resource, err := pool.Run("mysql", imageVersion, []string{"MYSQL_ROOT_PASSWORD=secret"})
- if err != nil {
- t.Fatalf("Could not start local MySQL docker container: %s", err)
- }
-
- cleanup = func() {
- docker.CleanupResource(t, pool, resource)
- }
-
- retURL = fmt.Sprintf("root:secret@(localhost:%s)/mysql?parseTime=true", resource.GetPort("3306/tcp"))
-
- // exponential backoff-retry
- if err = pool.Retry(func() error {
- var err error
- var db *sql.DB
- db, err = sql.Open("mysql", retURL)
- if err != nil {
- return err
- }
- defer db.Close()
- return db.Ping()
- }); err != nil {
- cleanup()
- t.Fatalf("Could not connect to MySQL docker container: %s", err)
- }
-
- return
-}
-
func TestMySQL_Initialize(t *testing.T) {
- cleanup, connURL := prepareMySQLTestContainer(t, false)
+ cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret")
defer cleanup()
connectionDetails := map[string]interface{}{
@@ -100,7 +53,7 @@ func TestMySQL_Initialize(t *testing.T) {
}
func TestMySQL_CreateUser(t *testing.T) {
- cleanup, connURL := prepareMySQLTestContainer(t, false)
+ cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret")
defer cleanup()
connectionDetails := map[string]interface{}{
@@ -133,7 +86,7 @@ func TestMySQL_CreateUser(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
@@ -143,7 +96,7 @@ func TestMySQL_CreateUser(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
@@ -155,14 +108,14 @@ func TestMySQL_CreateUser(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
}
func TestMySQL_CreateUser_Legacy(t *testing.T) {
- cleanup, connURL := prepareMySQLTestContainer(t, true)
+ cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, true, "secret")
defer cleanup()
connectionDetails := map[string]interface{}{
@@ -195,7 +148,7 @@ func TestMySQL_CreateUser_Legacy(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
@@ -205,13 +158,13 @@ func TestMySQL_CreateUser_Legacy(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
}
func TestMySQL_RotateRootCredentials(t *testing.T) {
- cleanup, connURL := prepareMySQLTestContainer(t, false)
+ cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret")
defer cleanup()
connURL = strings.Replace(connURL, "root:secret", `{{username}}:{{password}}`, -1)
@@ -247,7 +200,7 @@ func TestMySQL_RotateRootCredentials(t *testing.T) {
}
func TestMySQL_RevokeUser(t *testing.T) {
- cleanup, connURL := prepareMySQLTestContainer(t, false)
+ cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret")
defer cleanup()
connectionDetails := map[string]interface{}{
@@ -274,7 +227,7 @@ func TestMySQL_RevokeUser(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
@@ -284,7 +237,7 @@ func TestMySQL_RevokeUser(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err == nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err == nil {
t.Fatal("Credentials were not revoked")
}
@@ -294,7 +247,7 @@ func TestMySQL_RevokeUser(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
@@ -305,19 +258,19 @@ func TestMySQL_RevokeUser(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, username, password); err == nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, username, password); err == nil {
t.Fatal("Credentials were not revoked")
}
}
func TestMySQL_SetCredentials(t *testing.T) {
- cleanup, connURL := prepareMySQLTestContainer(t, false)
+ cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, "secret")
defer cleanup()
// create the database user and verify we can access
dbUser := "vaultstatictest"
createTestMySQLUser(t, connURL, dbUser, "password", testRoleStaticCreate)
- if err := testCredsExist(t, connURL, dbUser, "password"); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, "password"); err != nil {
t.Fatalf("Could not connect with credentials: %s", err)
}
@@ -351,7 +304,7 @@ func TestMySQL_SetCredentials(t *testing.T) {
}
// verify new password works
- if err := testCredsExist(t, connURL, dbUser, newPassword); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, newPassword); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
@@ -363,20 +316,38 @@ func TestMySQL_SetCredentials(t *testing.T) {
t.Fatalf("err: %s", err)
}
- if err := testCredsExist(t, connURL, dbUser, newPassword); err != nil {
+ if err := mysqlhelper.TestCredsExist(t, connURL, dbUser, newPassword); err != nil {
t.Fatalf("Could not connect with new credentials: %s", err)
}
}
-func testCredsExist(t testing.TB, connURL, username, password string) error {
- // Log in with the new creds
- connURL = strings.Replace(connURL, "root:secret", fmt.Sprintf("%s:%s", username, password), 1)
- db, err := sql.Open("mysql", connURL)
+func TestMySQL_Initialize_ReservedChars(t *testing.T) {
+ pw := "#secret!%25#{@}"
+ cleanup, connURL := mysqlhelper.PrepareMySQLTestContainer(t, false, pw)
+ defer cleanup()
+
+ // Revert password set to test replacement by db.Init
+ connURL = strings.ReplaceAll(connURL, pw, "{{password}}")
+
+ connectionDetails := map[string]interface{}{
+ "connection_url": connURL,
+ "password": pw,
+ }
+
+ db := new(MetadataLen, MetadataLen, UsernameLen)
+ _, err := db.Init(context.Background(), connectionDetails, true)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ if !db.Initialized {
+ t.Fatal("Database should be initialized")
+ }
+
+ err = db.Close()
if err != nil {
- return err
+ t.Fatalf("err: %s", err)
}
- defer db.Close()
- return db.Ping()
}
func createTestMySQLUser(t *testing.T, connURL, username, password, query string) {
command/agent/template/template.go+42 1
@@ -50,6 +50,11 @@ type Server struct {
// Templates holds the parsed Consul Templates
Templates []*ctconfig.TemplateConfig
+ // lookupMap is alist of templates indexed by their consul-template ID. This
+ // is used to ensure all Vault templates have been rendered before returning
+ // from the runner in the event we're using exit after auth.
+ lookupMap map[string][]*ctconfig.TemplateConfig
+
DoneCh chan struct{}
logger hclog.Logger
exitAfterAuth bool
@@ -104,6 +109,23 @@ func (ts *Server) Run(ctx context.Context, incoming chan string, templates []*ct
return
}
+ // Build the lookup map using the id mapping from the Template runner. This is
+ // used to check the template rendering against the expected templates. This
+ // returns a map with a generated ID and a slice of templates for that id. The
+ // slice is determined by the source or contents of the template, so if a
+ // configuration has multiple templates specified, but are the same source /
+ // contents, they will be identified by the same key.
+ idMap := ts.runner.TemplateConfigMapping()
+ lookupMap := make(map[string][]*ctconfig.TemplateConfig, len(idMap))
+ for id, ctmpls := range idMap {
+ for _, ctmpl := range ctmpls {
+ tl := lookupMap[id]
+ tl = append(tl, ctmpl)
+ lookupMap[id] = tl
+ }
+ }
+ ts.lookupMap = lookupMap
+
for {
select {
case <-ctx.Done():
@@ -133,7 +155,26 @@ func (ts *Server) Run(ctx context.Context, incoming chan string, templates []*ct
ts.logger.Error("template server error", "error", err.Error())
return
case <-ts.runner.TemplateRenderedCh():
- if ts.exitAfterAuth {
+ // A template has been rendered, figure out what to do
+ events := ts.runner.RenderEvents()
+
+ // events are keyed by template ID, and can be matched up to the id's from
+ // the lookupMap
+ if len(events) < len(ts.lookupMap) {
+ // Not all templates have been rendered yet
+ continue
+ }
+
+ // assume the renders are finished, until we find otherwise
+ doneRendering := true
+ for _, event := range events {
+ // This template hasn't been rendered
+ if event.LastWouldRender.IsZero() {
+ doneRendering = false
+ }
+ }
+
+ if doneRendering && ts.exitAfterAuth {
// if we want to exit after auth, go ahead and shut down the runner and
// return. The deferred closing of the DoneCh will allow agent to
// continue with closing down
vendor/github.com/hashicorp/vault-plugin-auth-alicloud/go.sum+27 11
@@ -1,11 +1,15 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190412020505-60e2075261b6 h1:5RwdKFlGKokYBbq4M2ZZ0LzfxdK4e1L4rwQH+76wPkE=
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190412020505-60e2075261b6/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
+github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -13,7 +17,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
+github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
+github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31 h1:28FVBuwkwowZMjbA7M0wXsI6t3PYulRTMio3SO+eKCM=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
@@ -35,21 +40,24 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.8.0 h1:z3ollgGRg8RjfJH6UVBaG54R70GFd++QOkvnJH3VSBY=
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
-github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE=
-github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-retryablehttp v0.6.2 h1:bHM2aVXwBtBJWxHtkSrWuI4umABCUczs52eiUS9nSiw=
+github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY=
github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.2-0.20191001231223-f32f5fe8d6a8 h1:PKbxRbsOP7R3f/TpdqcgXrO69T3yd9nLoR+RMRUxSxA=
+github.com/hashicorp/go-uuid v1.0.2-0.20191001231223-f32f5fe8d6a8/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -57,10 +65,11 @@ github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hashicorp/vault/api v1.0.5-0.20190814205728-e9c5cd8aca98 h1:LUVHA+Z7zJ5Y+m5i7K8X1q0FIrn7AISU575IQ3/b/GE=
-github.com/hashicorp/vault/api v1.0.5-0.20190814205728-e9c5cd8aca98/go.mod h1:t4IAg1Is4bLUtTq8cGgeUh0I8oDRBXPk2bM1Jvg/nWA=
-github.com/hashicorp/vault/sdk v0.1.14-0.20190814205504-1cad00d1133b h1:uC3aN7xIG8gPNm9cbNY05OJ44cYfAv5Rn+QLSBsFq1s=
-github.com/hashicorp/vault/sdk v0.1.14-0.20190814205504-1cad00d1133b/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
+github.com/hashicorp/vault/api v1.0.5-0.20191216174727-9d51b36f3ae4 h1:cjUSHrjKpl7WyZPJOEb20gkU9e+AC53XOjN5r3MWryI=
+github.com/hashicorp/vault/api v1.0.5-0.20191216174727-9d51b36f3ae4/go.mod h1:Uf8LaHyrYsgVgHzO2tMZKhqRGlL3UJ6XaSwW2EA1Iqo=
+github.com/hashicorp/vault/sdk v0.1.14-0.20191108161836-82f2b5571044/go.mod h1:PcekaFGiPJyHnFy+NZhP6ll650zEw51Ag7g/YEa+EOU=
+github.com/hashicorp/vault/sdk v0.1.14-0.20191216174727-9d51b36f3ae4 h1:yJmmFHFLC9jU8STDxzUKeS9KC2SKHrDSFQbW/PzC70k=
+github.com/hashicorp/vault/sdk v0.1.14-0.20191216174727-9d51b36f3ae4/go.mod h1:PcekaFGiPJyHnFy+NZhP6ll650zEw51Ag7g/YEa+EOU=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
@@ -77,6 +86,7 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -97,9 +107,14 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
@@ -113,6 +128,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -121,6 +137,7 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
@@ -159,7 +176,6 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
More files changed — see the full commit.

Release delta 1.4.0 → 1.4.4 (contains the fix)

· Mar 30, 2020, 06:19 PM+8293906compare
sdk/helper/authmetadata/auth_metadata_acc_test.go+399 0
@@ -0,0 +1,477 @@
+package authmetadata
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "testing"
+
+ "github.com/hashicorp/go-hclog"
+ "github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/logical"
+)
+
+type environment struct {
+ ctx context.Context
+ storage logical.Storage
+ backend logical.Backend
+}
+
+func TestAcceptance(t *testing.T) {
+ ctx := context.Background()
+ storage := &logical.InmemStorage{}
+ b, err := backend(ctx, storage)
+ if err != nil {
+ t.Fatal(err)
+ }
+ env := &environment{
+ ctx: ctx,
+ storage: storage,
+ backend: b,
+ }
+ t.Run("test initial fields are default", env.TestInitialFieldsAreDefault)
+ t.Run("test fields can be unset", env.TestAuthMetadataCanBeUnset)
+ t.Run("test defaults can be restored", env.TestDefaultCanBeReused)
+ t.Run("test default plus more cannot be selected", env.TestDefaultPlusMoreCannotBeSelected)
+ t.Run("test only non-defaults can be selected", env.TestOnlyNonDefaultsCanBeSelected)
+ t.Run("test bad field results in useful error", env.TestAddingBadField)
+}
+
+func (e *environment) TestInitialFieldsAreDefault(t *testing.T) {
+ // On the first read of auth_metadata, when nothing has been touched,
+ // we should receive the default field(s) if a read is performed.
+ resp, err := e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.ReadOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp == nil || resp.Data == nil {
+ t.Fatal("expected non-nil response")
+ }
+ if !reflect.DeepEqual(resp.Data[authMetadataFields.FieldName], []string{"role_name"}) {
+ t.Fatal("expected default field of role_name to be returned")
+ }
+
+ // The auth should only have the default metadata.
+ resp, err = e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "login",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ "role_name": "something",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp == nil || resp.Auth == nil || resp.Auth.Alias == nil || resp.Auth.Alias.Metadata == nil {
+ t.Fatalf("expected alias metadata")
+ }
+ if len(resp.Auth.Alias.Metadata) != 1 {
+ t.Fatal("expected only 1 field")
+ }
+ if resp.Auth.Alias.Metadata["role_name"] != "something" {
+ t.Fatal("expected role_name to be something")
+ }
+}
+
+func (e *environment) TestAuthMetadataCanBeUnset(t *testing.T) {
+ // We should be able to set the auth_metadata to empty by sending an
+ // explicitly empty array.
+ resp, err := e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ authMetadataFields.FieldName: []string{},
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp != nil {
+ t.Fatal("expected nil response")
+ }
+
+ // Now we should receive no fields for auth_metadata.
+ resp, err = e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.ReadOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp == nil || resp.Data == nil {
+ t.Fatal("expected non-nil response")
+ }
+ if !reflect.DeepEqual(resp.Data[authMetadataFields.FieldName], []string{}) {
+ t.Fatal("expected no fields to be returned")
+ }
+
+ // The auth should have no metadata.
+ resp, err = e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "login",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ "role_name": "something",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp == nil || resp.Auth == nil || resp.Auth.Alias == nil || resp.Auth.Alias.Metadata == nil {
+ t.Fatal("expected alias metadata")
+ }
+ if len(resp.Auth.Alias.Metadata) != 0 {
+ t.Fatal("expected 0 fields")
+ }
+}
+
+func (e *environment) TestDefaultCanBeReused(t *testing.T) {
+ // Now if we set it to "default", the default fields should
+ // be restored.
+ resp, err := e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ authMetadataFields.FieldName: []string{"default"},
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp != nil {
+ t.Fatal("expected nil response")
+ }
+
+ // Let's make sure we've returned to the default fields.
+ resp, err = e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.ReadOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp == nil || resp.Data == nil {
+ t.Fatal("expected non-nil response")
+ }
+ if !reflect.DeepEqual(resp.Data[authMetadataFields.FieldName], []string{"role_name"}) {
+ t.Fatal("expected default field of role_name to be returned")
+ }
+
+ // We should again only receive the default field on the login.
+ resp, err = e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "login",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ "role_name": "something",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp == nil || resp.Auth == nil || resp.Auth.Alias == nil || resp.Auth.Alias.Metadata == nil {
+ t.Fatal("expected alias metadata")
+ }
+ if len(resp.Auth.Alias.Metadata) != 1 {
+ t.Fatal("expected only 1 field")
+ }
+ if resp.Auth.Alias.Metadata["role_name"] != "something" {
+ t.Fatal("expected role_name to be something")
+ }
+}
+
+func (e *environment) TestDefaultPlusMoreCannotBeSelected(t *testing.T) {
+ // We should not be able to set it to "default" plus 1 optional field.
+ _, err := e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ authMetadataFields.FieldName: []string{"default", "remote_addr"},
+ },
+ })
+ if err == nil {
+ t.Fatal("expected err")
+ }
+}
+
+func (e *environment) TestOnlyNonDefaultsCanBeSelected(t *testing.T) {
+ // Omit all default fields and just select one.
+ resp, err := e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ authMetadataFields.FieldName: []string{"remote_addr"},
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp != nil {
+ t.Fatal("expected nil response")
+ }
+
+ // Make sure that worked.
+ resp, err = e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.ReadOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp == nil || resp.Data == nil {
+ t.Fatal("expected non-nil response")
+ }
+ if !reflect.DeepEqual(resp.Data[authMetadataFields.FieldName], []string{"remote_addr"}) {
+ t.Fatal("expected remote_addr to be returned")
+ }
+
+ // Ensure only the selected one is on logins.
+ // They both should now appear on the login.
+ resp, err = e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "login",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ "role_name": "something",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp == nil || resp.Auth == nil || resp.Auth.Alias == nil || resp.Auth.Alias.Metadata == nil {
+ t.Fatal("expected alias metadata")
+ }
+ if len(resp.Auth.Alias.Metadata) != 1 {
+ t.Fatal("expected only 1 field")
+ }
+ if resp.Auth.Alias.Metadata["remote_addr"] != "http://foo.com" {
+ t.Fatal("expected remote_addr to be http://foo.com")
+ }
+}
+
+func (e *environment) TestAddingBadField(t *testing.T) {
+ // Try adding an unsupported field.
+ resp, err := e.backend.HandleRequest(e.ctx, &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config",
+ Storage: e.storage,
+ Connection: &logical.Connection{
+ RemoteAddr: "http://foo.com",
+ },
+ Data: map[string]interface{}{
+ authMetadataFields.FieldName: []string{"asl;dfkj"},
+ },
+ })
+ if err == nil {
+ t.Fatal("expected err")
+ }
+ if resp == nil {
+ t.Fatal("expected non-nil response")
+ }
+ if !resp.IsError() {
+ t.Fatal("expected error response")
+ }
+}
+
+// We expect people to embed the Handler on their
+// config so it automatically makes its helper methods
+// available and easy to find wherever the config is
+// needed. Explicitly naming it in json avoids it
+// automatically being named "Handler" by Go's JSON
+// marshalling library.
+type fakeConfig struct {
+ *Handler `json:"auth_metadata_handler"`
+}
+
+type fakeBackend struct {
+ *framework.Backend
+}
+
+// We expect each back-end to explicitly define the fields that
+// will be included by default, and optionally available.
+var authMetadataFields = &Fields{
+ FieldName: "some_field_name",
+ Default: []string{
+ "role_name", // This would likely never change because the alias is the role name.
+ },
+ AvailableToAdd: []string{
+ "remote_addr", // This would likely change with every new caller.
+ },
+}
+
+func configPath() *framework.Path {
+ return &framework.Path{
+ Pattern: "config",
+ Fields: map[string]*framework.FieldSchema{
+ authMetadataFields.FieldName: FieldSchema(authMetadataFields),
+ },
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.ReadOperation: &framework.PathOperation{
+ Callback: func(ctx context.Context, req *logical.Request, fd *framework.FieldData) (*logical.Response, error) {
+ entryRaw, err := req.Storage.Get(ctx, "config")
+ if err != nil {
+ return nil, err
+ }
+ conf := &fakeConfig{
+ Handler: NewHandler(authMetadataFields),
+ }
+ if entryRaw != nil {
+ if err := entryRaw.DecodeJSON(conf); err != nil {
+ return nil, err
+ }
+ }
+ // Note that even if the config entry was nil, we return
+ // a populated response to give info on what the default
+ // auth metadata is when unconfigured.
+ return &logical.Response{
+ Data: map[string]interface{}{
+ authMetadataFields.FieldName: conf.AuthMetadata(),
+ },
+ }, nil
+ },
+ },
+ logical.UpdateOperation: &framework.PathOperation{
+ Callback: func(ctx context.Context, req *logical.Request, fd *framework.FieldData) (*logical.Response, error) {
+ entryRaw, err := req.Storage.Get(ctx, "config")
+ if err != nil {
+ return nil, err
+ }
+ conf := &fakeConfig{
+ Handler: NewHandler(authMetadataFields),
+ }
+ if entryRaw != nil {
+ if err := entryRaw.DecodeJSON(conf); err != nil {
+ return nil, err
+ }
+ }
+ // This is where we read in the user's given auth metadata.
+ if err := conf.ParseAuthMetadata(fd); err != nil {
+ // Since this will only error on bad input, it's best to give
+ // a 400 response with the explicit problem included.
+ return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
… diff truncated
sdk/helper/authmetadata/auth_metadata.go+200 0
@@ -0,0 +1,200 @@
+package authmetadata
+
+/*
+ authmetadata is a package offering convenience and
+ standardization when supporting an `auth_metadata`
+ field in a plugin's configuration. This then controls
+ what metadata is added to an Auth during login.
+
+ To see an example of how to add and use it, check out
+ how these structs and fields are used in the AWS auth
+ method.
+
+ Or, check out its acceptance test in this package to
+ see its integration points.
+*/
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/helper/strutil"
+ "github.com/hashicorp/vault/sdk/logical"
+)
+
+// Fields is for configuring a back-end's available
+// default and additional fields. These are used for
+// providing a verbose field description, and for parsing
+// user input.
+type Fields struct {
+ // The field name as it'll be reflected in the user-facing
+ // schema.
+ FieldName string
+
+ // Default is a list of the default fields that should
+ // be included if a user sends "default" in their list
+ // of desired fields. These fields should all have a
+ // low rate of change because each change can incur a
+ // write to storage.
+ Default []string
+
+ // AvailableToAdd is a list of fields not included by
+ // default, that the user may include.
+ AvailableToAdd []string
+}
+
+func (f *Fields) all() []string {
+ return append(f.Default, f.AvailableToAdd...)
+}
+
+// FieldSchema takes the default and additionally available
+// fields, and uses them to generate a verbose description
+// regarding how to use the "auth_metadata" field.
+func FieldSchema(fields *Fields) *framework.FieldSchema {
+ return &framework.FieldSchema{
+ Type: framework.TypeCommaStringSlice,
+ Description: description(fields),
+ DisplayAttrs: &framework.DisplayAttributes{
+ Name: fields.FieldName,
+ Value: "field1,field2",
+ },
+ Default: []string{"default"},
+ }
+}
+
+func NewHandler(fields *Fields) *Handler {
+ return &Handler{
+ fields: fields,
+ }
+}
+
+type Handler struct {
+ // authMetadata is an explicit list of all the user's configured
+ // fields that are being added to auth metadata. If it is set to
+ // default or unconfigured, it will be nil. Otherwise, it will
+ // hold the explicit fields set by the user.
+ authMetadata []string
+
+ // fields is a list of the configured default and available
+ // fields.
+ fields *Fields
+}
+
+// AuthMetadata is intended to be used on config reads.
+// It gets an explicit list of all the user's configured
+// fields that are being added to auth metadata.
+func (h *Handler) AuthMetadata() []string {
+ if h.authMetadata == nil {
+ return h.fields.Default
+ }
+ return h.authMetadata
+}
+
+// ParseAuthMetadata is intended to be used on config create/update.
+// It takes a user's selected fields (or lack thereof),
+// converts it to a list of explicit fields, and adds it to the Handler
+// for later storage.
+func (h *Handler) ParseAuthMetadata(data *framework.FieldData) error {
+ userProvidedRaw, ok := data.GetOk(h.fields.FieldName)
+ if !ok {
+ // Nothing further to do here.
+ return nil
+ }
+ userProvided, ok := userProvidedRaw.([]string)
+ if !ok {
+ return fmt.Errorf("%s is an unexpected type of %T", userProvidedRaw, userProvidedRaw)
+ }
+ userProvided = strutil.RemoveDuplicates(userProvided, true)
+
+ // If the only field the user has chosen was the default field,
+ // we don't store anything so we won't have to do a storage
+ // migration if the default changes.
+ if len(userProvided) == 1 && userProvided[0] == "default" {
+ h.authMetadata = nil
+ return nil
+ }
+
+ // Validate and store the input.
+ if strutil.StrListContains(userProvided, "default") {
+ return fmt.Errorf("%q contains default - default can't be used in combination with other fields",
+ userProvided)
+ }
+ if !strutil.StrListSubset(h.fields.all(), userProvided) {
+ return fmt.Errorf("%q contains an unavailable field, please select from %q",
+ strings.Join(userProvided, ", "), strings.Join(h.fields.all(), ", "))
+ }
+ h.authMetadata = userProvided
+ return nil
+}
+
+// PopulateDesiredMetadata is intended to be used during login
+// just before returning an auth.
+// It takes the available auth metadata and,
+// if the auth should have it, adds it to the auth's metadata.
+func (h *Handler) PopulateDesiredMetadata(auth *logical.Auth, available map[string]string) error {
+ if auth == nil {
+ return errors.New("auth is nil")
+ }
+ if auth.Metadata == nil {
+ auth.Metadata = make(map[string]string)
+ }
+ if auth.Alias == nil {
+ auth.Alias = &logical.Alias{}
+ }
+ if auth.Alias.Metadata == nil {
+ auth.Alias.Metadata = make(map[string]string)
+ }
+ fieldsToInclude := h.fields.Default
+ if h.authMetadata != nil {
+ fieldsToInclude = h.authMetadata
+ }
+ for availableField, itsValue := range available {
+ if itsValue == "" {
+ // Don't bother setting fields for which there is no value.
+ continue
+ }
+ if strutil.StrListContains(fieldsToInclude, availableField) {
+ auth.Metadata[availableField] = itsValue
+ auth.Alias.Metadata[availableField] = itsValue
+ }
+ }
+ return nil
+}
+
+func (h *Handler) MarshalJSON() ([]byte, error) {
+ return json.Marshal(&struct {
+ AuthMetadata []string `json:"auth_metadata"`
+ }{
+ AuthMetadata: h.authMetadata,
+ })
+}
+
+func (h *Handler) UnmarshalJSON(data []byte) error {
+ jsonable := &struct {
+ AuthMetadata []string `json:"auth_metadata"`
+ }{
+ AuthMetadata: h.authMetadata,
+ }
+ if err := json.Unmarshal(data, jsonable); err != nil {
+ return err
+ }
+ h.authMetadata = jsonable.AuthMetadata
+ return nil
+}
+
+func description(fields *Fields) string {
+ desc := "The metadata to include on the aliases and audit logs generated by this plugin."
+ if len(fields.Default) > 0 {
+ desc += fmt.Sprintf(" When set to 'default', includes: %s.", strings.Join(fields.Default, ", "))
+ }
+ if len(fields.AvailableToAdd) > 0 {
+ desc += fmt.Sprintf(" These fields are available to add: %s.", strings.Join(fields.AvailableToAdd, ", "))
+ }
+ desc += " Not editing this field means the 'default' fields are included." +
+ " Explicitly setting this field to empty overrides the 'default' and means no metadata will be included." +
+ " If not using 'default', explicit fields must be sent like: 'field1,field2'."
+ return desc
+}
vendor/github.com/hashicorp/vault/sdk/helper/authmetadata/auth_metadata.go+200 0
@@ -0,0 +1,200 @@
+package authmetadata
+
+/*
+ authmetadata is a package offering convenience and
+ standardization when supporting an `auth_metadata`
+ field in a plugin's configuration. This then controls
+ what metadata is added to an Auth during login.
+
+ To see an example of how to add and use it, check out
+ how these structs and fields are used in the AWS auth
+ method.
+
+ Or, check out its acceptance test in this package to
+ see its integration points.
+*/
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/helper/strutil"
+ "github.com/hashicorp/vault/sdk/logical"
+)
+
+// Fields is for configuring a back-end's available
+// default and additional fields. These are used for
+// providing a verbose field description, and for parsing
+// user input.
+type Fields struct {
+ // The field name as it'll be reflected in the user-facing
+ // schema.
+ FieldName string
+
+ // Default is a list of the default fields that should
+ // be included if a user sends "default" in their list
+ // of desired fields. These fields should all have a
+ // low rate of change because each change can incur a
+ // write to storage.
+ Default []string
+
+ // AvailableToAdd is a list of fields not included by
+ // default, that the user may include.
+ AvailableToAdd []string
+}
+
+func (f *Fields) all() []string {
+ return append(f.Default, f.AvailableToAdd...)
+}
+
+// FieldSchema takes the default and additionally available
+// fields, and uses them to generate a verbose description
+// regarding how to use the "auth_metadata" field.
+func FieldSchema(fields *Fields) *framework.FieldSchema {
+ return &framework.FieldSchema{
+ Type: framework.TypeCommaStringSlice,
+ Description: description(fields),
+ DisplayAttrs: &framework.DisplayAttributes{
+ Name: fields.FieldName,
+ Value: "field1,field2",
+ },
+ Default: []string{"default"},
+ }
+}
+
+func NewHandler(fields *Fields) *Handler {
+ return &Handler{
+ fields: fields,
+ }
+}
+
+type Handler struct {
+ // authMetadata is an explicit list of all the user's configured
+ // fields that are being added to auth metadata. If it is set to
+ // default or unconfigured, it will be nil. Otherwise, it will
+ // hold the explicit fields set by the user.
+ authMetadata []string
+
+ // fields is a list of the configured default and available
+ // fields.
+ fields *Fields
+}
+
+// AuthMetadata is intended to be used on config reads.
+// It gets an explicit list of all the user's configured
+// fields that are being added to auth metadata.
+func (h *Handler) AuthMetadata() []string {
+ if h.authMetadata == nil {
+ return h.fields.Default
+ }
+ return h.authMetadata
+}
+
+// ParseAuthMetadata is intended to be used on config create/update.
+// It takes a user's selected fields (or lack thereof),
+// converts it to a list of explicit fields, and adds it to the Handler
+// for later storage.
+func (h *Handler) ParseAuthMetadata(data *framework.FieldData) error {
+ userProvidedRaw, ok := data.GetOk(h.fields.FieldName)
+ if !ok {
+ // Nothing further to do here.
+ return nil
+ }
+ userProvided, ok := userProvidedRaw.([]string)
+ if !ok {
+ return fmt.Errorf("%s is an unexpected type of %T", userProvidedRaw, userProvidedRaw)
+ }
+ userProvided = strutil.RemoveDuplicates(userProvided, true)
+
+ // If the only field the user has chosen was the default field,
+ // we don't store anything so we won't have to do a storage
+ // migration if the default changes.
+ if len(userProvided) == 1 && userProvided[0] == "default" {
+ h.authMetadata = nil
+ return nil
+ }
+
+ // Validate and store the input.
+ if strutil.StrListContains(userProvided, "default") {
+ return fmt.Errorf("%q contains default - default can't be used in combination with other fields",
+ userProvided)
+ }
+ if !strutil.StrListSubset(h.fields.all(), userProvided) {
+ return fmt.Errorf("%q contains an unavailable field, please select from %q",
+ strings.Join(userProvided, ", "), strings.Join(h.fields.all(), ", "))
+ }
+ h.authMetadata = userProvided
+ return nil
+}
+
+// PopulateDesiredMetadata is intended to be used during login
+// just before returning an auth.
+// It takes the available auth metadata and,
+// if the auth should have it, adds it to the auth's metadata.
+func (h *Handler) PopulateDesiredMetadata(auth *logical.Auth, available map[string]string) error {
+ if auth == nil {
+ return errors.New("auth is nil")
+ }
+ if auth.Metadata == nil {
+ auth.Metadata = make(map[string]string)
+ }
+ if auth.Alias == nil {
+ auth.Alias = &logical.Alias{}
+ }
+ if auth.Alias.Metadata == nil {
+ auth.Alias.Metadata = make(map[string]string)
+ }
+ fieldsToInclude := h.fields.Default
+ if h.authMetadata != nil {
+ fieldsToInclude = h.authMetadata
+ }
+ for availableField, itsValue := range available {
+ if itsValue == "" {
+ // Don't bother setting fields for which there is no value.
+ continue
+ }
+ if strutil.StrListContains(fieldsToInclude, availableField) {
+ auth.Metadata[availableField] = itsValue
+ auth.Alias.Metadata[availableField] = itsValue
+ }
+ }
+ return nil
+}
+
+func (h *Handler) MarshalJSON() ([]byte, error) {
+ return json.Marshal(&struct {
+ AuthMetadata []string `json:"auth_metadata"`
+ }{
+ AuthMetadata: h.authMetadata,
+ })
+}
+
+func (h *Handler) UnmarshalJSON(data []byte) error {
+ jsonable := &struct {
+ AuthMetadata []string `json:"auth_metadata"`
+ }{
+ AuthMetadata: h.authMetadata,
+ }
+ if err := json.Unmarshal(data, jsonable); err != nil {
+ return err
+ }
+ h.authMetadata = jsonable.AuthMetadata
+ return nil
+}
+
+func description(fields *Fields) string {
+ desc := "The metadata to include on the aliases and audit logs generated by this plugin."
+ if len(fields.Default) > 0 {
+ desc += fmt.Sprintf(" When set to 'default', includes: %s.", strings.Join(fields.Default, ", "))
+ }
+ if len(fields.AvailableToAdd) > 0 {
+ desc += fmt.Sprintf(" These fields are available to add: %s.", strings.Join(fields.AvailableToAdd, ", "))
+ }
+ desc += " Not editing this field means the 'default' fields are included." +
+ " Explicitly setting this field to empty overrides the 'default' and means no metadata will be included." +
+ " If not using 'default', explicit fields must be sent like: 'field1,field2'."
+ return desc
+}
builtin/credential/aws/path_config_identity.go+64 7
@@ -5,10 +5,52 @@ import (
"fmt"
"github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/helper/authmetadata"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/hashicorp/vault/sdk/logical"
)
+var (
+ // iamAuthMetadataFields is a list of the default auth metadata
+ // added to tokens during login. The default alias type used
+ // by this back-end is the role ID. Subsequently, the default
+ // fields included are expected to have a low rate of change
+ // when the role ID is in use.
+ iamAuthMetadataFields = &authmetadata.Fields{
+ FieldName: "iam_metadata",
+ Default: []string{
+ "account_id",
+ "auth_type",
+ },
+ AvailableToAdd: []string{
+ "canonical_arn",
+ "client_arn",
+ "client_user_id",
+ "inferred_aws_region",
+ "inferred_entity_id",
+ "inferred_entity_type",
+ },
+ }
+
+ // ec2AuthMetadataFields is a list of the default auth metadata
+ // added to tokens during login. The default alias type used
+ // by this back-end is the role ID. Subsequently, the default
+ // fields included are expected to have a low rate of change
+ // when the role ID is in use.
+ ec2AuthMetadataFields = &authmetadata.Fields{
+ FieldName: "ec2_metadata",
+ Default: []string{
+ "account_id",
+ "auth_type",
+ },
+ AvailableToAdd: []string{
+ "ami_id",
+ "instance_id",
+ "region",
+ },
+ }
+)
+
func (b *backend) pathConfigIdentity() *framework.Path {
return &framework.Path{
Pattern: "config/identity$",
@@ -18,11 +60,13 @@ func (b *backend) pathConfigIdentity() *framework.Path {
Default: identityAliasIAMUniqueID,
Description: fmt.Sprintf("Configure how the AWS auth method generates entity aliases when using IAM auth. Valid values are %q, %q, and %q. Defaults to %q.", identityAliasRoleID, identityAliasIAMUniqueID, identityAliasIAMFullArn, identityAliasRoleID),
},
+ iamAuthMetadataFields.FieldName: authmetadata.FieldSchema(iamAuthMetadataFields),
"ec2_alias": {
Type: framework.TypeString,
Default: identityAliasEC2InstanceID,
Description: fmt.Sprintf("Configure how the AWS auth method generates entity alias when using EC2 auth. Valid values are %q, %q, and %q. Defaults to %q.", identityAliasRoleID, identityAliasEC2InstanceID, identityAliasEC2ImageID, identityAliasRoleID),
},
+ ec2AuthMetadataFields.FieldName: authmetadata.FieldSchema(ec2AuthMetadataFields),
},
Operations: map[logical.Operation]framework.OperationHandler{
@@ -45,9 +89,12 @@ func identityConfigEntry(ctx context.Context, s logical.Storage) (*identityConfi
return nil, err
}
- var entry identityConfig
+ entry := &identityConfig{
+ IAMAuthMetadataHandler: authmetadata.NewHandler(iamAuthMetadataFields),
+ EC2AuthMetadataHandler: authmetadata.NewHandler(ec2AuthMetadataFields),
+ }
if entryRaw != nil {
- if err := entryRaw.DecodeJSON(&entry); err != nil {
+ if err := entryRaw.DecodeJSON(entry); err != nil {
return nil, err
}
}
@@ -60,7 +107,7 @@ func identityConfigEntry(ctx context.Context, s logical.Storage) (*identityConfi
entry.EC2Alias = identityAliasRoleID
}
- return &entry, nil
+ return entry, nil
}
func pathConfigIdentityRead(ctx context.Context, req *logical.Request, _ *framework.FieldData) (*logical.Response, error) {
@@ -71,8 +118,10 @@ func pathConfigIdentityRead(ctx context.Context, req *logical.Request, _ *framew
return &logical.Response{
Data: map[string]interface{}{
- "iam_alias": config.IAMAlias,
- "ec2_alias": config.EC2Alias,
+ "iam_alias": config.IAMAlias,
+ iamAuthMetadataFields.FieldName: config.IAMAuthMetadataHandler.AuthMetadata(),
+ "ec2_alias": config.EC2Alias,
+ ec2AuthMetadataFields.FieldName: config.EC2AuthMetadataHandler.AuthMetadata(),
},
}, nil
}
@@ -102,6 +151,12 @@ func pathConfigIdentityUpdate(ctx context.Context, req *logical.Request, data *f
}
config.EC2Alias = ec2Alias
}
+ if err := config.IAMAuthMetadataHandler.ParseAuthMetadata(data); err != nil {
+ return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
+ }
+ if err := config.EC2AuthMetadataHandler.ParseAuthMetadata(data); err != nil {
+ return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
+ }
entry, err := logical.StorageEntryJSON("config/identity", config)
if err != nil {
@@ -117,8 +172,10 @@ func pathConfigIdentityUpdate(ctx context.Context, req *logical.Request, data *f
}
type identityConfig struct {
- IAMAlias string `json:"iam_alias"`
- EC2Alias string `json:"ec2_alias"`
+ IAMAlias string `json:"iam_alias"`
+ IAMAuthMetadataHandler *authmetadata.Handler `json:"iam_auth_metadata_handler"`
+ EC2Alias string `json:"ec2_alias"`
+ EC2AuthMetadataHandler *authmetadata.Handler `json:"ec2_auth_metadata_handler"`
}
const identityAliasIAMUniqueID = "unique_id"
sdk/helper/authmetadata/auth_metadata_test.go+127 0
@@ -0,0 +1,127 @@
+package authmetadata
+
+import (
+ "fmt"
+ "reflect"
+ "sort"
+ "testing"
+
+ "github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/logical"
+)
+
+var testFields = &Fields{
+ FieldName: "some-field-name",
+ Default: []string{"fizz", "buzz"},
+ AvailableToAdd: []string{"foo", "bar"},
+}
+
+func TestFieldSchema(t *testing.T) {
+ schema := FieldSchema(testFields)
+ if schema.Type != framework.TypeCommaStringSlice {
+ t.Fatal("expected TypeCommaStringSlice")
+ }
+ if schema.Description != `The metadata to include on the aliases and audit logs generated by this plugin. When set to 'default', includes: fizz, buzz. These fields are available to add: foo, bar. Not editing this field means the 'default' fields are included. Explicitly setting this field to empty overrides the 'default' and means no metadata will be included. If not using 'default', explicit fields must be sent like: 'field1,field2'.` {
+ t.Fatal("received unexpected description: " + schema.Description)
+ }
+ if schema.DisplayAttrs == nil {
+ t.Fatal("expected display attributes")
+ }
+ if schema.DisplayAttrs.Name != testFields.FieldName {
+ t.Fatalf("expected name of %s", testFields.FieldName)
+ }
+ if schema.DisplayAttrs.Value != "field1,field2" {
+ t.Fatal("expected field1,field2")
+ }
+ if !reflect.DeepEqual(schema.Default, []string{"default"}) {
+ t.Fatal("expected default")
+ }
+}
+
+func TestGetAuthMetadata(t *testing.T) {
+ h := NewHandler(testFields)
+ expected := []string{"fizz", "buzz"}
+ sort.Strings(expected)
+ actual := h.AuthMetadata()
+ sort.Strings(actual)
+ if !reflect.DeepEqual(expected, actual) {
+ t.Fatalf("expected %s but received %s", expected, actual)
+ }
+}
+
+func TestParseAuthMetadata(t *testing.T) {
+ h := NewHandler(testFields)
+ data := &framework.FieldData{
+ Raw: map[string]interface{}{
+ testFields.FieldName: []string{"default"},
+ },
+ Schema: map[string]*framework.FieldSchema{
+ testFields.FieldName: FieldSchema(testFields),
+ },
+ }
+ if err := h.ParseAuthMetadata(data); err != nil {
+ t.Fatal(err)
+ }
+ expected := []string{"fizz", "buzz"}
+ sort.Strings(expected)
+ actual := h.AuthMetadata()
+ sort.Strings(actual)
+ if !reflect.DeepEqual(expected, actual) {
+ t.Fatalf("expected %s but received %s", expected, actual)
+ }
+}
+
+func TestPopulateDesiredAuthMetadata(t *testing.T) {
+ h := NewHandler(testFields)
+ data := &framework.FieldData{
+ Raw: map[string]interface{}{
+ testFields.FieldName: []string{"foo"},
+ },
+ Schema: map[string]*framework.FieldSchema{
+ testFields.FieldName: FieldSchema(testFields),
+ },
+ }
+ if err := h.ParseAuthMetadata(data); err != nil {
+ t.Fatal(err)
+ }
+ auth := &logical.Auth{
+ Alias: &logical.Alias{
+ Name: "foo",
+ },
+ }
+ if err := h.PopulateDesiredMetadata(auth, map[string]string{
+ "fizz": "fizzval",
+ "buzz": "buzzval",
+ "foo": "fooval",
+ }); err != nil {
+ t.Fatal(err)
+ }
+ if len(auth.Alias.Metadata) != 1 {
+ t.Fatal("expected only 1 configured field to be populated")
+ }
+ if auth.Alias.Metadata["foo"] != "fooval" {
+ t.Fatal("expected foova;")
+ }
+}
+
+func TestMarshalJSON(t *testing.T) {
+ h := NewHandler(&Fields{})
+ h.authMetadata = []string{"fizz", "buzz"}
+ b, err := h.MarshalJSON()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(b) != `{"auth_metadata":["fizz","buzz"]}` {
+ t.Fatal(`expected {"auth_metadata":["fizz","buzz"]}`)
+ }
+}
+
+func TestUnmarshalJSON(t *testing.T) {
+ h := NewHandler(&Fields{})
+ if err := h.UnmarshalJSON([]byte(`{"auth_metadata":["fizz","buzz"]}`)); err != nil {
+ t.Fatal(err)
+ }
+ if fmt.Sprintf("%s", h.authMetadata) != `[fizz buzz]` {
+ t.Fatal(`expected [fizz buzz]`)
+ }
+}
go.sum+38 40
@@ -391,47 +391,45 @@ github.com/hashicorp/raft-snapshot v1.0.2-0.20190827162939-8117efcc5aab/go.mod h
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k=
github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
-github.com/hashicorp/vault-plugin-auth-alicloud v0.5.4 h1:dX0bpQ4yRzqpPdyTKM6dPeJq3LDQStKUOZKq2cErkH0=
-github.com/hashicorp/vault-plugin-auth-alicloud v0.5.4/go.mod h1:sQ+VNwPQlemgXHXikYH6onfH9gPwDZ1GUVRLz0ZvHx8=
-github.com/hashicorp/vault-plugin-auth-azure v0.5.4 h1:14HpiBV5a547+fph6aoHZ80ND+1edzHfcqjYRV1wXNc=
-github.com/hashicorp/vault-plugin-auth-azure v0.5.4/go.mod h1:RCVBsf8AJndh4c6iGZtvVZFui9SG0Bj9fnF0SodNIkw=
-github.com/hashicorp/vault-plugin-auth-centrify v0.5.4 h1:ttcdUkEIjcS7vKqmWIwuY3IAsjfIbiooO5QFWHoUfoM=
-github.com/hashicorp/vault-plugin-auth-centrify v0.5.4/go.mod h1:GfRoy7NHsuR/ogmZtbExdJXUwbfwcxPrS9xzkyy2J/c=
-github.com/hashicorp/vault-plugin-auth-cf v0.5.3 h1:w1IGOcyhT8fNej1JIABXHF75sEgKtjZrqOgLaNEcttY=
-github.com/hashicorp/vault-plugin-auth-cf v0.5.3/go.mod h1:idkFYHc6ske2BE7fe00SpH+SBIlqDKz8vk/IPLJuX2o=
+github.com/hashicorp/vault-plugin-auth-alicloud v0.5.5 h1:JYf3VYpKs7mOdtcwZWi73S82oXrC/JR7uoPVUd8c4Hk=
+github.com/hashicorp/vault-plugin-auth-alicloud v0.5.5/go.mod h1:sQ+VNwPQlemgXHXikYH6onfH9gPwDZ1GUVRLz0ZvHx8=
+github.com/hashicorp/vault-plugin-auth-azure v0.5.5 h1:kN79ai+aMVU9hUmwscHjmweW2fGa8V/t+ScIchPZGrk=
+github.com/hashicorp/vault-plugin-auth-azure v0.5.5/go.mod h1:RCVBsf8AJndh4c6iGZtvVZFui9SG0Bj9fnF0SodNIkw=
+github.com/hashicorp/vault-plugin-auth-centrify v0.5.5 h1:YXxXt6o6I1rOkYW+hADK0vd+uVMj4C6Qs3jBrQlKQcY=
+github.com/hashicorp/vault-plugin-auth-centrify v0.5.5/go.mod h1:GfRoy7NHsuR/ogmZtbExdJXUwbfwcxPrS9xzkyy2J/c=
+github.com/hashicorp/vault-plugin-auth-cf v0.5.4 h1:2wl+qK7cLpr4u/lkv5DgvkNoKKhHC69H1QmoXOnArLw=
+github.com/hashicorp/vault-plugin-auth-cf v0.5.4/go.mod h1:idkFYHc6ske2BE7fe00SpH+SBIlqDKz8vk/IPLJuX2o=
github.com/hashicorp/vault-plugin-auth-gcp v0.5.1/go.mod h1:eLj92eX8MPI4vY1jaazVLF2sVbSAJ3LRHLRhF/pUmlI=
-github.com/hashicorp/vault-plugin-auth-gcp v0.6.0 h1:cGr2x2g7/JeUvz8AgVLWlLY+jQBrr4eIOXkkfS4d/gs=
-github.com/hashicorp/vault-plugin-auth-gcp v0.6.0/go.mod h1:8eBRzg+JIhAaDBfDndDAQKIhDrQ3WW8OPklxAYftNFs=
-github.com/hashicorp/vault-plugin-auth-jwt v0.6.1 h1:UeFnLdlaro4JqPhfAM97cSnCN2uXQIdnOHdDMjyj+OM=
-github.com/hashicorp/vault-plugin-auth-jwt v0.6.1/go.mod h1:SFadxIfoLGzugEjwUUmUaCGbsYEz2/jJymZDDQjEqYg=
-github.com/hashicorp/vault-plugin-auth-kerberos v0.1.4 h1:shZtbXy99VG4BIOHndGwbvv6GAn5Ujw1OzI6AemSA1w=
-github.com/hashicorp/vault-plugin-auth-kerberos v0.1.4/go.mod h1:r4UqWITHYKmBeAMKPWqLo4V8bl/wNqoSIaQcMpeK9ss=
-github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.0 h1:WvrhA/U6wsG378Q8esLSCKZtPNH6Ag1QRfiFNYCDUIg=
-github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.0/go.mod h1:/Y9W5aZULfPeNVRQK0/nrFGpHWyNm0J3UWhOdsAu0vM=
-github.com/hashicorp/vault-plugin-auth-oci v0.5.3 h1:ShFPX95UIS1j0eMSRq0gPmU2uSDgKjsO4COQThoJ+qs=
-github.com/hashicorp/vault-plugin-auth-oci v0.5.3/go.mod h1:j05O2b9fw2Q82NxDPhHMYVfHKvitUYGWfmqmpBdqmmc=
-github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.3 h1:apAR1DzqV9H7NWSQIahMFQqRgSHx7LE8RRzmLzVtshA=
-github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.3/go.mod h1:QjGrrxcRXv/4XkEZAlM0VMZEa3uxKAICFqDj27FP/48=
-github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.0 h1:BJvE4GFD/UmmNAGQQxOiNbHo5OXih225lNSMAWAbKYs=
-github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.0/go.mod h1:MP3kfr0N+7miOTZFwKv952b9VkXM4S2Q6YtQCiNKWq8=
-github.com/hashicorp/vault-plugin-secrets-ad v0.6.4 h1:FperRRhD6KQZWvCaV7l3ExNqMkNFkJuutHf3Z8cfOyk=
-github.com/hashicorp/vault-plugin-secrets-ad v0.6.4/go.mod h1:kk98nB+cwDbt3I7UGQq3ota7+eHZrGSTQZfSRGpluvA=
-github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.4 h1:YGx7SiVJeJlUyP9wrHYxTKT6BEStusEFsTw51ykAb+I=
-github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.4/go.mod h1:gAoReoUpBHaBwkxQqTK7FY8nQC0MuaZHLiW5WOSny5g=
-github.com/hashicorp/vault-plugin-secrets-azure v0.5.5 h1:TrePxAdQri6f0Vj3fowcbLnrxJeMbLVPETLqSdahuPc=
-github.com/hashicorp/vault-plugin-secrets-azure v0.5.5/go.mod h1:Q0cIL4kZWnMmQWkBfWtyOd7+JXTEpAyU4L932PMHq3E=
-github.com/hashicorp/vault-plugin-secrets-gcp v0.6.0 h1:7NCura5H734IQtmJNTcCypKPa1DvxPvxqOQITxRioPU=
-github.com/hashicorp/vault-plugin-secrets-gcp v0.6.0/go.mod h1:jVTE1fuhRcBOb/gnCT9W++AnlwiyQEX4S8iVCKhKQsE=
-github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.4 h1:R+8YT0LxbNiFV+6DGFxh0I+FUi0pblz8BgrrieFaHj4=
-github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.4/go.mod h1:b6RwFD1bny1zbfqhD35iGJdQYHRtJLx3HfBD109GO38=
-github.com/hashicorp/vault-plugin-secrets-kv v0.5.4 h1:rmP+NFz32aDvfinoa8977x2y0GPh9JO2xx8LAY6ORoE=
-github.com/hashicorp/vault-plugin-secrets-kv v0.5.4/go.mod h1:oNyUoMMQq6uNTwyYPnkldiedaknYbPfQIdKoyKQdy2g=
-github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.0 h1:qChA5Q1kQNXkWRvKYYy4t68s7I9rSJnZV3wFp8n197Y=
-github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.0/go.mod h1:K55+frX6W+CxqTLC2JSAxvWad5JRHgYE+LPvqhsJDmM=
-github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.1 h1:hrDehrV7zZ5/v5O58C4mdk80hR13h4ngMLfJYDuVNMs=
-github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.1/go.mod h1:YRW9zn9NZNitRlPYNAWRp/YEdKCF/X8aOg8IYSxFT5Y=
-github.com/hashicorp/vault-plugin-secrets-openldap v0.1.1 h1:rdGO8Ix8R8pzNJQ1H8TVlU6guv7NMPFt5tVwADNyAfk=
-github.com/hashicorp/vault-plugin-secrets-openldap v0.1.1/go.mod h1:9Cy4Jp779BjuIOhYLjEfH3M3QCUxZgPnvJ3tAOOmof4=
+github.com/hashicorp/vault-plugin-auth-gcp v0.6.1 h1:WXTuja3WC2BdZekYCnzuZGoVvZTAGH8kSDUHzOK2PQY=
+github.com/hashicorp/vault-plugin-auth-gcp v0.6.1/go.mod h1:8eBRzg+JIhAaDBfDndDAQKIhDrQ3WW8OPklxAYftNFs=
+github.com/hashicorp/vault-plugin-auth-jwt v0.6.2 h1:fp6Rk89iPjDS8dyEK7lEauYE/UhkgkHbmwRZKuQA01U=
+github.com/hashicorp/vault-plugin-auth-jwt v0.6.2/go.mod h1:SFadxIfoLGzugEjwUUmUaCGbsYEz2/jJymZDDQjEqYg=
+github.com/hashicorp/vault-plugin-auth-kerberos v0.1.5 h1:knWedzZ51g8Aj6Hyi1ATlQ/7jEx6nJeqFoCoHSrbQFI=
+github.com/hashicorp/vault-plugin-auth-kerberos v0.1.5/go.mod h1:r4UqWITHYKmBeAMKPWqLo4V8bl/wNqoSIaQcMpeK9ss=
+github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.1 h1:TpdQhHdZZN1Wo9RpJG33gUfuiVtajVcSF/hNpHWaatI=
+github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.1/go.mod h1:/Y9W5aZULfPeNVRQK0/nrFGpHWyNm0J3UWhOdsAu0vM=
+github.com/hashicorp/vault-plugin-auth-oci v0.5.4 h1:Hoauxh1V8Lusf7BRs+yXfoDTFQzgykbb3OC77aReXDY=
+github.com/hashicorp/vault-plugin-auth-oci v0.5.4/go.mod h1:j05O2b9fw2Q82NxDPhHMYVfHKvitUYGWfmqmpBdqmmc=
+github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.4 h1:YE4qndazWmYGpVOoZI7nDGG+gwTZKzL1Ou4WZQ+Tdxk=
+github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.4/go.mod h1:QjGrrxcRXv/4XkEZAlM0VMZEa3uxKAICFqDj27FP/48=
+github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.1 h1:fA6cFH8lIPH2M4KNTEzf1bpc6Tbyy5ZvoYP8H/TI9ts=
+github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.1/go.mod h1:MP3kfr0N+7miOTZFwKv952b9VkXM4S2Q6YtQCiNKWq8=
+github.com/hashicorp/vault-plugin-secrets-ad v0.6.5 h1:wrHzXSD6qmKvkuHaQn+BNj89+HGhMNchxAckGnd7YTc=
+github.com/hashicorp/vault-plugin-secrets-ad v0.6.5/go.mod h1:kk98nB+cwDbt3I7UGQq3ota7+eHZrGSTQZfSRGpluvA=
+github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5 h1:BOOtSls+BQ1EtPmpE9LoqZztsEZ1fRWVSkHWtRIrCB4=
+github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5/go.mod h1:gAoReoUpBHaBwkxQqTK7FY8nQC0MuaZHLiW5WOSny5g=
+github.com/hashicorp/vault-plugin-secrets-azure v0.5.6 h1:4PgQ5rCT29wW5PMyebEhPkEYuR5s+SnInuZz3x2cP50=
+github.com/hashicorp/vault-plugin-secrets-azure v0.5.6/go.mod h1:Q0cIL4kZWnMmQWkBfWtyOd7+JXTEpAyU4L932PMHq3E=
+github.com/hashicorp/vault-plugin-secrets-gcp v0.6.1 h1:APkzBSHo+sKeWxXCM1aGGwcbfKfVQFN3CHmNGHyfqL0=
+github.com/hashicorp/vault-plugin-secrets-gcp v0.6.1/go.mod h1:jVTE1fuhRcBOb/gnCT9W++AnlwiyQEX4S8iVCKhKQsE=
+github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.5 h1:NigzA2v+h+cjBPl41pRirRwWELF+RPJGch/ys0Sijrc=
+github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.5/go.mod h1:b6RwFD1bny1zbfqhD35iGJdQYHRtJLx3HfBD109GO38=
+github.com/hashicorp/vault-plugin-secrets-kv v0.5.5 h1:yLtfsAiJOkpRkk+OxQmFluQJ35OUw420Y+CwfGMWuSc=
+github.com/hashicorp/vault-plugin-secrets-kv v0.5.5/go.mod h1:oNyUoMMQq6uNTwyYPnkldiedaknYbPfQIdKoyKQdy2g=
+github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2 h1:X9eK6NSb1qafvoEYxH5nomAW3JXl12KybR77NpgqpIU=
+github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2/go.mod h1:YRW9zn9NZNitRlPYNAWRp/YEdKCF/X8aOg8IYSxFT5Y=
+github.com/hashicorp/vault-plugin-secrets-openldap v0.1.2 h1:618nyNUHX2Oc7pcQh6r0Zm0kaMrhkfAyUyFmDFwyYnQ=
+github.com/hashicorp/vault-plugin-secrets-openldap v0.1.2/go.mod h1:9Cy4Jp779BjuIOhYLjEfH3M3QCUxZgPnvJ3tAOOmof4=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
builtin/credential/aws/path_login_test.go+168 5
@@ -214,8 +214,39 @@ func TestBackend_pathLogin_IAMHeaders(t *testing.T) {
t.Fatal(err)
}
+ // Configure identity.
+ _, err = b.HandleRequest(context.Background(), &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config/identity",
+ Storage: storage,
+ Data: map[string]interface{}{
+ "iam_alias": "role_id",
+ "iam_metadata": []string{
+ "account_id",
+ "auth_type",
+ "canonical_arn",
+ "client_arn",
+ "client_user_id",
+ "inferred_aws_region",
+ "inferred_entity_id",
+ "inferred_entity_type",
+ },
+ "ec2_alias": "role_id",
+ "ec2_metadata": []string{
+ "account_id",
+ "ami_id",
+ "instance_id",
+ "region",
+ },
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
// create a role entry
roleEntry := &awsRoleEntry{
+ RoleID: "foo",
Version: currentRoleStorageVersion,
AuthType: iamAuthType,
}
@@ -232,16 +263,12 @@ func TestBackend_pathLogin_IAMHeaders(t *testing.T) {
t.Fatal(err)
}
- expectedAliasMetadata := map[string]string{
+ expectedAuthMetadata := map[string]string{
"account_id": "123456789012",
"auth_type": "iam",
"canonical_arn": "arn:aws:iam::123456789012:user/valid-role",
"client_arn": "arn:aws:iam::123456789012:user/valid-role",
"client_user_id": "ASOMETHINGSOMETHINGSOMETHING",
- // Note there is no inferred entity, so these fields should be empty
- "inferred_aws_region": "",
- "inferred_entity_id": "",
- "inferred_entity_type": "",
}
// expected errors for certain tests
@@ -317,6 +344,142 @@ func TestBackend_pathLogin_IAMHeaders(t *testing.T) {
},
}
+ for _, tc := range testCases {
+ t.Run(tc.Name, func(t *testing.T) {
+ if tc.Header != nil {
+ loginData["iam_request_headers"] = tc.Header
+ }
+
+ loginRequest := &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "login",
+ Storage: storage,
+ Data: loginData,
+ Connection: &logical.Connection{},
+ }
+
+ resp, err := b.HandleRequest(context.Background(), loginRequest)
+ if err != nil || resp == nil || resp.IsError() {
+ if tc.ExpectErr != nil && tc.ExpectErr.Error() == resp.Error().Error() {
+ return
+ }
+ t.Errorf("un expected failed login:\nresp: %#v\n\nerr: %v", resp, err)
+ }
+
+ if !reflect.DeepEqual(expectedAuthMetadata, resp.Auth.Alias.Metadata) {
+ t.Errorf("expected metadata (%#v) to match (%#v)", expectedAuthMetadata, resp.Auth.Alias.Metadata)
+ }
+ })
+ }
+}
+
+func TestBackend_defaultAliasMetadata(t *testing.T) {
+ storage := &logical.InmemStorage{}
+ config := logical.TestBackendConfig()
+ config.StorageView = storage
+ b, err := Backend(config)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = b.Setup(context.Background(), config)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // sets up a test server to stand in for STS service
+ ts := setupIAMTestServer()
+ defer ts.Close()
+
+ clientConfigData := map[string]interface{}{
+ "iam_server_id_header_value": testVaultHeaderValue,
+ "sts_endpoint": ts.URL,
+ }
+ clientRequest := &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config/client",
+ Storage: storage,
+ Data: clientConfigData,
+ }
+ _, err = b.HandleRequest(context.Background(), clientRequest)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Configure identity.
+ _, err = b.HandleRequest(context.Background(), &logical.Request{
+ Operation: logical.UpdateOperation,
+ Path: "config/identity",
+ Storage: storage,
+ Data: map[string]interface{}{
+ "iam_alias": "role_id",
+ "ec2_alias": "role_id",
+ },
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // create a role entry
+ roleEntry := &awsRoleEntry{
+ RoleID: "foo",
+ Version: currentRoleStorageVersion,
+ AuthType: iamAuthType,
+ }
+
+ if err := b.setRole(context.Background(), storage, testValidRoleName, roleEntry); err != nil {
+ t.Fatalf("failed to set entry: %s", err)
+ }
+
+ // create a baseline loginData map structure, including iam_request_headers
+ // already base64encoded. This is the "Default" loginData used for all tests.
+ // Each sub test can override the map's iam_request_headers entry
+ loginData, err := defaultLoginData()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expectedAliasMetadata := map[string]string{
+ "account_id": "123456789012",
+ "auth_type": "iam",
+ }
+
+ testCases := []struct {
+ Name string
+ Header interface{}
+ ExpectErr error
+ }{
+ {
+ Name: "Default",
+ },
+ {
+ Name: "Map-complete",
+ Header: map[string]interface{}{
+ "Content-Length": "43",
+ "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
+ "User-Agent": "aws-sdk-go/1.14.24 (go1.11; darwin; amd64)",
+ "X-Amz-Date": "20180910T203328Z",
+ "X-Vault-Aws-Iam-Server-Id": "VaultAcceptanceTesting",
+ "Authorization": "AWS4-HMAC-SHA256 Credential=AKIAJPQ466AIIQW4LPSQ/20180910/us-east-1/sts/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date;x-vault-aws-iam-server-id, Signature=cdef5819b2e97f1ff0f3e898fd2621aa03af00a4ec3e019122c20e5482534bf4",
+ },
+ },
+ {
+ Name: "JSON-complete",
+ Header: `{
+ "Content-Length":"43",
+ "Content-Type":"application/x-www-form-urlencoded; charset=utf-8",
+ "User-Agent":"aws-sdk-go/1.14.24 (go1.11; darwin; amd64)",
+ "X-Amz-Date":"20180910T203328Z",
+ "X-Vault-Aws-Iam-Server-Id": "VaultAcceptanceTesting",
+ "Authorization":"AWS4-HMAC-SHA256 Credential=AKIAJPQ466AIIQW4LPSQ/20180910/us-east-1/sts/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date;x-vault-aws-iam-server-id, Signature=cdef5819b2e97f1ff0f3e898fd2621aa03af00a4ec3e019122c20e5482534bf4"
+ }`,
+ },
+ {
+ Name: "Base64-complete",
+ Header: base64Complete(),
+ },
+ }
+
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
if tc.Header != nil {
vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute/dedicatedhostgroups.go+399 0
@@ -0,0 +1,592 @@
+package compute
+
+// Copyright (c) Microsoft and contributors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Code generated by Microsoft (R) AutoRest Code Generator.
+// Changes may cause incorrect behavior and will be lost if the code is regenerated.
+
+import (
+ "context"
+ "github.com/Azure/go-autorest/autorest"
+ "github.com/Azure/go-autorest/autorest/azure"
+ "github.com/Azure/go-autorest/autorest/validation"
+ "github.com/Azure/go-autorest/tracing"
+ "net/http"
+)
+
+// DedicatedHostGroupsClient is the compute Client
+type DedicatedHostGroupsClient struct {
+ BaseClient
+}
+
+// NewDedicatedHostGroupsClient creates an instance of the DedicatedHostGroupsClient client.
+func NewDedicatedHostGroupsClient(subscriptionID string) DedicatedHostGroupsClient {
+ return NewDedicatedHostGroupsClientWithBaseURI(DefaultBaseURI, subscriptionID)
+}
+
+// NewDedicatedHostGroupsClientWithBaseURI creates an instance of the DedicatedHostGroupsClient client.
+func NewDedicatedHostGroupsClientWithBaseURI(baseURI string, subscriptionID string) DedicatedHostGroupsClient {
+ return DedicatedHostGroupsClient{NewWithBaseURI(baseURI, subscriptionID)}
+}
+
+// CreateOrUpdate create or update a dedicated host group. For details of Dedicated Host and Dedicated Host Groups
+// please see [Dedicated Host Documentation] (https://go.microsoft.com/fwlink/?linkid=2082596)
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// hostGroupName - the name of the dedicated host group.
+// parameters - parameters supplied to the Create Dedicated Host Group.
+func (client DedicatedHostGroupsClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, hostGroupName string, parameters DedicatedHostGroup) (result DedicatedHostGroup, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostGroupsClient.CreateOrUpdate")
+ defer func() {
+ sc := -1
+ if result.Response.Response != nil {
+ sc = result.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ if err := validation.Validate([]validation.Validation{
+ {TargetValue: parameters,
+ Constraints: []validation.Constraint{{Target: "parameters.DedicatedHostGroupProperties", Name: validation.Null, Rule: false,
+ Chain: []validation.Constraint{{Target: "parameters.DedicatedHostGroupProperties.PlatformFaultDomainCount", Name: validation.Null, Rule: true,
+ Chain: []validation.Constraint{{Target: "parameters.DedicatedHostGroupProperties.PlatformFaultDomainCount", Name: validation.InclusiveMaximum, Rule: int64(3), Chain: nil},
+ {Target: "parameters.DedicatedHostGroupProperties.PlatformFaultDomainCount", Name: validation.InclusiveMinimum, Rule: 1, Chain: nil},
+ }},
+ }}}}}); err != nil {
+ return result, validation.NewError("compute.DedicatedHostGroupsClient", "CreateOrUpdate", err.Error())
+ }
+
+ req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, hostGroupName, parameters)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "CreateOrUpdate", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.CreateOrUpdateSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "CreateOrUpdate", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.CreateOrUpdateResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "CreateOrUpdate", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
+func (client DedicatedHostGroupsClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, hostGroupName string, parameters DedicatedHostGroup) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "hostGroupName": autorest.Encode("path", hostGroupName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsContentType("application/json; charset=utf-8"),
+ autorest.AsPut(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/hostGroups/{hostGroupName}", pathParameters),
+ autorest.WithJSON(parameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the
+// http.Response Body if it receives an error.
+func (client DedicatedHostGroupsClient) CreateOrUpdateSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
+// closes the http.Response Body.
+func (client DedicatedHostGroupsClient) CreateOrUpdateResponder(resp *http.Response) (result DedicatedHostGroup, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// Delete delete a dedicated host group.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// hostGroupName - the name of the dedicated host group.
+func (client DedicatedHostGroupsClient) Delete(ctx context.Context, resourceGroupName string, hostGroupName string) (result autorest.Response, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostGroupsClient.Delete")
+ defer func() {
+ sc := -1
+ if result.Response != nil {
+ sc = result.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.DeletePreparer(ctx, resourceGroupName, hostGroupName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "Delete", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.DeleteSender(req)
+ if err != nil {
+ result.Response = resp
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "Delete", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.DeleteResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "Delete", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// DeletePreparer prepares the Delete request.
+func (client DedicatedHostGroupsClient) DeletePreparer(ctx context.Context, resourceGroupName string, hostGroupName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "hostGroupName": autorest.Encode("path", hostGroupName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsDelete(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/hostGroups/{hostGroupName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// DeleteSender sends the Delete request. The method will close the
+// http.Response Body if it receives an error.
+func (client DedicatedHostGroupsClient) DeleteSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// DeleteResponder handles the response to the Delete request. The method always
+// closes the http.Response Body.
+func (client DedicatedHostGroupsClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent),
+ autorest.ByClosing())
+ result.Response = resp
+ return
+}
+
+// Get retrieves information about a dedicated host group.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// hostGroupName - the name of the dedicated host group.
+func (client DedicatedHostGroupsClient) Get(ctx context.Context, resourceGroupName string, hostGroupName string) (result DedicatedHostGroup, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostGroupsClient.Get")
+ defer func() {
+ sc := -1
+ if result.Response.Response != nil {
+ sc = result.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.GetPreparer(ctx, resourceGroupName, hostGroupName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "Get", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.GetSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "Get", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.GetResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "Get", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// GetPreparer prepares the Get request.
+func (client DedicatedHostGroupsClient) GetPreparer(ctx context.Context, resourceGroupName string, hostGroupName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "hostGroupName": autorest.Encode("path", hostGroupName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/hostGroups/{hostGroupName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// GetSender sends the Get request. The method will close the
+// http.Response Body if it receives an error.
+func (client DedicatedHostGroupsClient) GetSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// GetResponder handles the response to the Get request. The method always
+// closes the http.Response Body.
+func (client DedicatedHostGroupsClient) GetResponder(resp *http.Response) (result DedicatedHostGroup, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// ListByResourceGroup lists all of the dedicated host groups in the specified resource group. Use the nextLink
+// property in the response to get the next page of dedicated host groups.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+func (client DedicatedHostGroupsClient) ListByResourceGroup(ctx context.Context, resourceGroupName string) (result DedicatedHostGroupListResultPage, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostGroupsClient.ListByResourceGroup")
+ defer func() {
+ sc := -1
+ if result.dhglr.Response.Response != nil {
+ sc = result.dhglr.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ result.fn = client.listByResourceGroupNextResults
+ req, err := client.ListByResourceGroupPreparer(ctx, resourceGroupName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "ListByResourceGroup", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.ListByResourceGroupSender(req)
+ if err != nil {
+ result.dhglr.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "ListByResourceGroup", resp, "Failure sending request")
+ return
+ }
+
+ result.dhglr, err = client.ListByResourceGroupResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "ListByResourceGroup", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// ListByResourceGroupPreparer prepares the ListByResourceGroup request.
+func (client DedicatedHostGroupsClient) ListByResourceGroupPreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/hostGroups", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// ListByResourceGroupSender sends the ListByResourceGroup request. The method will close the
+// http.Response Body if it receives an error.
+func (client DedicatedHostGroupsClient) ListByResourceGroupSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// ListByResourceGroupResponder handles the response to the ListByResourceGroup request. The method always
+// closes the http.Response Body.
+func (client DedicatedHostGroupsClient) ListByResourceGroupResponder(resp *http.Response) (result DedicatedHostGroupListResult, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// listByResourceGroupNextResults retrieves the next set of results, if any.
+func (client DedicatedHostGroupsClient) listByResourceGroupNextResults(ctx context.Context, lastResults DedicatedHostGroupListResult) (result DedicatedHostGroupListResult, err error) {
+ req, err := lastResults.dedicatedHostGroupListResultPreparer(ctx)
+ if err != nil {
+ return result, autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "listByResourceGroupNextResults", nil, "Failure preparing next results request")
+ }
+ if req == nil {
+ return
+ }
+ resp, err := client.ListByResourceGroupSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ return result, autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "listByResourceGroupNextResults", resp, "Failure sending next results request")
+ }
+ result, err = client.ListByResourceGroupResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostGroupsClient", "listByResourceGroupNextResults", resp, "Failure responding to next results request")
+ }
+ return
+}
+
+// ListByResourceGroupComplete enumerates all values, automatically crossing page boundaries as required.
+func (client DedicatedHostGroupsClient) ListByResourceGroupComplete(ctx context.Context, resourceGroupName string) (result DedicatedHostGroupListResultIterator, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostGroupsClient.ListByResourceGroup")
+ defer func() {
+ sc := -1
+ if result.Response().Response.Response != nil {
+ sc = result.page.Response().Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ result.page, err = client.ListByResourceGroup(ctx, resourceGroupName)
… diff truncated
vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute/proximityplacementgroups.go+399 0
@@ -0,0 +1,577 @@
+package compute
+
+// Copyright (c) Microsoft and contributors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Code generated by Microsoft (R) AutoRest Code Generator.
+// Changes may cause incorrect behavior and will be lost if the code is regenerated.
+
+import (
+ "context"
+ "github.com/Azure/go-autorest/autorest"
+ "github.com/Azure/go-autorest/autorest/azure"
+ "github.com/Azure/go-autorest/tracing"
+ "net/http"
+)
+
+// ProximityPlacementGroupsClient is the compute Client
+type ProximityPlacementGroupsClient struct {
+ BaseClient
+}
+
+// NewProximityPlacementGroupsClient creates an instance of the ProximityPlacementGroupsClient client.
+func NewProximityPlacementGroupsClient(subscriptionID string) ProximityPlacementGroupsClient {
+ return NewProximityPlacementGroupsClientWithBaseURI(DefaultBaseURI, subscriptionID)
+}
+
+// NewProximityPlacementGroupsClientWithBaseURI creates an instance of the ProximityPlacementGroupsClient client.
+func NewProximityPlacementGroupsClientWithBaseURI(baseURI string, subscriptionID string) ProximityPlacementGroupsClient {
+ return ProximityPlacementGroupsClient{NewWithBaseURI(baseURI, subscriptionID)}
+}
+
+// CreateOrUpdate create or update a proximity placement group.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// proximityPlacementGroupName - the name of the proximity placement group.
+// parameters - parameters supplied to the Create Proximity Placement Group operation.
+func (client ProximityPlacementGroupsClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string, parameters ProximityPlacementGroup) (result ProximityPlacementGroup, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/ProximityPlacementGroupsClient.CreateOrUpdate")
+ defer func() {
+ sc := -1
+ if result.Response.Response != nil {
+ sc = result.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, proximityPlacementGroupName, parameters)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "CreateOrUpdate", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.CreateOrUpdateSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "CreateOrUpdate", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.CreateOrUpdateResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "CreateOrUpdate", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
+func (client ProximityPlacementGroupsClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string, parameters ProximityPlacementGroup) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "proximityPlacementGroupName": autorest.Encode("path", proximityPlacementGroupName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsContentType("application/json; charset=utf-8"),
+ autorest.AsPut(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/proximityPlacementGroups/{proximityPlacementGroupName}", pathParameters),
+ autorest.WithJSON(parameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the
+// http.Response Body if it receives an error.
+func (client ProximityPlacementGroupsClient) CreateOrUpdateSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
+// closes the http.Response Body.
+func (client ProximityPlacementGroupsClient) CreateOrUpdateResponder(resp *http.Response) (result ProximityPlacementGroup, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// Delete delete a proximity placement group.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// proximityPlacementGroupName - the name of the proximity placement group.
+func (client ProximityPlacementGroupsClient) Delete(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string) (result autorest.Response, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/ProximityPlacementGroupsClient.Delete")
+ defer func() {
+ sc := -1
+ if result.Response != nil {
+ sc = result.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.DeletePreparer(ctx, resourceGroupName, proximityPlacementGroupName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "Delete", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.DeleteSender(req)
+ if err != nil {
+ result.Response = resp
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "Delete", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.DeleteResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "Delete", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// DeletePreparer prepares the Delete request.
+func (client ProximityPlacementGroupsClient) DeletePreparer(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "proximityPlacementGroupName": autorest.Encode("path", proximityPlacementGroupName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsDelete(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/proximityPlacementGroups/{proximityPlacementGroupName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// DeleteSender sends the Delete request. The method will close the
+// http.Response Body if it receives an error.
+func (client ProximityPlacementGroupsClient) DeleteSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// DeleteResponder handles the response to the Delete request. The method always
+// closes the http.Response Body.
+func (client ProximityPlacementGroupsClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByClosing())
+ result.Response = resp
+ return
+}
+
+// Get retrieves information about a proximity placement group .
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// proximityPlacementGroupName - the name of the proximity placement group.
+func (client ProximityPlacementGroupsClient) Get(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string) (result ProximityPlacementGroup, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/ProximityPlacementGroupsClient.Get")
+ defer func() {
+ sc := -1
+ if result.Response.Response != nil {
+ sc = result.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.GetPreparer(ctx, resourceGroupName, proximityPlacementGroupName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "Get", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.GetSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "Get", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.GetResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "Get", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// GetPreparer prepares the Get request.
+func (client ProximityPlacementGroupsClient) GetPreparer(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "proximityPlacementGroupName": autorest.Encode("path", proximityPlacementGroupName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/proximityPlacementGroups/{proximityPlacementGroupName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// GetSender sends the Get request. The method will close the
+// http.Response Body if it receives an error.
+func (client ProximityPlacementGroupsClient) GetSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// GetResponder handles the response to the Get request. The method always
+// closes the http.Response Body.
+func (client ProximityPlacementGroupsClient) GetResponder(resp *http.Response) (result ProximityPlacementGroup, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// ListByResourceGroup lists all proximity placement groups in a resource group.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+func (client ProximityPlacementGroupsClient) ListByResourceGroup(ctx context.Context, resourceGroupName string) (result ProximityPlacementGroupListResultPage, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/ProximityPlacementGroupsClient.ListByResourceGroup")
+ defer func() {
+ sc := -1
+ if result.ppglr.Response.Response != nil {
+ sc = result.ppglr.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ result.fn = client.listByResourceGroupNextResults
+ req, err := client.ListByResourceGroupPreparer(ctx, resourceGroupName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "ListByResourceGroup", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.ListByResourceGroupSender(req)
+ if err != nil {
+ result.ppglr.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "ListByResourceGroup", resp, "Failure sending request")
+ return
+ }
+
+ result.ppglr, err = client.ListByResourceGroupResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "ListByResourceGroup", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// ListByResourceGroupPreparer prepares the ListByResourceGroup request.
+func (client ProximityPlacementGroupsClient) ListByResourceGroupPreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/proximityPlacementGroups", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// ListByResourceGroupSender sends the ListByResourceGroup request. The method will close the
+// http.Response Body if it receives an error.
+func (client ProximityPlacementGroupsClient) ListByResourceGroupSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// ListByResourceGroupResponder handles the response to the ListByResourceGroup request. The method always
+// closes the http.Response Body.
+func (client ProximityPlacementGroupsClient) ListByResourceGroupResponder(resp *http.Response) (result ProximityPlacementGroupListResult, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// listByResourceGroupNextResults retrieves the next set of results, if any.
+func (client ProximityPlacementGroupsClient) listByResourceGroupNextResults(ctx context.Context, lastResults ProximityPlacementGroupListResult) (result ProximityPlacementGroupListResult, err error) {
+ req, err := lastResults.proximityPlacementGroupListResultPreparer(ctx)
+ if err != nil {
+ return result, autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "listByResourceGroupNextResults", nil, "Failure preparing next results request")
+ }
+ if req == nil {
+ return
+ }
+ resp, err := client.ListByResourceGroupSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ return result, autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "listByResourceGroupNextResults", resp, "Failure sending next results request")
+ }
+ result, err = client.ListByResourceGroupResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.ProximityPlacementGroupsClient", "listByResourceGroupNextResults", resp, "Failure responding to next results request")
+ }
+ return
+}
+
+// ListByResourceGroupComplete enumerates all values, automatically crossing page boundaries as required.
+func (client ProximityPlacementGroupsClient) ListByResourceGroupComplete(ctx context.Context, resourceGroupName string) (result ProximityPlacementGroupListResultIterator, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/ProximityPlacementGroupsClient.ListByResourceGroup")
+ defer func() {
+ sc := -1
+ if result.Response().Response.Response != nil {
+ sc = result.page.Response().Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ result.page, err = client.ListByResourceGroup(ctx, resourceGroupName)
+ return
+}
+
+// ListBySubscription lists all proximity placement groups in a subscription.
+func (client ProximityPlacementGroupsClient) ListBySubscription(ctx context.Context) (result ProximityPlacementGroupListResultPage, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/ProximityPlacementGroupsClient.ListBySubscription")
+ defer func() {
+ sc := -1
+ if result.ppglr.Response.Response != nil {
+ sc = result.ppglr.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
… diff truncated
go.mod+19 19
@@ -70,25 +70,25 @@ require (
github.com/hashicorp/nomad/api v0.0.0-20191220223628-edc62acd919d
github.com/hashicorp/raft v1.1.2-0.20191002163536-9c6bd3e3eb17
github.com/hashicorp/raft-snapshot v1.0.2-0.20190827162939-8117efcc5aab
- github.com/hashicorp/vault-plugin-auth-alicloud v0.5.4
- github.com/hashicorp/vault-plugin-auth-azure v0.5.4
- github.com/hashicorp/vault-plugin-auth-centrify v0.5.4
- github.com/hashicorp/vault-plugin-auth-cf v0.5.3
- github.com/hashicorp/vault-plugin-auth-gcp v0.6.0
- github.com/hashicorp/vault-plugin-auth-jwt v0.6.1
- github.com/hashicorp/vault-plugin-auth-kerberos v0.1.4
- github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.0
- github.com/hashicorp/vault-plugin-auth-oci v0.5.3
- github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.3
- github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.0
- github.com/hashicorp/vault-plugin-secrets-ad v0.6.4
- github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.4
- github.com/hashicorp/vault-plugin-secrets-azure v0.5.5
- github.com/hashicorp/vault-plugin-secrets-gcp v0.6.0
- github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.4
- github.com/hashicorp/vault-plugin-secrets-kv v0.5.4
- github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.1
- github.com/hashicorp/vault-plugin-secrets-openldap v0.1.1
+ github.com/hashicorp/vault-plugin-auth-alicloud v0.5.5
+ github.com/hashicorp/vault-plugin-auth-azure v0.5.5
+ github.com/hashicorp/vault-plugin-auth-centrify v0.5.5
+ github.com/hashicorp/vault-plugin-auth-cf v0.5.4
+ github.com/hashicorp/vault-plugin-auth-gcp v0.6.1
+ github.com/hashicorp/vault-plugin-auth-jwt v0.6.2
+ github.com/hashicorp/vault-plugin-auth-kerberos v0.1.5
+ github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.1
+ github.com/hashicorp/vault-plugin-auth-oci v0.5.4
+ github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.4
+ github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.1
+ github.com/hashicorp/vault-plugin-secrets-ad v0.6.5
+ github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5
+ github.com/hashicorp/vault-plugin-secrets-azure v0.5.6
+ github.com/hashicorp/vault-plugin-secrets-gcp v0.6.1
+ github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.5
+ github.com/hashicorp/vault-plugin-secrets-kv v0.5.5
+ github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2
+ github.com/hashicorp/vault-plugin-secrets-openldap v0.1.2
github.com/hashicorp/vault/api v1.0.5-0.20200317185738-82f498082f02
github.com/hashicorp/vault/sdk v0.1.14-0.20200317185738-82f498082f02
github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4
vendor/modules.txt+19 19
@@ -378,55 +378,55 @@ github.com/hashicorp/raft
github.com/hashicorp/raft-snapshot
# github.com/hashicorp/serf v0.8.3
github.com/hashicorp/serf/coordinate
-# github.com/hashicorp/vault-plugin-auth-alicloud v0.5.4
+# github.com/hashicorp/vault-plugin-auth-alicloud v0.5.5
github.com/hashicorp/vault-plugin-auth-alicloud
github.com/hashicorp/vault-plugin-auth-alicloud/tools
-# github.com/hashicorp/vault-plugin-auth-azure v0.5.4
+# github.com/hashicorp/vault-plugin-auth-azure v0.5.5
github.com/hashicorp/vault-plugin-auth-azure
-# github.com/hashicorp/vault-plugin-auth-centrify v0.5.4
+# github.com/hashicorp/vault-plugin-auth-centrify v0.5.5
github.com/hashicorp/vault-plugin-auth-centrify
-# github.com/hashicorp/vault-plugin-auth-cf v0.5.3
+# github.com/hashicorp/vault-plugin-auth-cf v0.5.4
github.com/hashicorp/vault-plugin-auth-cf
github.com/hashicorp/vault-plugin-auth-cf/models
github.com/hashicorp/vault-plugin-auth-cf/signatures
github.com/hashicorp/vault-plugin-auth-cf/testing/certificates
github.com/hashicorp/vault-plugin-auth-cf/testing/cf
github.com/hashicorp/vault-plugin-auth-cf/util
-# github.com/hashicorp/vault-plugin-auth-gcp v0.6.0
+# github.com/hashicorp/vault-plugin-auth-gcp v0.6.1
github.com/hashicorp/vault-plugin-auth-gcp/plugin
github.com/hashicorp/vault-plugin-auth-gcp/plugin/cache
-# github.com/hashicorp/vault-plugin-auth-jwt v0.6.1
+# github.com/hashicorp/vault-plugin-auth-jwt v0.6.2
github.com/hashicorp/vault-plugin-auth-jwt
-# github.com/hashicorp/vault-plugin-auth-kerberos v0.1.4
+# github.com/hashicorp/vault-plugin-auth-kerberos v0.1.5
github.com/hashicorp/vault-plugin-auth-kerberos
-# github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.0
+# github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.1
github.com/hashicorp/vault-plugin-auth-kubernetes
-# github.com/hashicorp/vault-plugin-auth-oci v0.5.3
+# github.com/hashicorp/vault-plugin-auth-oci v0.5.4
github.com/hashicorp/vault-plugin-auth-oci
-# github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.3
+# github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.4
github.com/hashicorp/vault-plugin-database-elasticsearch
-# github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.0
+# github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.1
github.com/hashicorp/vault-plugin-database-mongodbatlas
-# github.com/hashicorp/vault-plugin-secrets-ad v0.6.4
+# github.com/hashicorp/vault-plugin-secrets-ad v0.6.5
github.com/hashicorp/vault-plugin-secrets-ad/plugin
github.com/hashicorp/vault-plugin-secrets-ad/plugin/client
github.com/hashicorp/vault-plugin-secrets-ad/plugin/util
-# github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.4
+# github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5
github.com/hashicorp/vault-plugin-secrets-alicloud
github.com/hashicorp/vault-plugin-secrets-alicloud/clients
-# github.com/hashicorp/vault-plugin-secrets-azure v0.5.5
+# github.com/hashicorp/vault-plugin-secrets-azure v0.5.6
github.com/hashicorp/vault-plugin-secrets-azure
-# github.com/hashicorp/vault-plugin-secrets-gcp v0.6.0
+# github.com/hashicorp/vault-plugin-secrets-gcp v0.6.1
github.com/hashicorp/vault-plugin-secrets-gcp/plugin
github.com/hashicorp/vault-plugin-secrets-gcp/plugin/iamutil
github.com/hashicorp/vault-plugin-secrets-gcp/plugin/util
-# github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.4
+# github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.5
github.com/hashicorp/vault-plugin-secrets-gcpkms
-# github.com/hashicorp/vault-plugin-secrets-kv v0.5.4
+# github.com/hashicorp/vault-plugin-secrets-kv v0.5.5
github.com/hashicorp/vault-plugin-secrets-kv
-# github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.1
+# github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2
github.com/hashicorp/vault-plugin-secrets-mongodbatlas
-# github.com/hashicorp/vault-plugin-secrets-openldap v0.1.1
+# github.com/hashicorp/vault-plugin-secrets-openldap v0.1.2
github.com/hashicorp/vault-plugin-secrets-openldap
github.com/hashicorp/vault-plugin-secrets-openldap/client
# github.com/hashicorp/vault/api v1.0.5-0.20200317185738-82f498082f02 => ./api
(#8784)
command/server.go | 11 ++++++++++-
physical/raft/raft.go | 18 ++++++++++++++++--
vault/cluster.go | 3 +--
website/pages/docs/configuration/index.mdx | 3 ++-
4 files changed, 29 insertions(+), 6 deletions(-)
vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute/dedicatedhosts.go+399 0
@@ -0,0 +1,495 @@
+package compute
+
+// Copyright (c) Microsoft and contributors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Code generated by Microsoft (R) AutoRest Code Generator.
+// Changes may cause incorrect behavior and will be lost if the code is regenerated.
+
+import (
+ "context"
+ "github.com/Azure/go-autorest/autorest"
+ "github.com/Azure/go-autorest/autorest/azure"
+ "github.com/Azure/go-autorest/autorest/validation"
+ "github.com/Azure/go-autorest/tracing"
+ "net/http"
+)
+
+// DedicatedHostsClient is the compute Client
+type DedicatedHostsClient struct {
+ BaseClient
+}
+
+// NewDedicatedHostsClient creates an instance of the DedicatedHostsClient client.
+func NewDedicatedHostsClient(subscriptionID string) DedicatedHostsClient {
+ return NewDedicatedHostsClientWithBaseURI(DefaultBaseURI, subscriptionID)
+}
+
+// NewDedicatedHostsClientWithBaseURI creates an instance of the DedicatedHostsClient client.
+func NewDedicatedHostsClientWithBaseURI(baseURI string, subscriptionID string) DedicatedHostsClient {
+ return DedicatedHostsClient{NewWithBaseURI(baseURI, subscriptionID)}
+}
+
+// CreateOrUpdate create or update a dedicated host .
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// hostGroupName - the name of the dedicated host group.
+// hostName - the name of the dedicated host .
+// parameters - parameters supplied to the Create Dedicated Host.
+func (client DedicatedHostsClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, hostGroupName string, hostName string, parameters DedicatedHost) (result DedicatedHostsCreateOrUpdateFuture, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostsClient.CreateOrUpdate")
+ defer func() {
+ sc := -1
+ if result.Response() != nil {
+ sc = result.Response().StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ if err := validation.Validate([]validation.Validation{
+ {TargetValue: parameters,
+ Constraints: []validation.Constraint{{Target: "parameters.DedicatedHostProperties", Name: validation.Null, Rule: false,
+ Chain: []validation.Constraint{{Target: "parameters.DedicatedHostProperties.PlatformFaultDomain", Name: validation.Null, Rule: false,
+ Chain: []validation.Constraint{{Target: "parameters.DedicatedHostProperties.PlatformFaultDomain", Name: validation.InclusiveMaximum, Rule: int64(2), Chain: nil},
+ {Target: "parameters.DedicatedHostProperties.PlatformFaultDomain", Name: validation.InclusiveMinimum, Rule: 0, Chain: nil},
+ }},
+ }},
+ {Target: "parameters.Sku", Name: validation.Null, Rule: true, Chain: nil}}}}); err != nil {
+ return result, validation.NewError("compute.DedicatedHostsClient", "CreateOrUpdate", err.Error())
+ }
+
+ req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, hostGroupName, hostName, parameters)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "CreateOrUpdate", nil, "Failure preparing request")
+ return
+ }
+
+ result, err = client.CreateOrUpdateSender(req)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "CreateOrUpdate", result.Response(), "Failure sending request")
+ return
+ }
+
+ return
+}
+
+// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
+func (client DedicatedHostsClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, hostGroupName string, hostName string, parameters DedicatedHost) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "hostGroupName": autorest.Encode("path", hostGroupName),
+ "hostName": autorest.Encode("path", hostName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsContentType("application/json; charset=utf-8"),
+ autorest.AsPut(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/hostGroups/{hostGroupName}/hosts/{hostName}", pathParameters),
+ autorest.WithJSON(parameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the
+// http.Response Body if it receives an error.
+func (client DedicatedHostsClient) CreateOrUpdateSender(req *http.Request) (future DedicatedHostsCreateOrUpdateFuture, err error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ var resp *http.Response
+ resp, err = autorest.SendWithSender(client, req, sd...)
+ if err != nil {
+ return
+ }
+ future.Future, err = azure.NewFutureFromResponse(resp)
+ return
+}
+
+// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
+// closes the http.Response Body.
+func (client DedicatedHostsClient) CreateOrUpdateResponder(resp *http.Response) (result DedicatedHost, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// Delete delete a dedicated host.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// hostGroupName - the name of the dedicated host group.
+// hostName - the name of the dedicated host.
+func (client DedicatedHostsClient) Delete(ctx context.Context, resourceGroupName string, hostGroupName string, hostName string) (result DedicatedHostsDeleteFuture, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostsClient.Delete")
+ defer func() {
+ sc := -1
+ if result.Response() != nil {
+ sc = result.Response().StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.DeletePreparer(ctx, resourceGroupName, hostGroupName, hostName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "Delete", nil, "Failure preparing request")
+ return
+ }
+
+ result, err = client.DeleteSender(req)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "Delete", result.Response(), "Failure sending request")
+ return
+ }
+
+ return
+}
+
+// DeletePreparer prepares the Delete request.
+func (client DedicatedHostsClient) DeletePreparer(ctx context.Context, resourceGroupName string, hostGroupName string, hostName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "hostGroupName": autorest.Encode("path", hostGroupName),
+ "hostName": autorest.Encode("path", hostName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsDelete(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/hostGroups/{hostGroupName}/hosts/{hostName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// DeleteSender sends the Delete request. The method will close the
+// http.Response Body if it receives an error.
+func (client DedicatedHostsClient) DeleteSender(req *http.Request) (future DedicatedHostsDeleteFuture, err error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ var resp *http.Response
+ resp, err = autorest.SendWithSender(client, req, sd...)
+ if err != nil {
+ return
+ }
+ future.Future, err = azure.NewFutureFromResponse(resp)
+ return
+}
+
+// DeleteResponder handles the response to the Delete request. The method always
+// closes the http.Response Body.
+func (client DedicatedHostsClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent),
+ autorest.ByClosing())
+ result.Response = resp
+ return
+}
+
+// Get retrieves information about a dedicated host.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// hostGroupName - the name of the dedicated host group.
+// hostName - the name of the dedicated host.
+// expand - the expand expression to apply on the operation.
+func (client DedicatedHostsClient) Get(ctx context.Context, resourceGroupName string, hostGroupName string, hostName string, expand InstanceViewTypes) (result DedicatedHost, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostsClient.Get")
+ defer func() {
+ sc := -1
+ if result.Response.Response != nil {
+ sc = result.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.GetPreparer(ctx, resourceGroupName, hostGroupName, hostName, expand)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "Get", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.GetSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "Get", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.GetResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "Get", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// GetPreparer prepares the Get request.
+func (client DedicatedHostsClient) GetPreparer(ctx context.Context, resourceGroupName string, hostGroupName string, hostName string, expand InstanceViewTypes) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "hostGroupName": autorest.Encode("path", hostGroupName),
+ "hostName": autorest.Encode("path", hostName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+ if len(string(expand)) > 0 {
+ queryParameters["$expand"] = autorest.Encode("query", expand)
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/hostGroups/{hostGroupName}/hosts/{hostName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// GetSender sends the Get request. The method will close the
+// http.Response Body if it receives an error.
+func (client DedicatedHostsClient) GetSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// GetResponder handles the response to the Get request. The method always
+// closes the http.Response Body.
+func (client DedicatedHostsClient) GetResponder(resp *http.Response) (result DedicatedHost, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// ListByHostGroup lists all of the dedicated hosts in the specified dedicated host group. Use the nextLink property in
+// the response to get the next page of dedicated hosts.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// hostGroupName - the name of the dedicated host group.
+func (client DedicatedHostsClient) ListByHostGroup(ctx context.Context, resourceGroupName string, hostGroupName string) (result DedicatedHostListResultPage, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DedicatedHostsClient.ListByHostGroup")
+ defer func() {
+ sc := -1
+ if result.dhlr.Response.Response != nil {
+ sc = result.dhlr.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ result.fn = client.listByHostGroupNextResults
+ req, err := client.ListByHostGroupPreparer(ctx, resourceGroupName, hostGroupName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "ListByHostGroup", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.ListByHostGroupSender(req)
+ if err != nil {
+ result.dhlr.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "ListByHostGroup", resp, "Failure sending request")
+ return
+ }
+
+ result.dhlr, err = client.ListByHostGroupResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "ListByHostGroup", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// ListByHostGroupPreparer prepares the ListByHostGroup request.
+func (client DedicatedHostsClient) ListByHostGroupPreparer(ctx context.Context, resourceGroupName string, hostGroupName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "hostGroupName": autorest.Encode("path", hostGroupName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/hostGroups/{hostGroupName}/hosts", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// ListByHostGroupSender sends the ListByHostGroup request. The method will close the
+// http.Response Body if it receives an error.
+func (client DedicatedHostsClient) ListByHostGroupSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// ListByHostGroupResponder handles the response to the ListByHostGroup request. The method always
+// closes the http.Response Body.
+func (client DedicatedHostsClient) ListByHostGroupResponder(resp *http.Response) (result DedicatedHostListResult, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// listByHostGroupNextResults retrieves the next set of results, if any.
+func (client DedicatedHostsClient) listByHostGroupNextResults(ctx context.Context, lastResults DedicatedHostListResult) (result DedicatedHostListResult, err error) {
+ req, err := lastResults.dedicatedHostListResultPreparer(ctx)
+ if err != nil {
+ return result, autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "listByHostGroupNextResults", nil, "Failure preparing next results request")
+ }
+ if req == nil {
+ return
+ }
+ resp, err := client.ListByHostGroupSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ return result, autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "listByHostGroupNextResults", resp, "Failure sending next results request")
+ }
+ result, err = client.ListByHostGroupResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DedicatedHostsClient", "listByHostGroupNextResults", resp, "Failure responding to next results request")
+ }
+ return
+}
+
+// ListByHostGroupComplete enumerates all values, automatically crossing page boundaries as required.
… diff truncated
vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute/diskencryptionsets.go+399 0
@@ -0,0 +1,599 @@
+package compute
+
+// Copyright (c) Microsoft and contributors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Code generated by Microsoft (R) AutoRest Code Generator.
+// Changes may cause incorrect behavior and will be lost if the code is regenerated.
+
+import (
+ "context"
+ "github.com/Azure/go-autorest/autorest"
+ "github.com/Azure/go-autorest/autorest/azure"
+ "github.com/Azure/go-autorest/autorest/validation"
+ "github.com/Azure/go-autorest/tracing"
+ "net/http"
+)
+
+// DiskEncryptionSetsClient is the compute Client
+type DiskEncryptionSetsClient struct {
+ BaseClient
+}
+
+// NewDiskEncryptionSetsClient creates an instance of the DiskEncryptionSetsClient client.
+func NewDiskEncryptionSetsClient(subscriptionID string) DiskEncryptionSetsClient {
+ return NewDiskEncryptionSetsClientWithBaseURI(DefaultBaseURI, subscriptionID)
+}
+
+// NewDiskEncryptionSetsClientWithBaseURI creates an instance of the DiskEncryptionSetsClient client.
+func NewDiskEncryptionSetsClientWithBaseURI(baseURI string, subscriptionID string) DiskEncryptionSetsClient {
+ return DiskEncryptionSetsClient{NewWithBaseURI(baseURI, subscriptionID)}
+}
+
+// CreateOrUpdate creates or updates a disk encryption set
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// diskEncryptionSetName - the name of the disk encryption set that is being created. The name can't be changed
+// after the disk encryption set is created. Supported characters for the name are a-z, A-Z, 0-9 and _. The
+// maximum name length is 80 characters.
+// diskEncryptionSet - disk encryption set object supplied in the body of the Put disk encryption set
+// operation.
+func (client DiskEncryptionSetsClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, diskEncryptionSetName string, diskEncryptionSet DiskEncryptionSet) (result DiskEncryptionSetsCreateOrUpdateFuture, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DiskEncryptionSetsClient.CreateOrUpdate")
+ defer func() {
+ sc := -1
+ if result.Response() != nil {
+ sc = result.Response().StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ if err := validation.Validate([]validation.Validation{
+ {TargetValue: diskEncryptionSet,
+ Constraints: []validation.Constraint{{Target: "diskEncryptionSet.EncryptionSetProperties", Name: validation.Null, Rule: false,
+ Chain: []validation.Constraint{{Target: "diskEncryptionSet.EncryptionSetProperties.ActiveKey", Name: validation.Null, Rule: false,
+ Chain: []validation.Constraint{{Target: "diskEncryptionSet.EncryptionSetProperties.ActiveKey.SourceVault", Name: validation.Null, Rule: true, Chain: nil},
+ {Target: "diskEncryptionSet.EncryptionSetProperties.ActiveKey.KeyURL", Name: validation.Null, Rule: true, Chain: nil},
+ }},
+ }}}}}); err != nil {
+ return result, validation.NewError("compute.DiskEncryptionSetsClient", "CreateOrUpdate", err.Error())
+ }
+
+ req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, diskEncryptionSetName, diskEncryptionSet)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "CreateOrUpdate", nil, "Failure preparing request")
+ return
+ }
+
+ result, err = client.CreateOrUpdateSender(req)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "CreateOrUpdate", result.Response(), "Failure sending request")
+ return
+ }
+
+ return
+}
+
+// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
+func (client DiskEncryptionSetsClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, diskEncryptionSetName string, diskEncryptionSet DiskEncryptionSet) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "diskEncryptionSetName": autorest.Encode("path", diskEncryptionSetName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsContentType("application/json; charset=utf-8"),
+ autorest.AsPut(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/diskEncryptionSets/{diskEncryptionSetName}", pathParameters),
+ autorest.WithJSON(diskEncryptionSet),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the
+// http.Response Body if it receives an error.
+func (client DiskEncryptionSetsClient) CreateOrUpdateSender(req *http.Request) (future DiskEncryptionSetsCreateOrUpdateFuture, err error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ var resp *http.Response
+ resp, err = autorest.SendWithSender(client, req, sd...)
+ if err != nil {
+ return
+ }
+ future.Future, err = azure.NewFutureFromResponse(resp)
+ return
+}
+
+// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
+// closes the http.Response Body.
+func (client DiskEncryptionSetsClient) CreateOrUpdateResponder(resp *http.Response) (result DiskEncryptionSet, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// Delete deletes a disk encryption set.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// diskEncryptionSetName - the name of the disk encryption set that is being created. The name can't be changed
+// after the disk encryption set is created. Supported characters for the name are a-z, A-Z, 0-9 and _. The
+// maximum name length is 80 characters.
+func (client DiskEncryptionSetsClient) Delete(ctx context.Context, resourceGroupName string, diskEncryptionSetName string) (result DiskEncryptionSetsDeleteFuture, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DiskEncryptionSetsClient.Delete")
+ defer func() {
+ sc := -1
+ if result.Response() != nil {
+ sc = result.Response().StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.DeletePreparer(ctx, resourceGroupName, diskEncryptionSetName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "Delete", nil, "Failure preparing request")
+ return
+ }
+
+ result, err = client.DeleteSender(req)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "Delete", result.Response(), "Failure sending request")
+ return
+ }
+
+ return
+}
+
+// DeletePreparer prepares the Delete request.
+func (client DiskEncryptionSetsClient) DeletePreparer(ctx context.Context, resourceGroupName string, diskEncryptionSetName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "diskEncryptionSetName": autorest.Encode("path", diskEncryptionSetName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsDelete(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/diskEncryptionSets/{diskEncryptionSetName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// DeleteSender sends the Delete request. The method will close the
+// http.Response Body if it receives an error.
+func (client DiskEncryptionSetsClient) DeleteSender(req *http.Request) (future DiskEncryptionSetsDeleteFuture, err error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ var resp *http.Response
+ resp, err = autorest.SendWithSender(client, req, sd...)
+ if err != nil {
+ return
+ }
+ future.Future, err = azure.NewFutureFromResponse(resp)
+ return
+}
+
+// DeleteResponder handles the response to the Delete request. The method always
+// closes the http.Response Body.
+func (client DiskEncryptionSetsClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent),
+ autorest.ByClosing())
+ result.Response = resp
+ return
+}
+
+// Get gets information about a disk encryption set.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// diskEncryptionSetName - the name of the disk encryption set that is being created. The name can't be changed
+// after the disk encryption set is created. Supported characters for the name are a-z, A-Z, 0-9 and _. The
+// maximum name length is 80 characters.
+func (client DiskEncryptionSetsClient) Get(ctx context.Context, resourceGroupName string, diskEncryptionSetName string) (result DiskEncryptionSet, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DiskEncryptionSetsClient.Get")
+ defer func() {
+ sc := -1
+ if result.Response.Response != nil {
+ sc = result.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.GetPreparer(ctx, resourceGroupName, diskEncryptionSetName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "Get", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.GetSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "Get", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.GetResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "Get", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// GetPreparer prepares the Get request.
+func (client DiskEncryptionSetsClient) GetPreparer(ctx context.Context, resourceGroupName string, diskEncryptionSetName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "diskEncryptionSetName": autorest.Encode("path", diskEncryptionSetName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/diskEncryptionSets/{diskEncryptionSetName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// GetSender sends the Get request. The method will close the
+// http.Response Body if it receives an error.
+func (client DiskEncryptionSetsClient) GetSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// GetResponder handles the response to the Get request. The method always
+// closes the http.Response Body.
+func (client DiskEncryptionSetsClient) GetResponder(resp *http.Response) (result DiskEncryptionSet, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// List lists all the disk encryption sets under a subscription.
+func (client DiskEncryptionSetsClient) List(ctx context.Context) (result DiskEncryptionSetListPage, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DiskEncryptionSetsClient.List")
+ defer func() {
+ sc := -1
+ if result.desl.Response.Response != nil {
+ sc = result.desl.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ result.fn = client.listNextResults
+ req, err := client.ListPreparer(ctx)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "List", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.ListSender(req)
+ if err != nil {
+ result.desl.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "List", resp, "Failure sending request")
+ return
+ }
+
+ result.desl, err = client.ListResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "List", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// ListPreparer prepares the List request.
+func (client DiskEncryptionSetsClient) ListPreparer(ctx context.Context) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.Compute/diskEncryptionSets", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// ListSender sends the List request. The method will close the
+// http.Response Body if it receives an error.
+func (client DiskEncryptionSetsClient) ListSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// ListResponder handles the response to the List request. The method always
+// closes the http.Response Body.
+func (client DiskEncryptionSetsClient) ListResponder(resp *http.Response) (result DiskEncryptionSetList, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// listNextResults retrieves the next set of results, if any.
+func (client DiskEncryptionSetsClient) listNextResults(ctx context.Context, lastResults DiskEncryptionSetList) (result DiskEncryptionSetList, err error) {
+ req, err := lastResults.diskEncryptionSetListPreparer(ctx)
+ if err != nil {
+ return result, autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "listNextResults", nil, "Failure preparing next results request")
+ }
+ if req == nil {
+ return
+ }
+ resp, err := client.ListSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ return result, autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "listNextResults", resp, "Failure sending next results request")
+ }
+ result, err = client.ListResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.DiskEncryptionSetsClient", "listNextResults", resp, "Failure responding to next results request")
+ }
+ return
+}
+
+// ListComplete enumerates all values, automatically crossing page boundaries as required.
+func (client DiskEncryptionSetsClient) ListComplete(ctx context.Context) (result DiskEncryptionSetListIterator, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/DiskEncryptionSetsClient.List")
+ defer func() {
+ sc := -1
+ if result.Response().Response.Response != nil {
+ sc = result.page.Response().Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
… diff truncated
vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute/galleryimages.go+399 0
@@ -0,0 +1,410 @@
+package compute
+
+// Copyright (c) Microsoft and contributors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Code generated by Microsoft (R) AutoRest Code Generator.
+// Changes may cause incorrect behavior and will be lost if the code is regenerated.
+
+import (
+ "context"
+ "github.com/Azure/go-autorest/autorest"
+ "github.com/Azure/go-autorest/autorest/azure"
+ "github.com/Azure/go-autorest/autorest/validation"
+ "github.com/Azure/go-autorest/tracing"
+ "net/http"
+)
+
+// GalleryImagesClient is the compute Client
+type GalleryImagesClient struct {
+ BaseClient
+}
+
+// NewGalleryImagesClient creates an instance of the GalleryImagesClient client.
+func NewGalleryImagesClient(subscriptionID string) GalleryImagesClient {
+ return NewGalleryImagesClientWithBaseURI(DefaultBaseURI, subscriptionID)
+}
+
+// NewGalleryImagesClientWithBaseURI creates an instance of the GalleryImagesClient client.
+func NewGalleryImagesClientWithBaseURI(baseURI string, subscriptionID string) GalleryImagesClient {
+ return GalleryImagesClient{NewWithBaseURI(baseURI, subscriptionID)}
+}
+
+// CreateOrUpdate create or update a gallery Image Definition.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// galleryName - the name of the Shared Image Gallery in which the Image Definition is to be created.
+// galleryImageName - the name of the gallery Image Definition to be created or updated. The allowed characters
+// are alphabets and numbers with dots, dashes, and periods allowed in the middle. The maximum length is 80
+// characters.
+// galleryImage - parameters supplied to the create or update gallery image operation.
+func (client GalleryImagesClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string, galleryImage GalleryImage) (result GalleryImagesCreateOrUpdateFuture, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/GalleryImagesClient.CreateOrUpdate")
+ defer func() {
+ sc := -1
+ if result.Response() != nil {
+ sc = result.Response().StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ if err := validation.Validate([]validation.Validation{
+ {TargetValue: galleryImage,
+ Constraints: []validation.Constraint{{Target: "galleryImage.GalleryImageProperties", Name: validation.Null, Rule: false,
+ Chain: []validation.Constraint{{Target: "galleryImage.GalleryImageProperties.Identifier", Name: validation.Null, Rule: true,
+ Chain: []validation.Constraint{{Target: "galleryImage.GalleryImageProperties.Identifier.Publisher", Name: validation.Null, Rule: true, Chain: nil},
+ {Target: "galleryImage.GalleryImageProperties.Identifier.Offer", Name: validation.Null, Rule: true, Chain: nil},
+ {Target: "galleryImage.GalleryImageProperties.Identifier.Sku", Name: validation.Null, Rule: true, Chain: nil},
+ }},
+ }}}}}); err != nil {
+ return result, validation.NewError("compute.GalleryImagesClient", "CreateOrUpdate", err.Error())
+ }
+
+ req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, galleryName, galleryImageName, galleryImage)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "CreateOrUpdate", nil, "Failure preparing request")
+ return
+ }
+
+ result, err = client.CreateOrUpdateSender(req)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "CreateOrUpdate", result.Response(), "Failure sending request")
+ return
+ }
+
+ return
+}
+
+// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
+func (client GalleryImagesClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string, galleryImage GalleryImage) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "galleryImageName": autorest.Encode("path", galleryImageName),
+ "galleryName": autorest.Encode("path", galleryName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsContentType("application/json; charset=utf-8"),
+ autorest.AsPut(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{galleryImageName}", pathParameters),
+ autorest.WithJSON(galleryImage),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the
+// http.Response Body if it receives an error.
+func (client GalleryImagesClient) CreateOrUpdateSender(req *http.Request) (future GalleryImagesCreateOrUpdateFuture, err error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ var resp *http.Response
+ resp, err = autorest.SendWithSender(client, req, sd...)
+ if err != nil {
+ return
+ }
+ future.Future, err = azure.NewFutureFromResponse(resp)
+ return
+}
+
+// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
+// closes the http.Response Body.
+func (client GalleryImagesClient) CreateOrUpdateResponder(resp *http.Response) (result GalleryImage, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated, http.StatusAccepted),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// Delete delete a gallery image.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// galleryName - the name of the Shared Image Gallery in which the Image Definition is to be deleted.
+// galleryImageName - the name of the gallery Image Definition to be deleted.
+func (client GalleryImagesClient) Delete(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string) (result GalleryImagesDeleteFuture, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/GalleryImagesClient.Delete")
+ defer func() {
+ sc := -1
+ if result.Response() != nil {
+ sc = result.Response().StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.DeletePreparer(ctx, resourceGroupName, galleryName, galleryImageName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "Delete", nil, "Failure preparing request")
+ return
+ }
+
+ result, err = client.DeleteSender(req)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "Delete", result.Response(), "Failure sending request")
+ return
+ }
+
+ return
+}
+
+// DeletePreparer prepares the Delete request.
+func (client GalleryImagesClient) DeletePreparer(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "galleryImageName": autorest.Encode("path", galleryImageName),
+ "galleryName": autorest.Encode("path", galleryName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsDelete(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{galleryImageName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// DeleteSender sends the Delete request. The method will close the
+// http.Response Body if it receives an error.
+func (client GalleryImagesClient) DeleteSender(req *http.Request) (future GalleryImagesDeleteFuture, err error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ var resp *http.Response
+ resp, err = autorest.SendWithSender(client, req, sd...)
+ if err != nil {
+ return
+ }
+ future.Future, err = azure.NewFutureFromResponse(resp)
+ return
+}
+
+// DeleteResponder handles the response to the Delete request. The method always
+// closes the http.Response Body.
+func (client GalleryImagesClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent),
+ autorest.ByClosing())
+ result.Response = resp
+ return
+}
+
+// Get retrieves information about a gallery Image Definition.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// galleryName - the name of the Shared Image Gallery from which the Image Definitions are to be retrieved.
+// galleryImageName - the name of the gallery Image Definition to be retrieved.
+func (client GalleryImagesClient) Get(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string) (result GalleryImage, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/GalleryImagesClient.Get")
+ defer func() {
+ sc := -1
+ if result.Response.Response != nil {
+ sc = result.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ req, err := client.GetPreparer(ctx, resourceGroupName, galleryName, galleryImageName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "Get", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.GetSender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "Get", resp, "Failure sending request")
+ return
+ }
+
+ result, err = client.GetResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "Get", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// GetPreparer prepares the Get request.
+func (client GalleryImagesClient) GetPreparer(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "galleryImageName": autorest.Encode("path", galleryImageName),
+ "galleryName": autorest.Encode("path", galleryName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{galleryImageName}", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// GetSender sends the Get request. The method will close the
+// http.Response Body if it receives an error.
+func (client GalleryImagesClient) GetSender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// GetResponder handles the response to the Get request. The method always
+// closes the http.Response Body.
+func (client GalleryImagesClient) GetResponder(resp *http.Response) (result GalleryImage, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// ListByGallery list gallery Image Definitions in a gallery.
+// Parameters:
+// resourceGroupName - the name of the resource group.
+// galleryName - the name of the Shared Image Gallery from which Image Definitions are to be listed.
+func (client GalleryImagesClient) ListByGallery(ctx context.Context, resourceGroupName string, galleryName string) (result GalleryImageListPage, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/GalleryImagesClient.ListByGallery")
+ defer func() {
+ sc := -1
+ if result.gil.Response.Response != nil {
+ sc = result.gil.Response.Response.StatusCode
+ }
+ tracing.EndSpan(ctx, sc, err)
+ }()
+ }
+ result.fn = client.listByGalleryNextResults
+ req, err := client.ListByGalleryPreparer(ctx, resourceGroupName, galleryName)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "ListByGallery", nil, "Failure preparing request")
+ return
+ }
+
+ resp, err := client.ListByGallerySender(req)
+ if err != nil {
+ result.gil.Response = autorest.Response{Response: resp}
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "ListByGallery", resp, "Failure sending request")
+ return
+ }
+
+ result.gil, err = client.ListByGalleryResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "ListByGallery", resp, "Failure responding to request")
+ }
+
+ return
+}
+
+// ListByGalleryPreparer prepares the ListByGallery request.
+func (client GalleryImagesClient) ListByGalleryPreparer(ctx context.Context, resourceGroupName string, galleryName string) (*http.Request, error) {
+ pathParameters := map[string]interface{}{
+ "galleryName": autorest.Encode("path", galleryName),
+ "resourceGroupName": autorest.Encode("path", resourceGroupName),
+ "subscriptionId": autorest.Encode("path", client.SubscriptionID),
+ }
+
+ const APIVersion = "2019-07-01"
+ queryParameters := map[string]interface{}{
+ "api-version": APIVersion,
+ }
+
+ preparer := autorest.CreatePreparer(
+ autorest.AsGet(),
+ autorest.WithBaseURL(client.BaseURI),
+ autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/images", pathParameters),
+ autorest.WithQueryParameters(queryParameters))
+ return preparer.Prepare((&http.Request{}).WithContext(ctx))
+}
+
+// ListByGallerySender sends the ListByGallery request. The method will close the
+// http.Response Body if it receives an error.
+func (client GalleryImagesClient) ListByGallerySender(req *http.Request) (*http.Response, error) {
+ sd := autorest.GetSendDecorators(req.Context(), azure.DoRetryWithRegistration(client.Client))
+ return autorest.SendWithSender(client, req, sd...)
+}
+
+// ListByGalleryResponder handles the response to the ListByGallery request. The method always
+// closes the http.Response Body.
+func (client GalleryImagesClient) ListByGalleryResponder(resp *http.Response) (result GalleryImageList, err error) {
+ err = autorest.Respond(
+ resp,
+ client.ByInspecting(),
+ azure.WithErrorUnlessStatusCode(http.StatusOK),
+ autorest.ByUnmarshallingJSON(&result),
+ autorest.ByClosing())
+ result.Response = autorest.Response{Response: resp}
+ return
+}
+
+// listByGalleryNextResults retrieves the next set of results, if any.
+func (client GalleryImagesClient) listByGalleryNextResults(ctx context.Context, lastResults GalleryImageList) (result GalleryImageList, err error) {
+ req, err := lastResults.galleryImageListPreparer(ctx)
+ if err != nil {
+ return result, autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "listByGalleryNextResults", nil, "Failure preparing next results request")
+ }
+ if req == nil {
+ return
+ }
+ resp, err := client.ListByGallerySender(req)
+ if err != nil {
+ result.Response = autorest.Response{Response: resp}
+ return result, autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "listByGalleryNextResults", resp, "Failure sending next results request")
+ }
+ result, err = client.ListByGalleryResponder(resp)
+ if err != nil {
+ err = autorest.NewErrorWithError(err, "compute.GalleryImagesClient", "listByGalleryNextResults", resp, "Failure responding to next results request")
+ }
+ return
+}
+
+// ListByGalleryComplete enumerates all values, automatically crossing page boundaries as required.
+func (client GalleryImagesClient) ListByGalleryComplete(ctx context.Context, resourceGroupName string, galleryName string) (result GalleryImageListIterator, err error) {
+ if tracing.IsEnabled() {
+ ctx = tracing.StartSpan(ctx, fqdn+"/GalleryImagesClient.ListByGallery")
… diff truncated
command/kv_metadata_put_test.go+76 0
@@ -0,0 +1,76 @@
+package command
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/vault/api"
+ "github.com/mitchellh/cli"
+)
+
+func testKVMetadataPutCommand(tb testing.TB) (*cli.MockUi, *KVMetadataPutCommand) {
+ tb.Helper()
+
+ ui := cli.NewMockUi()
+ return ui, &KVMetadataPutCommand{
+ BaseCommand: &BaseCommand{
+ UI: ui,
+ },
+ }
+}
+
+func TestKvMetadataPutCommandDeleteVersionAfter(t *testing.T) {
+ client, closer := testVaultServer(t)
+ defer closer()
+
+ if err := client.Sys().Mount("kv/", &api.MountInput{
+ Type: "kv-v2",
+ }); err != nil {
+ t.Fatal(err)
+ }
+
+ ui, cmd := testKVMetadataPutCommand(t)
+ cmd.client = client
+
+ // Set a limit of 1s first.
+ code := cmd.Run([]string{"-delete-version-after=1s", "kv/secret/my-secret"})
+ if code != 0 {
+ t.Errorf("expected %d but received %d", 0, code)
+ }
+
+ combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
+ if !strings.Contains(combined, "Success! Data written to: kv/metadata/secret/my-secret\n") {
+ t.Errorf("expected %q but received %q", "Success! Data written to: kv/metadata/secret/my-secret\n", combined)
+ }
+
+ secret, err := client.Logical().Read("kv/metadata/secret/my-secret")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if secret.Data["delete_version_after"] != "1s" {
+ t.Fatalf("expected 1s but received %q", secret.Data["delete_version_after"])
+ }
+
+ // Now verify that we can return it to 0s.
+ ui, cmd = testKVMetadataPutCommand(t)
+ cmd.client = client
+
+ // Set a limit of 1s first.
+ code = cmd.Run([]string{"-delete-version-after=0", "kv/secret/my-secret"})
+ if code != 0 {
+ t.Errorf("expected %d but received %d", 0, code)
+ }
+
+ combined = ui.OutputWriter.String() + ui.ErrorWriter.String()
+ if !strings.Contains(combined, "Success! Data written to: kv/metadata/secret/my-secret\n") {
+ t.Errorf("expected %q but received %q", "Success! Data written to: kv/metadata/secret/my-secret\n", combined)
+ }
+
+ secret, err = client.Logical().Read("kv/metadata/secret/my-secret")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if secret.Data["delete_version_after"] != "0s" {
+ t.Fatalf("expected 0s but received %q", secret.Data["delete_version_after"])
+ }
+}
ui/app/templates/components/shamir-flow.hbs | 27 ++++++++++++++-------
1 file changed, 18 insertions(+), 9 deletions(-)
More files changed — see the full commit.

References