3
0
corteza/system/service/auth_test.go

273 lines
7.1 KiB
Go

package service
import (
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/markbates/goth"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
"github.com/cortezaproject/corteza-server/system/repository"
repomock "github.com/cortezaproject/corteza-server/system/repository/mocks"
"github.com/cortezaproject/corteza-server/system/types"
)
// @todo this mockDB will be probably be used by other tests, move it to some common place
type mockDB struct{}
func (mockDB) Transaction(callback func() error) error { return callback() }
// Mock auth service with nil for current time, dummy provider validator and mock db
func makeMockAuthService(u repository.UserRepository, c repository.CredentialsRepository) *auth {
return &auth{
db: &mockDB{},
users: u,
credentials: c,
providerValidator: func(s string) error {
// All providers are valid.
return nil
},
logger: zap.NewNop(),
settings: &types.Settings{},
now: func() *time.Time {
return nil
},
}
}
func TestAuth_External_Existing(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
// Create some virtual user and credentials
var u = &types.User{ID: 300000, Email: "foo@example.tld"}
var c = &types.Credentials{ID: 200000, OwnerID: u.ID}
// Profile to be used. make sure email matches
var p = goth.User{UserID: "some-profile-id", Provider: "google", Email: u.Email}
crdRpoMock := repomock.NewMockCredentialsRepository(mockCtrl)
crdRpoMock.EXPECT().
FindByCredentials("google", p.UserID).
Times(1).
Return(types.CredentialsSet{c}, nil)
crdRpoMock.EXPECT().
Update(gomock.Any()).
Times(1).
Return(c, nil)
usrRpoMock := repomock.NewMockUserRepository(mockCtrl)
usrRpoMock.EXPECT().FindByID(u.ID).Times(1).Return(u, nil)
svc := makeMockAuthService(usrRpoMock, crdRpoMock)
svc.settings.Auth.External.Enabled = true
{
auser, err := svc.External(p)
require.NoError(t, err)
require.True(t, auser.ID == u.ID, "Did not receive expected user")
}
}
func TestAuth_External_NonExisting(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
var u = &types.User{ID: 300000, Email: "foo@example.tld"}
var c = &types.Credentials{ID: 200000, OwnerID: u.ID}
var p = goth.User{UserID: "some-profile-id", Provider: "google", Email: u.Email}
crdRpoMock := repomock.NewMockCredentialsRepository(mockCtrl)
crdRpoMock.EXPECT().
FindByCredentials("google", p.UserID).
Times(1).
Return(types.CredentialsSet{}, nil)
crdRpoMock.EXPECT().
Create(&types.Credentials{Kind: "google", OwnerID: u.ID, Credentials: p.UserID}).
Times(1).
Return(c, nil)
usrRpoMock := repomock.NewMockUserRepository(mockCtrl)
usrRpoMock.EXPECT().
FindByEmail(u.Email).
Times(1).
Return(nil, repository.ErrUserNotFound)
usrRpoMock.EXPECT().
Create(&types.User{Email: "foo@example.tld"}).
Times(1).
Return(u, nil)
usrRpoMock.EXPECT().
Total().
Times(1).
Return(uint(0))
svc := makeMockAuthService(usrRpoMock, crdRpoMock)
svc.settings.Auth.External.Enabled = true
{
auser, err := svc.External(p)
require.NoError(t, err)
require.True(t, auser.ID == u.ID, "Did not receive expected user")
}
}
func Test_auth_validateInternalLogin(t *testing.T) {
type args struct {
email string
password string
}
tests := []struct {
name string
args args
wantErr bool
}{
{name: "no email", args: args{"", ""}, wantErr: true},
{name: "bad email", args: args{"test", ""}, wantErr: true},
{name: "no pass", args: args{"test@domain.tld", ""}, wantErr: true},
{name: "all good", args: args{"test@domain.tld", "password"}, wantErr: false},
}
svc := auth{
logger: zap.NewNop(),
settings: &types.Settings{},
}
svc.settings.Auth.Internal.Enabled = true
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := svc.validateInternalLogin(tt.args.email, tt.args.password); (err != nil) != tt.wantErr {
t.Errorf("auth.validateInternalLogin() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func Test_auth_checkPassword(t *testing.T) {
plainPassword := " ... plain password ... "
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(plainPassword), bcrypt.DefaultCost)
type args struct {
password string
cc types.CredentialsSet
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "empty set",
wantErr: true,
args: args{}},
{
name: "bad pwd",
wantErr: true,
args: args{
password: " foo ",
cc: types.CredentialsSet{&types.Credentials{ID: 1, Credentials: string(hashedPassword)}}}},
{
name: "invalid credentials",
wantErr: true,
args: args{
password: " foo ",
cc: types.CredentialsSet{&types.Credentials{ID: 0, Credentials: string(hashedPassword)}}}},
{
name: "ok",
wantErr: false,
args: args{
password: plainPassword,
cc: types.CredentialsSet{&types.Credentials{ID: 1, Credentials: string(hashedPassword)}}}},
{
name: "multipass",
wantErr: false,
args: args{
password: plainPassword,
cc: types.CredentialsSet{
&types.Credentials{ID: 0, Credentials: string(hashedPassword)},
&types.Credentials{ID: 1, Credentials: "$2a$10$8sOZxfZinxnu3bAtpkqEx.wBBwOfci6aG1szgUyxm5.BL2WiLu.ni"},
&types.Credentials{ID: 2, Credentials: string(hashedPassword)},
&types.Credentials{ID: 3, Credentials: ""},
}}},
}
svc := auth{
logger: zap.NewNop(),
settings: &types.Settings{},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := svc.checkPassword(tt.args.password, tt.args.cc); (err != nil) != tt.wantErr {
t.Errorf("auth.checkPassword() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func Test_auth_validateToken(t *testing.T) {
type args struct {
token string
}
tests := []struct {
name string
args args
wantID uint64
wantCredentials string
wantErr bool
}{
// TODO: Add test cases.
{
name: "empty",
wantID: 0,
wantCredentials: "",
wantErr: true,
args: args{token: ""}},
{
name: "foo",
wantID: 0,
wantCredentials: "",
wantErr: true,
args: args{token: "foo1"}},
{
name: "semivalid",
wantID: 0,
wantCredentials: "",
wantErr: true,
args: args{token: "foofoofoofoofoofoofoofoofoofoofo0"}},
{
name: "valid",
wantID: 1,
wantCredentials: "foofoofoofoofoofoofoofoofoofoofo",
wantErr: false,
args: args{token: "foofoofoofoofoofoofoofoofoofoofo1"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
svc := auth{}
svc.logger = zap.NewNop()
gotID, gotCredentials, err := svc.validateToken(tt.args.token)
if (err != nil) != tt.wantErr {
t.Errorf("auth.validateToken() error = %v, wantErr %v", err, tt.wantErr)
return
}
if gotID != tt.wantID {
t.Errorf("auth.validateToken() gotID = %v, want %v", gotID, tt.wantID)
}
if gotCredentials != tt.wantCredentials {
t.Errorf("auth.validateToken() gotCredentials = %v, want %v", gotCredentials, tt.wantCredentials)
}
})
}
}