Files
vault/builtin/credential/approle/path_login_test.go
hashicorp-copywrite[bot] 0b12cdcfd1 [COMPLIANCE] License changes (#22290)
* Adding explicit MPL license for sub-package.

This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository.

* Adding explicit MPL license for sub-package.

This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository.

* Updating the license from MPL to Business Source License.

Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl.

* add missing license headers

* Update copyright file headers to BUS-1.1

* Fix test that expected exact offset on hcl file

---------

Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Sarah Thompson <sthompson@hashicorp.com>
Co-authored-by: Brian Kassouf <bkassouf@hashicorp.com>
2023-08-10 18:14:03 -07:00

361 lines
9.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package approle
import (
"context"
"strings"
"testing"
"time"
"github.com/hashicorp/vault/sdk/logical"
)
func TestAppRole_BoundCIDRLogin(t *testing.T) {
var resp *logical.Response
var err error
b, s := createBackendWithStorage(t)
// Create a role with secret ID binding disabled and only bound cidr list
// enabled
resp = b.requestNoErr(t, &logical.Request{
Path: "role/testrole",
Operation: logical.CreateOperation,
Data: map[string]interface{}{
"bind_secret_id": false,
"bound_cidr_list": []string{"127.0.0.1/8"},
"token_bound_cidrs": []string{"10.0.0.0/8"},
},
Storage: s,
})
// Read the role ID
resp = b.requestNoErr(t, &logical.Request{
Path: "role/testrole/role-id",
Operation: logical.ReadOperation,
Storage: s,
})
roleID := resp.Data["role_id"]
// Fill in the connection information and login with just the role ID
resp = b.requestNoErr(t, &logical.Request{
Path: "login",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"role_id": roleID,
},
Storage: s,
Connection: &logical.Connection{RemoteAddr: "127.0.0.1"},
})
if resp.Auth == nil {
t.Fatal("expected login to succeed")
}
if len(resp.Auth.BoundCIDRs) != 1 {
t.Fatal("bad token bound cidrs")
}
if resp.Auth.BoundCIDRs[0].String() != "10.0.0.0/8" {
t.Fatalf("bad: %s", resp.Auth.BoundCIDRs[0].String())
}
// Override with a secret-id value, verify it doesn't pass
resp = b.requestNoErr(t, &logical.Request{
Path: "role/testrole",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"bind_secret_id": true,
},
Storage: s,
})
roleSecretIDReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "role/testrole/secret-id",
Storage: s,
Data: map[string]interface{}{
"token_bound_cidrs": []string{"11.0.0.0/24"},
},
}
resp, err = b.HandleRequest(context.Background(), roleSecretIDReq)
if err == nil {
t.Fatal("expected error due to mismatching subnet relationship")
}
roleSecretIDReq.Data["token_bound_cidrs"] = "10.0.0.0/24"
resp = b.requestNoErr(t, roleSecretIDReq)
secretID := resp.Data["secret_id"]
resp = b.requestNoErr(t, &logical.Request{
Path: "login",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"role_id": roleID,
"secret_id": secretID,
},
Storage: s,
Connection: &logical.Connection{RemoteAddr: "127.0.0.1"},
})
if resp.Auth == nil {
t.Fatal("expected login to succeed")
}
if len(resp.Auth.BoundCIDRs) != 1 {
t.Fatal("bad token bound cidrs")
}
if resp.Auth.BoundCIDRs[0].String() != "10.0.0.0/24" {
t.Fatalf("bad: %s", resp.Auth.BoundCIDRs[0].String())
}
}
func TestAppRole_RoleLogin(t *testing.T) {
var resp *logical.Response
var err error
b, storage := createBackendWithStorage(t)
createRole(t, b, storage, "role1", "a,b,c")
roleRoleIDReq := &logical.Request{
Operation: logical.ReadOperation,
Path: "role/role1/role-id",
Storage: storage,
}
resp = b.requestNoErr(t, roleRoleIDReq)
roleID := resp.Data["role_id"]
roleSecretIDReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "role/role1/secret-id",
Storage: storage,
}
resp = b.requestNoErr(t, roleSecretIDReq)
secretID := resp.Data["secret_id"]
loginData := map[string]interface{}{
"role_id": roleID,
"secret_id": secretID,
}
loginReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "login",
Storage: storage,
Data: loginData,
Connection: &logical.Connection{
RemoteAddr: "127.0.0.1",
},
}
loginResp, err := b.HandleRequest(context.Background(), loginReq)
if err != nil || (loginResp != nil && loginResp.IsError()) {
t.Fatalf("err:%v resp:%#v", err, loginResp)
}
if loginResp.Auth == nil {
t.Fatalf("expected a non-nil auth object in the response")
}
if loginResp.Auth.Metadata == nil {
t.Fatalf("expected a non-nil metadata object in the response")
}
if val := loginResp.Auth.Metadata["role_name"]; val != "role1" {
t.Fatalf("expected metadata.role_name to equal 'role1', got: %v", val)
}
if loginResp.Auth.Alias.Metadata == nil {
t.Fatalf("expected a non-nil alias metadata object in the response")
}
if val := loginResp.Auth.Alias.Metadata["role_name"]; val != "role1" {
t.Fatalf("expected metadata.alias.role_name to equal 'role1', got: %v", val)
}
// Test renewal
renewReq := generateRenewRequest(storage, loginResp.Auth)
resp, err = b.HandleRequest(context.Background(), renewReq)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err:%v resp:%#v", err, resp)
}
if resp.Auth.TTL != 400*time.Second {
t.Fatalf("expected period value from response to be 400s, got: %s", resp.Auth.TTL)
}
///
// Test renewal with period
///
// Create role
period := 600 * time.Second
roleData := map[string]interface{}{
"policies": "a,b,c",
"period": period.String(),
}
roleReq := &logical.Request{
Operation: logical.CreateOperation,
Path: "role/" + "role-period",
Storage: storage,
Data: roleData,
}
resp = b.requestNoErr(t, roleReq)
roleRoleIDReq = &logical.Request{
Operation: logical.ReadOperation,
Path: "role/role-period/role-id",
Storage: storage,
}
resp = b.requestNoErr(t, roleRoleIDReq)
roleID = resp.Data["role_id"]
roleSecretIDReq = &logical.Request{
Operation: logical.UpdateOperation,
Path: "role/role-period/secret-id",
Storage: storage,
}
resp = b.requestNoErr(t, roleSecretIDReq)
secretID = resp.Data["secret_id"]
loginData["role_id"] = roleID
loginData["secret_id"] = secretID
loginResp, err = b.HandleRequest(context.Background(), loginReq)
if err != nil || (loginResp != nil && loginResp.IsError()) {
t.Fatalf("err:%v resp:%#v", err, loginResp)
}
if loginResp.Auth == nil {
t.Fatalf("expected a non-nil auth object in the response")
}
renewReq = generateRenewRequest(storage, loginResp.Auth)
resp, err = b.HandleRequest(context.Background(), renewReq)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("err:%v resp:%#v", err, resp)
}
if resp.Auth.Period != period {
t.Fatalf("expected period value of %d in the response, got: %s", period, resp.Auth.Period)
}
// Test input validation with secret_id that exceeds max length
loginData["secret_id"] = strings.Repeat("a", maxHmacInputLength+1)
loginReq = &logical.Request{
Operation: logical.UpdateOperation,
Path: "login",
Storage: storage,
Data: loginData,
Connection: &logical.Connection{
RemoteAddr: "127.0.0.1",
},
}
loginResp, err = b.HandleRequest(context.Background(), loginReq)
expectedErr := "failed to create HMAC of secret_id"
if loginResp != nil || err == nil || !strings.Contains(err.Error(), expectedErr) {
t.Fatalf("expected login test to fail with error %q, resp: %#v, err: %v", expectedErr, loginResp, err)
}
}
func generateRenewRequest(s logical.Storage, auth *logical.Auth) *logical.Request {
renewReq := &logical.Request{
Operation: logical.RenewOperation,
Storage: s,
Auth: &logical.Auth{},
}
renewReq.Auth.InternalData = auth.InternalData
renewReq.Auth.Metadata = auth.Metadata
renewReq.Auth.LeaseOptions = auth.LeaseOptions
renewReq.Auth.Policies = auth.Policies
renewReq.Auth.Period = auth.Period
return renewReq
}
func TestAppRole_RoleResolve(t *testing.T) {
b, storage := createBackendWithStorage(t)
role := "role1"
createRole(t, b, storage, role, "a,b,c")
roleRoleIDReq := &logical.Request{
Operation: logical.ReadOperation,
Path: "role/role1/role-id",
Storage: storage,
}
resp := b.requestNoErr(t, roleRoleIDReq)
roleID := resp.Data["role_id"]
roleSecretIDReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "role/role1/secret-id",
Storage: storage,
}
resp = b.requestNoErr(t, roleSecretIDReq)
secretID := resp.Data["secret_id"]
loginData := map[string]interface{}{
"role_id": roleID,
"secret_id": secretID,
}
loginReq := &logical.Request{
Operation: logical.ResolveRoleOperation,
Path: "login",
Storage: storage,
Data: loginData,
Connection: &logical.Connection{
RemoteAddr: "127.0.0.1",
},
}
resp = b.requestNoErr(t, loginReq)
if resp.Data["role"] != role {
t.Fatalf("Role was not as expected. Expected %s, received %s", role, resp.Data["role"])
}
}
func TestAppRole_RoleDoesNotExist(t *testing.T) {
var resp *logical.Response
var err error
b, storage := createBackendWithStorage(t)
roleID := "roleDoesNotExist"
loginData := map[string]interface{}{
"role_id": roleID,
"secret_id": "secret",
}
loginReq := &logical.Request{
Operation: logical.ResolveRoleOperation,
Path: "login",
Storage: storage,
Data: loginData,
Connection: &logical.Connection{
RemoteAddr: "127.0.0.1",
},
}
resp, err = b.HandleRequest(context.Background(), loginReq)
if resp == nil && !resp.IsError() {
t.Fatalf("Response was not an error: err:%v resp:%#v", err, resp)
}
errString, ok := resp.Data["error"].(string)
if !ok {
t.Fatal("Error not part of response.")
}
if !strings.Contains(errString, "invalid role ID") {
t.Fatalf("Error was not due to invalid role ID. Error: %s", errString)
}
}