27bb03bbc0
* adding copyright header * fix fmt and a test
431 lines
12 KiB
Go
431 lines
12 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package approle
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
)
|
|
|
|
func createBackendWithStorage(t *testing.T) (*backend, logical.Storage) {
|
|
t.Helper()
|
|
config := logical.TestBackendConfig()
|
|
config.StorageView = &logical.InmemStorage{}
|
|
|
|
b, err := Backend(config)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if b == nil {
|
|
t.Fatalf("failed to create backend")
|
|
}
|
|
err = b.Backend.Setup(context.Background(), config)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return b, config.StorageView
|
|
}
|
|
|
|
func TestAppRole_RoleServiceToBatchNumUses(t *testing.T) {
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
requestFunc := func(operation logical.Operation, data map[string]interface{}) {
|
|
resp, err := b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/testrole",
|
|
Operation: operation,
|
|
Storage: s,
|
|
Data: data,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: err: %#v\nresp: %#v", err, resp)
|
|
}
|
|
}
|
|
|
|
data := map[string]interface{}{
|
|
"bind_secret_id": true,
|
|
"secret_id_num_uses": 0,
|
|
"secret_id_ttl": "10m",
|
|
"token_policies": "policy",
|
|
"token_ttl": "5m",
|
|
"token_max_ttl": "10m",
|
|
"token_num_uses": 2,
|
|
"token_type": "default",
|
|
}
|
|
requestFunc(logical.CreateOperation, data)
|
|
|
|
data["token_num_uses"] = 0
|
|
data["token_type"] = "batch"
|
|
requestFunc(logical.UpdateOperation, data)
|
|
|
|
resp, err := b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/testrole/role-id",
|
|
Operation: logical.ReadOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
roleID := resp.Data["role_id"]
|
|
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/testrole/secret-id",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
secretID := resp.Data["secret_id"]
|
|
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
require.NotNil(t, resp.Auth)
|
|
}
|
|
|
|
func TestAppRole_RoleNameCaseSensitivity(t *testing.T) {
|
|
testFunc := func(t *testing.T, roleName string) {
|
|
var resp *logical.Response
|
|
var err error
|
|
b, s := createBackendWithStorage(t)
|
|
|
|
// Create the role
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName,
|
|
Operation: logical.CreateOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
|
|
}
|
|
|
|
// Get the role-id
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName + "/role-id",
|
|
Operation: logical.ReadOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
roleID := resp.Data["role_id"]
|
|
|
|
// Create a secret-id
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName + "/secret-id",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
secretID := resp.Data["secret_id"]
|
|
secretIDAccessor := resp.Data["secret_id_accessor"]
|
|
|
|
// Ensure login works
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
if resp.Auth == nil {
|
|
t.Fatalf("failed to perform login")
|
|
}
|
|
|
|
// Destroy secret ID accessor
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName + "/secret-id-accessor/destroy",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"secret_id_accessor": secretIDAccessor,
|
|
},
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// Login again using the accessor's corresponding secret ID should fail
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil && err != logical.ErrInvalidCredentials {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil || !resp.IsError() {
|
|
t.Fatalf("expected error due to invalid secret ID")
|
|
}
|
|
|
|
// Generate another secret ID
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName + "/secret-id",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
secretID = resp.Data["secret_id"]
|
|
secretIDAccessor = resp.Data["secret_id_accessor"]
|
|
|
|
// Ensure login works
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
if resp.Auth == nil {
|
|
t.Fatalf("failed to perform login")
|
|
}
|
|
|
|
// Destroy the secret ID
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName + "/secret-id/destroy",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"secret_id": secretID,
|
|
},
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// Login again using the same secret ID should fail
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil && err != logical.ErrInvalidCredentials {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil || !resp.IsError() {
|
|
t.Fatalf("expected error due to invalid secret ID")
|
|
}
|
|
|
|
// Generate another secret ID
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName + "/secret-id",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
secretID = resp.Data["secret_id"]
|
|
secretIDAccessor = resp.Data["secret_id_accessor"]
|
|
|
|
// Ensure login works
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
if resp.Auth == nil {
|
|
t.Fatalf("failed to perform login")
|
|
}
|
|
|
|
// Destroy the secret ID using lower cased role name
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + strings.ToLower(roleName) + "/secret-id/destroy",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"secret_id": secretID,
|
|
},
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// Login again using the same secret ID should fail
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil && err != logical.ErrInvalidCredentials {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil || !resp.IsError() {
|
|
t.Fatalf("expected error due to invalid secret ID")
|
|
}
|
|
|
|
// Generate another secret ID
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName + "/secret-id",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
secretID = resp.Data["secret_id"]
|
|
secretIDAccessor = resp.Data["secret_id_accessor"]
|
|
|
|
// Ensure login works
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
if resp.Auth == nil {
|
|
t.Fatalf("failed to perform login")
|
|
}
|
|
|
|
// Destroy the secret ID using upper cased role name
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + strings.ToUpper(roleName) + "/secret-id/destroy",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"secret_id": secretID,
|
|
},
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// Login again using the same secret ID should fail
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil && err != logical.ErrInvalidCredentials {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil || !resp.IsError() {
|
|
t.Fatalf("expected error due to invalid secret ID")
|
|
}
|
|
|
|
// Generate another secret ID
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/" + roleName + "/secret-id",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
secretID = resp.Data["secret_id"]
|
|
secretIDAccessor = resp.Data["secret_id_accessor"]
|
|
|
|
// Ensure login works
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
if resp.Auth == nil {
|
|
t.Fatalf("failed to perform login")
|
|
}
|
|
|
|
// Destroy the secret ID using mixed case name
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "role/saMpleRolEnaMe/secret-id/destroy",
|
|
Operation: logical.UpdateOperation,
|
|
Storage: s,
|
|
Data: map[string]interface{}{
|
|
"secret_id": secretID,
|
|
},
|
|
})
|
|
if err != nil || (resp != nil && resp.IsError()) {
|
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
|
}
|
|
|
|
// Login again using the same secret ID should fail
|
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
|
Path: "login",
|
|
Operation: logical.UpdateOperation,
|
|
Data: map[string]interface{}{
|
|
"role_id": roleID,
|
|
"secret_id": secretID,
|
|
},
|
|
Storage: s,
|
|
})
|
|
if err != nil && err != logical.ErrInvalidCredentials {
|
|
t.Fatal(err)
|
|
}
|
|
if resp == nil || !resp.IsError() {
|
|
t.Fatalf("expected error due to invalid secret ID")
|
|
}
|
|
}
|
|
|
|
// Lower case role name
|
|
testFunc(t, "samplerolename")
|
|
// Upper case role name
|
|
testFunc(t, "SAMPLEROLENAME")
|
|
// Mixed case role name
|
|
testFunc(t, "SampleRoleName")
|
|
}
|