mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-06 22:57:02 +02:00
update alias lookahead to respect case (#31352)
* userpass is not case sensitive * ldap is case sensitive when it is configured that way --------- Co-authored-by: Ben Ash <bash@hashicorp.com>
This commit is contained in:
parent
8f7d76d781
commit
881febbf98
@ -948,6 +948,121 @@ func TestBackend_configDefaultsAfterUpdate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestLdapAuthBackend_AliasLookaheadDefault will test the alias lookahead functionality
|
||||||
|
// for the LDAP auth backend with a default configuration (i.e. case insensitive if the flag is
|
||||||
|
// not set or is set to false).
|
||||||
|
func TestLdapAuthBackend_AliasLookaheadDefault(t *testing.T) {
|
||||||
|
// create config and storage
|
||||||
|
b, storage := createBackendWithStorage(t)
|
||||||
|
|
||||||
|
// Create user "testuser"
|
||||||
|
resp, err := b.HandleRequest(namespace.RootContext(nil), &logical.Request{
|
||||||
|
Path: "users/testuser",
|
||||||
|
Operation: logical.UpdateOperation,
|
||||||
|
Storage: storage,
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"policies": []string{"default"},
|
||||||
|
"groups": "testgroup,nested/testgroup",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List users
|
||||||
|
resp, err = b.HandleRequest(namespace.RootContext(nil), &logical.Request{
|
||||||
|
Path: "users/",
|
||||||
|
Operation: logical.ListOperation,
|
||||||
|
Storage: storage,
|
||||||
|
})
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||||
|
}
|
||||||
|
expected := []string{"testuser"}
|
||||||
|
if !reflect.DeepEqual(expected, resp.Data["keys"].([]string)) {
|
||||||
|
t.Fatalf("bad: listed users; expected: %#v actual: %#v", expected, resp.Data["keys"].([]string))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
||||||
|
Operation: logical.AliasLookaheadOperation,
|
||||||
|
Storage: storage,
|
||||||
|
Path: "login/testuser",
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"Raw": map[string]interface{}{
|
||||||
|
"username": "testuser",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||||
|
}
|
||||||
|
if resp.Auth.Alias.Name != "testuser" {
|
||||||
|
t.Fatalf("bad: alias lookahead did not return expected alias name; expected: 'testuser', actual: '%s'", resp.Auth.Alias.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestLdapAuthBackend_AliasLookaheadCaseSensitive will test the alias lookahead functionality
|
||||||
|
// for the LDAP auth backend when a case sensitive configuration flag is set
|
||||||
|
func TestLdapAuthBackend_AliasLookaheadCaseSensitive(t *testing.T) {
|
||||||
|
// create config and storage
|
||||||
|
b, storage := createBackendWithStorage(t)
|
||||||
|
|
||||||
|
// make the backend case sensitive
|
||||||
|
resp, err := b.HandleRequest(namespace.RootContext(nil), &logical.Request{
|
||||||
|
Operation: logical.UpdateOperation,
|
||||||
|
Path: "config",
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"case_sensitive_names": true,
|
||||||
|
},
|
||||||
|
Storage: storage,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create user "teSTuser"
|
||||||
|
resp, err = b.HandleRequest(namespace.RootContext(nil), &logical.Request{
|
||||||
|
Path: "users/teSTuser",
|
||||||
|
Operation: logical.UpdateOperation,
|
||||||
|
Storage: storage,
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"policies": []string{"default"},
|
||||||
|
"groups": "testgroup,nested/testgroup",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List users
|
||||||
|
resp, err = b.HandleRequest(namespace.RootContext(nil), &logical.Request{
|
||||||
|
Path: "users/",
|
||||||
|
Operation: logical.ListOperation,
|
||||||
|
Storage: storage,
|
||||||
|
})
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||||
|
}
|
||||||
|
expected := []string{"teSTuser"}
|
||||||
|
if !reflect.DeepEqual(expected, resp.Data["keys"].([]string)) {
|
||||||
|
t.Fatalf("bad: listed users; expected: %#v actual: %#v", expected, resp.Data["keys"].([]string))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(context.Background(), &logical.Request{
|
||||||
|
Operation: logical.AliasLookaheadOperation,
|
||||||
|
Storage: storage,
|
||||||
|
Path: "login/teSTuser",
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"Raw": map[string]interface{}{
|
||||||
|
"username": "teSTuser",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
|
||||||
|
}
|
||||||
|
if resp.Auth.Alias.Name != "teSTuser" {
|
||||||
|
t.Fatalf("bad: alias lookahead did not return expected alias name; expected: 'teSTuser', actual: '%s'", resp.Auth.Alias.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testAccStepConfigUrl(t *testing.T, cfg *ldaputil.ConfigEntry) logicaltest.TestStep {
|
func testAccStepConfigUrl(t *testing.T, cfg *ldaputil.ConfigEntry) logicaltest.TestStep {
|
||||||
return logicaltest.TestStep{
|
return logicaltest.TestStep{
|
||||||
Operation: logical.UpdateOperation,
|
Operation: logical.UpdateOperation,
|
||||||
|
@ -6,6 +6,7 @@ package ldap
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/sdk/framework"
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
"github.com/hashicorp/vault/sdk/helper/cidrutil"
|
"github.com/hashicorp/vault/sdk/helper/cidrutil"
|
||||||
@ -50,6 +51,16 @@ func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Requ
|
|||||||
return nil, fmt.Errorf("missing username")
|
return nil, fmt.Errorf("missing username")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg, err := b.Config(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
caseSensitive := cfg != nil && cfg.CaseSensitiveNames != nil && *cfg.CaseSensitiveNames
|
||||||
|
// if the username is not configured to be case-sensitive, we normalize it to lower case.
|
||||||
|
if !caseSensitive {
|
||||||
|
username = strings.ToLower(username)
|
||||||
|
}
|
||||||
return &logical.Response{
|
return &logical.Response{
|
||||||
Auth: &logical.Auth{
|
Auth: &logical.Auth{
|
||||||
Alias: &logical.Alias{
|
Alias: &logical.Alias{
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -201,6 +202,35 @@ func TestBackend_userCreateOperation(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestBackend_userCreateOperationCheckCase will test the alias lookahead functionality
|
||||||
|
// for the userpass auth method to ensure the alias returned is always lowercase due to
|
||||||
|
// the effective case insensitivity of the auth method
|
||||||
|
func TestBackend_userCreateOperationCheckCase(t *testing.T) {
|
||||||
|
b, err := Factory(context.Background(), &logical.BackendConfig{
|
||||||
|
Logger: nil,
|
||||||
|
System: &logical.StaticSystemView{
|
||||||
|
DefaultLeaseTTLVal: testSysTTL,
|
||||||
|
MaxLeaseTTLVal: testSysMaxTTL,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to create backend: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
|
CredentialBackend: b,
|
||||||
|
Steps: []logicaltest.TestStep{
|
||||||
|
testUserCreateOperation(t, "web", "password", "foo"),
|
||||||
|
testAccStepLogin(t, "web", "password", []string{"default", "foo"}),
|
||||||
|
testAccStepLoginAlias(t, "web", "password"),
|
||||||
|
testAccStepLogin(t, "WEb", "password", []string{"default", "foo"}),
|
||||||
|
testAccStepLoginAlias(t, "wEb", "password"),
|
||||||
|
testAccStepLogin(t, "WEb", "password", []string{"default", "foo"}),
|
||||||
|
testAccStepLoginAlias(t, "WEb", "password"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestBackend_passwordUpdate(t *testing.T) {
|
func TestBackend_passwordUpdate(t *testing.T) {
|
||||||
b, err := Factory(context.Background(), &logical.BackendConfig{
|
b, err := Factory(context.Background(), &logical.BackendConfig{
|
||||||
Logger: nil,
|
Logger: nil,
|
||||||
@ -302,6 +332,30 @@ func testAccStepLogin(t *testing.T, user string, pass string, policies []string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// userpass is case insentive, so we need to ensure that the alias lookahead returns all lowercase username
|
||||||
|
// even if the username is provided in a different case.
|
||||||
|
func testAccStepLoginAlias(t *testing.T, user string, pass string) logicaltest.TestStep {
|
||||||
|
return logicaltest.TestStep{
|
||||||
|
Operation: logical.AliasLookaheadOperation,
|
||||||
|
Path: "login/" + user,
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"Raw": map[string]interface{}{
|
||||||
|
"username": user,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Check: func(resp *logical.Response) error {
|
||||||
|
if resp.Auth.Alias.Name != strings.ToLower(user) {
|
||||||
|
return fmt.Errorf("expected alias name to be '%s', got: %s", strings.ToLower(user), resp.Auth.Alias.Name)
|
||||||
|
}
|
||||||
|
if resp.IsError() {
|
||||||
|
return fmt.Errorf("bad: %#v", resp)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
ConnState: &tls.ConnectionState{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testUserCreateOperation(
|
func testUserCreateOperation(
|
||||||
t *testing.T, name string, password string, policies string,
|
t *testing.T, name string, password string, policies string,
|
||||||
) logicaltest.TestStep {
|
) logicaltest.TestStep {
|
||||||
|
@ -47,10 +47,10 @@ func pathLogin(b *backend) *framework.Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) pathLoginAliasLookahead(_ context.Context, _ *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
username := d.Get("username").(string)
|
username, err := b.getUsername(d)
|
||||||
if username == "" {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("missing username")
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &logical.Response{
|
return &logical.Response{
|
||||||
@ -62,8 +62,21 @@ func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Requ
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getUsername retrieves the username from the field data, ensuring it is not
|
||||||
|
// empty. The username is always returned in lowercase.
|
||||||
|
func (b *backend) getUsername(d *framework.FieldData) (string, error) {
|
||||||
|
username := d.Get("username").(string)
|
||||||
|
if username == "" {
|
||||||
|
return "", fmt.Errorf("missing username")
|
||||||
|
}
|
||||||
|
return strings.ToLower(username), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
username := strings.ToLower(d.Get("username").(string))
|
username, err := b.getUsername(d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
password := d.Get("password").(string)
|
password := d.Get("password").(string)
|
||||||
if password == "" {
|
if password == "" {
|
||||||
|
3
changelog/31352.txt
Normal file
3
changelog/31352.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
```release-note:bug
|
||||||
|
auth: update alias lookahead to respect username case for LDAP and username/password
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user