AuthN: Refactor basic auth client to support multiple password auth (#61153)
* AuthN: add interface for password clients * AuthN: Extract grafana password client * AuthN: Rewrite basic client tests * AuthN: Add Ldap client and rename method of PasswordClient * AuthN: Configure multiple password clients * AuthN: create ldap service and add tests
This commit is contained in:
@@ -6,62 +6,59 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/authn/authntest"
|
||||
"github.com/grafana/grafana/pkg/services/loginattempt/loginattempttest"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBasic_Authenticate(t *testing.T) {
|
||||
type TestCase struct {
|
||||
desc string
|
||||
req *authn.Request
|
||||
blockLogin bool
|
||||
expectedErr error
|
||||
expectedSignedInUser *user.SignedInUser
|
||||
expectedIdentity *authn.Identity
|
||||
desc string
|
||||
req *authn.Request
|
||||
blockLogin bool
|
||||
clients []authn.PasswordClient
|
||||
expectedErr error
|
||||
expectedIdentity *authn.Identity
|
||||
}
|
||||
|
||||
tests := []TestCase{
|
||||
{
|
||||
desc: "should successfully authenticate user with correct password",
|
||||
req: &authn.Request{HTTPRequest: &http.Request{Header: map[string][]string{authorizationHeaderName: {encodeBasicAuth("user", "password")}}}},
|
||||
expectedErr: nil,
|
||||
expectedSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, OrgRole: "Viewer"},
|
||||
expectedIdentity: &authn.Identity{ID: "user:1", OrgID: 1, OrgRoles: map[int64]org.RoleType{1: "Viewer"}, IsGrafanaAdmin: boolPtr(false)},
|
||||
desc: "should success when password client return identity",
|
||||
req: &authn.Request{HTTPRequest: &http.Request{Header: map[string][]string{authorizationHeaderName: {encodeBasicAuth("user", "password")}}}},
|
||||
clients: []authn.PasswordClient{authntest.FakePasswordClient{ExpectedIdentity: &authn.Identity{ID: "user:1"}}},
|
||||
expectedIdentity: &authn.Identity{ID: "user:1"},
|
||||
},
|
||||
{
|
||||
desc: "should fail for incorrect password",
|
||||
req: &authn.Request{HTTPRequest: &http.Request{Header: map[string][]string{authorizationHeaderName: {encodeBasicAuth("user", "wrong")}}}},
|
||||
expectedErr: ErrBasicAuthCredentials,
|
||||
desc: "should success when found in second client",
|
||||
req: &authn.Request{HTTPRequest: &http.Request{Header: map[string][]string{authorizationHeaderName: {encodeBasicAuth("user", "password")}}}},
|
||||
clients: []authn.PasswordClient{authntest.FakePasswordClient{ExpectedErr: errIdentityNotFound}, authntest.FakePasswordClient{ExpectedIdentity: &authn.Identity{ID: "user:2"}}},
|
||||
expectedIdentity: &authn.Identity{ID: "user:2"},
|
||||
},
|
||||
{
|
||||
desc: "should fail for empty password",
|
||||
req: &authn.Request{HTTPRequest: &http.Request{Header: map[string][]string{authorizationHeaderName: {encodeBasicAuth("user", "")}}}},
|
||||
expectedErr: ErrBasicAuthCredentials,
|
||||
expectedErr: errBasicAuthCredentials,
|
||||
},
|
||||
{
|
||||
desc: "should if login is blocked by to many attempts",
|
||||
req: &authn.Request{HTTPRequest: &http.Request{Header: map[string][]string{authorizationHeaderName: {encodeBasicAuth("user", "")}}}},
|
||||
blockLogin: true,
|
||||
expectedErr: ErrBasicAuthCredentials,
|
||||
expectedErr: errBasicAuthCredentials,
|
||||
},
|
||||
{
|
||||
desc: "should fail when not found in any clients",
|
||||
req: &authn.Request{HTTPRequest: &http.Request{Header: map[string][]string{authorizationHeaderName: {encodeBasicAuth("user", "password")}}}},
|
||||
clients: []authn.PasswordClient{authntest.FakePasswordClient{ExpectedErr: errIdentityNotFound}, authntest.FakePasswordClient{ExpectedErr: errIdentityNotFound}},
|
||||
expectedErr: errBasicAuthCredentials,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
hashed, _ := util.EncodePassword("password", "salt")
|
||||
c := ProvideBasic(&usertest.FakeUserService{
|
||||
ExpectedUser: &user.User{
|
||||
Password: hashed,
|
||||
Salt: "salt",
|
||||
},
|
||||
ExpectedSignedInUser: tt.expectedSignedInUser,
|
||||
}, loginattempttest.FakeLoginAttemptService{
|
||||
ExpectedValid: !tt.blockLogin,
|
||||
})
|
||||
c := ProvideBasic(
|
||||
loginattempttest.FakeLoginAttemptService{ExpectedValid: !tt.blockLogin},
|
||||
tt.clients...,
|
||||
)
|
||||
|
||||
identity, err := c.Authenticate(context.Background(), tt.req)
|
||||
if tt.expectedErr != nil {
|
||||
@@ -77,9 +74,10 @@ func TestBasic_Authenticate(t *testing.T) {
|
||||
|
||||
func TestBasic_Test(t *testing.T) {
|
||||
type TestCase struct {
|
||||
desc string
|
||||
req *authn.Request
|
||||
expected bool
|
||||
desc string
|
||||
req *authn.Request
|
||||
noClients bool
|
||||
expected bool
|
||||
}
|
||||
|
||||
tests := []TestCase{
|
||||
@@ -94,6 +92,18 @@ func TestBasic_Test(t *testing.T) {
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should fail when no password client is configured",
|
||||
req: &authn.Request{
|
||||
HTTPRequest: &http.Request{
|
||||
Header: map[string][]string{
|
||||
authorizationHeaderName: {encodeBasicAuth("user", "password")},
|
||||
},
|
||||
},
|
||||
},
|
||||
noClients: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "should fail when no http request is passed",
|
||||
req: &authn.Request{},
|
||||
@@ -114,7 +124,10 @@ func TestBasic_Test(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
c := ProvideBasic(usertest.NewUserServiceFake(), loginattempttest.FakeLoginAttemptService{})
|
||||
c := ProvideBasic(loginattempttest.FakeLoginAttemptService{}, authntest.FakePasswordClient{})
|
||||
if tt.noClients {
|
||||
c.clients = nil
|
||||
}
|
||||
assert.Equal(t, tt.expected, c.Test(context.Background(), tt.req))
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user