mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-06 14:47:01 +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 {
|
||||
return logicaltest.TestStep{
|
||||
Operation: logical.UpdateOperation,
|
||||
|
@ -6,6 +6,7 @@ package ldap
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/vault/sdk/framework"
|
||||
"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")
|
||||
}
|
||||
|
||||
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{
|
||||
Auth: &logical.Auth{
|
||||
Alias: &logical.Alias{
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"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) {
|
||||
b, err := Factory(context.Background(), &logical.BackendConfig{
|
||||
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(
|
||||
t *testing.T, name string, password string, policies string,
|
||||
) 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) {
|
||||
username := d.Get("username").(string)
|
||||
if username == "" {
|
||||
return nil, fmt.Errorf("missing username")
|
||||
func (b *backend) pathLoginAliasLookahead(_ context.Context, _ *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
username, err := b.getUsername(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &logical.Response{
|
||||
@ -62,8 +62,21 @@ func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Requ
|
||||
}, 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) {
|
||||
username := strings.ToLower(d.Get("username").(string))
|
||||
username, err := b.getUsername(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
password := d.Get("password").(string)
|
||||
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