diff --git a/builtin/credential/approle/path_login.go b/builtin/credential/approle/path_login.go index fce24f540ba5..cec371e7a63b 100644 --- a/builtin/credential/approle/path_login.go +++ b/builtin/credential/approle/path_login.go @@ -83,7 +83,7 @@ func (b *backend) pathLoginUpdate(ctx context.Context, req *logical.Request, dat return logical.ErrorResponse("invalid role ID"), nil } - var metadata map[string]string + metadata := make(map[string]string) if role.BindSecretID { secretID := strings.TrimSpace(data.Get("secret_id").(string)) if secretID == "" { @@ -261,6 +261,12 @@ func (b *backend) pathLoginUpdate(ctx context.Context, req *logical.Request, dat } } + // For some reason, if metadata was set to nil while processing secret ID + // binding, ensure that it is initialized again to avoid a panic. + if metadata == nil { + metadata = make(map[string]string) + } + // Always include the role name, for later filtering metadata["role_name"] = role.name diff --git a/builtin/credential/approle/path_login_test.go b/builtin/credential/approle/path_login_test.go index b5f5cbf6c278..ec23be6d1a4a 100644 --- a/builtin/credential/approle/path_login_test.go +++ b/builtin/credential/approle/path_login_test.go @@ -8,6 +8,58 @@ import ( "github.com/hashicorp/vault/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, err = b.HandleRequest(context.Background(), &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"}, + }, + Storage: s, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%v resp:%#v", err, resp) + } + + // Read the role ID + 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("err:%v resp:%#v", err, resp) + } + + roleID := resp.Data["role_id"] + + // Fill in the connection information and login with just the role ID + resp, err = b.HandleRequest(context.Background(), &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 err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err:%v resp:%#v", err, resp) + } + + // Login should pass + if resp.Auth == nil { + t.Fatalf("expected login to succeed") + } +} + func TestAppRole_RoleLogin(t *testing.T) { var resp *logical.Response var err error