grafana_bak/pkg/services/authn/clients/passwordless_test.go
2025-04-01 10:38:02 +09:00

161 lines
5.1 KiB
Go

package clients
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
claims "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/infra/remotecache"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/loginattempt/loginattempttest"
"github.com/grafana/grafana/pkg/services/notifications"
tempuser "github.com/grafana/grafana/pkg/services/temp_user"
"github.com/grafana/grafana/pkg/services/temp_user/tempusertest"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
func TestPasswordless_StartPasswordless(t *testing.T) {
type testCase struct {
desc string
email string
findUser bool
findTempUser bool
blockLogin bool
expectedErr error
}
tests := []testCase{
{
desc: "should succeed if user is found",
email: "user@domain.com",
findUser: true,
blockLogin: false,
},
{
desc: "should succeed if temp user is found",
email: "user@domain.com",
findUser: false,
findTempUser: true,
blockLogin: false,
},
{
desc: "should fail if user or temp user is not found",
email: "user@domain.com",
findUser: false,
findTempUser: false,
blockLogin: false,
expectedErr: errPasswordlessClientInvalidEmail.Errorf("no user or invite found with email user@domain.com"),
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
hashed, _ := util.EncodePassword("password", "salt")
userService := &usertest.FakeUserService{
ExpectedUser: &user.User{ID: 1, Email: "user@domain.com", Login: "user", Password: user.Password(hashed), Salt: "salt"},
}
las := &loginattempttest.FakeLoginAttemptService{ExpectedValid: !tt.blockLogin}
tus := &tempusertest.FakeTempUserService{}
tus.GetTempUsersQueryFN = func(ctx context.Context, query *tempuser.GetTempUsersQuery) ([]*tempuser.TempUserDTO, error) {
return []*tempuser.TempUserDTO{{
ID: 1,
Email: "user@domain.com",
Status: tempuser.TmpUserInvitePending,
EmailSent: true,
}}, nil
}
ns := notifications.MockNotificationService()
cache := remotecache.NewFakeCacheStorage()
if !tt.findUser {
userService.ExpectedUser = nil
userService.ExpectedError = user.ErrUserNotFound
}
if !tt.findTempUser {
tus.GetTempUsersQueryFN = func(ctx context.Context, query *tempuser.GetTempUsersQuery) ([]*tempuser.TempUserDTO, error) {
return nil, tempuser.ErrTempUserNotFound
}
}
c := ProvidePasswordless(setting.NewCfg(), las, userService, tus, ns, cache)
_, err := c.startPasswordless(context.Background(), tt.email)
assert.ErrorIs(t, err, tt.expectedErr)
})
}
}
func TestPasswordless_AuthenticatePasswordless(t *testing.T) {
type testCase struct {
desc string
email string
findUser bool
blockLogin bool
expectedErr error
expectedIdentity *authn.Identity
}
tests := []testCase{
{
desc: "should successfully authenticate user with correct passwordless magic link",
email: "user@domain.com",
findUser: true,
blockLogin: false,
expectedIdentity: &authn.Identity{
ID: "1",
Type: claims.TypeUser,
OrgID: 1,
AuthenticatedBy: login.PasswordlessAuthModule,
ClientParams: authn.ClientParams{FetchSyncedUser: true, SyncPermissions: true},
},
},
{
desc: "should fail if login is blocked",
email: "user@domain.com",
findUser: true,
blockLogin: true,
expectedErr: errPasswordlessClientTooManyLoginAttempts.Errorf("too many consecutive incorrect login attempts for user - login for user temporarily blocked"),
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
hashed, _ := util.EncodePassword("password", "salt")
userService := &usertest.FakeUserService{
ExpectedUser: &user.User{ID: 1, Email: "user@domain.com", Login: "user", Password: user.Password(hashed), Salt: "salt"},
}
las := &loginattempttest.FakeLoginAttemptService{ExpectedValid: !tt.blockLogin}
tus := &tempusertest.FakeTempUserService{}
ns := notifications.MockNotificationService()
cache := remotecache.NewFakeCacheStorage()
if !tt.findUser {
userService.ExpectedUser = nil
userService.ExpectedError = user.ErrUserNotFound
}
c := ProvidePasswordless(setting.NewCfg(), las, userService, tus, ns, cache)
code, err := c.startPasswordless(context.Background(), tt.email)
if err != nil {
t.Fatalf("failed to start passwordless: %v", err)
}
form := &PasswordlessForm{
Code: code,
ConfirmationCode: ns.Email.Data["ConfirmationCode"].(string),
Name: "user",
Username: "username",
}
identity, err := c.authenticatePasswordless(context.Background(), &authn.Request{OrgID: 1}, *form)
assert.ErrorIs(t, err, tt.expectedErr)
assert.EqualValues(t, tt.expectedIdentity, identity)
})
}
}