Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions apps/srv/internal/adapters/secondary/hasher/bcrypt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,28 @@ func TestBcryptHasher_Hash(t *testing.T) {
require.NotEqual(t, "password", hash)
})
}

func TestBcryptHasher_Verify(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

h := hasher.NewBcryptHasher(bcrypt.DefaultCost)

t.Run("it should return an error if the password does not match", func(t *testing.T) {
hash, err := h.Hash(ctx, "password")
require.NoError(t, err)

err = h.Verify(ctx, "wrong-password", hash)
require.Error(t, err)
})

t.Run("it should verify the password", func(t *testing.T) {
hash, err := h.Hash(ctx, "password")
require.NoError(t, err)

err = h.Verify(ctx, "password", hash)
require.NoError(t, err)
})
}
2 changes: 2 additions & 0 deletions apps/srv/internal/adapters/secondary/paseto/paseto_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build unit

package paseto_test

import (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//go:build integration

package authentication_test

import (
"context"
"testing"
"time"

authenticationStore "github.com/arthurdotwork/bastion/internal/adapters/secondary/store/authentication"
"github.com/arthurdotwork/bastion/internal/domain/authentication"
"github.com/arthurdotwork/bastion/internal/infra/psql"
"github.com/arthurdotwork/bastion/internal/infra/queries"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)

func TestAccessTokenStore_CreateAccessToken(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

db, err := psql.Connect(ctx, "postgres", "postgres", "localhost", "5432", "postgres")
require.NoError(t, err)

tx, err := db.BeginTxx(ctx, nil)
require.NoError(t, err)
defer tx.Rollback() //nolint:errcheck

q := queries.New(tx.Tx())
accessTokenStore := authenticationStore.NewAccessTokenStore(tx, q)

t.Run("it should create the token", func(t *testing.T) {
user, err := q.CreateUser(ctx, queries.CreateUserParams{
Email: "email@bastion.dev",
Password: "password",
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
})
require.NoError(t, err)

token := authentication.AccessToken{
ID: uuid.New(),
UserID: user.ID,
TokenIdentifier: uuid.New(),
IssuedAt: time.Now().UTC(),
ExpiresAt: time.Now().UTC(),
RawToken: "token",
}

createdToken, err := accessTokenStore.CreateAccessToken(ctx, token)
require.NoError(t, err)
require.NotEmpty(t, createdToken.ID)
})

t.Run("it should return an error if it can not create the token", func(t *testing.T) {
token := authentication.AccessToken{
ID: uuid.New(),
UserID: uuid.UUID{},
TokenIdentifier: uuid.New(),
IssuedAt: time.Now().UTC(),
ExpiresAt: time.Now().UTC(),
RawToken: "token",
}

_, err := accessTokenStore.CreateAccessToken(ctx, token)
require.Error(t, err)
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//go:build integration

package authentication_test

import (
"context"
"testing"
"time"

authenticationStore "github.com/arthurdotwork/bastion/internal/adapters/secondary/store/authentication"
"github.com/arthurdotwork/bastion/internal/infra/psql"
"github.com/arthurdotwork/bastion/internal/infra/queries"
"github.com/stretchr/testify/require"
)

func TestUserStore_GetUserByEmail(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

db, err := psql.Connect(ctx, "postgres", "postgres", "localhost", "5432", "postgres")
require.NoError(t, err)

tx, err := db.BeginTxx(ctx, nil)
require.NoError(t, err)
defer tx.Rollback() //nolint:errcheck

q := queries.New(tx.Tx())
accessTokenStore := authenticationStore.NewUserStore(tx, q)

t.Run("it should return an error if the user can not be found", func(t *testing.T) {
_, err := accessTokenStore.GetUserByEmail(ctx, "email@bastion.dev")
require.Error(t, err)
})

t.Run("it should return the user", func(t *testing.T) {
user, err := q.CreateUser(ctx, queries.CreateUserParams{
Email: "email@bastion.dev",
Password: "password",
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
})
require.NoError(t, err)

foundUser, err := accessTokenStore.GetUserByEmail(ctx, user.Email)
require.NoError(t, err)
require.EqualValues(t, user.ID, foundUser.ID)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,37 @@ func TestUserStore_CreateUser(t *testing.T) {
}

func TestUserStore_GetUserByEmail(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

db, err := psql.Connect(ctx, "postgres", "postgres", "localhost", "5432", "postgres")
require.NoError(t, err)

tx, err := db.BeginTxx(ctx, nil)
require.NoError(t, err)
defer tx.Rollback() //nolint:errcheck

q := queries.New(tx.Tx())
userStore := membershipStore.NewUserStore(tx, q)

t.Run("it should not return an error if the user can not be found", func(t *testing.T) {
_, err := userStore.GetUserByEmail(ctx, "email@bastion.dev")
require.NoError(t, err)
})

t.Run("it should return the user", func(t *testing.T) {
user, err := q.CreateUser(ctx, queries.CreateUserParams{
Email: "email@bastion.dev",
Password: "password",
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
})
require.NoError(t, err)

foundUser, err := userStore.GetUserByEmail(ctx, user.Email)
require.NoError(t, err)
require.EqualValues(t, user.ID, foundUser.ID)
})
}
101 changes: 101 additions & 0 deletions apps/srv/internal/domain/authentication/authentication_service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//go:build unit

package authentication_test

import (
"context"
"testing"

"github.com/arthurdotwork/bastion/internal/domain/authentication"
"github.com/arthurdotwork/bastion/internal/domain/authentication/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestService_AuthenticateWithPassword(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

userStore := mocks.NewUserStore(t)
hasher := mocks.NewHasher(t)
tokenProvider := mocks.NewTokenProvider(t)
accessTokenStore := mocks.NewAccessTokenStore(t)

authenticationService := authentication.NewService(userStore, hasher, tokenProvider, accessTokenStore)

t.Run("it should return an error if it can not find the user", func(t *testing.T) {
userStore.EXPECT().GetUserByEmail(ctx, "email@bastion.dev").Return(authentication.User{}, assert.AnError).Once()

_, err := authenticationService.AuthenticateWithPassword(ctx, "email@bastion.dev", "password")
require.Error(t, err)
})

t.Run("it should return an error if the password is incorrect", func(t *testing.T) {
userStore.EXPECT().GetUserByEmail(ctx, "email@bastion.dev").Return(authentication.User{HashedPassword: "password"}, nil).Once()
hasher.EXPECT().Verify(ctx, "password", "password").Return(assert.AnError).Once()

_, err := authenticationService.AuthenticateWithPassword(ctx, "email@bastion.dev", "password")
require.Error(t, err)
})

t.Run("it should return an error if the token provider fails to create a token", func(t *testing.T) {
userStore.EXPECT().GetUserByEmail(ctx, "email@bastion.dev").Return(authentication.User{HashedPassword: "password"}, nil).Once()
hasher.EXPECT().Verify(ctx, "password", "password").Return(nil).Once()
tokenProvider.EXPECT().Generate(ctx, authentication.User{HashedPassword: "password"}).Return(authentication.AccessToken{}, assert.AnError).Once()

_, err := authenticationService.AuthenticateWithPassword(ctx, "email@bastion.dev", "password")
require.Error(t, err)
})

t.Run("it should return an error if the access token store fails to save the token", func(t *testing.T) {
userStore.EXPECT().GetUserByEmail(ctx, "email@bastion.dev").Return(authentication.User{HashedPassword: "password"}, nil).Once()
hasher.EXPECT().Verify(ctx, "password", "password").Return(nil).Once()
tokenProvider.EXPECT().Generate(ctx, authentication.User{HashedPassword: "password"}).Return(authentication.AccessToken{}, nil).Once()
accessTokenStore.EXPECT().CreateAccessToken(ctx, authentication.AccessToken{}).Return(authentication.AccessToken{}, assert.AnError).Once()

_, err := authenticationService.AuthenticateWithPassword(ctx, "email@bastion.dev", "password")
require.Error(t, err)
})

t.Run("it should authenticate the user", func(t *testing.T) {
userStore.EXPECT().GetUserByEmail(ctx, "email@bastion.dev").Return(authentication.User{HashedPassword: "password"}, nil).Once()
hasher.EXPECT().Verify(ctx, "password", "password").Return(nil).Once()
tokenProvider.EXPECT().Generate(ctx, authentication.User{HashedPassword: "password"}).Return(authentication.AccessToken{}, nil).Once()
accessTokenStore.EXPECT().CreateAccessToken(ctx, authentication.AccessToken{}).Return(authentication.AccessToken{RawToken: "rawToken"}, nil).Once()

accessToken, err := authenticationService.AuthenticateWithPassword(ctx, "email@bastion.dev", "password")
require.NoError(t, err)
require.NotEmpty(t, accessToken)
require.Equal(t, "rawToken", accessToken.RawToken)
})
}

func TestService_VerifyAccessToken(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

userStore := mocks.NewUserStore(t)
hasher := mocks.NewHasher(t)
tokenProvider := mocks.NewTokenProvider(t)
accessTokenStore := mocks.NewAccessTokenStore(t)

authenticationService := authentication.NewService(userStore, hasher, tokenProvider, accessTokenStore)

t.Run("it should return an error if the token is invalid", func(t *testing.T) {
tokenProvider.EXPECT().Verify(ctx, "invalidToken").Return(assert.AnError).Once()

err := authenticationService.VerifyAccessToken(ctx, "invalidToken")
require.Error(t, err)
})

t.Run("it should verify the token", func(t *testing.T) {
tokenProvider.EXPECT().Verify(ctx, "validToken").Return(nil).Once()

err := authenticationService.VerifyAccessToken(ctx, "validToken")
require.NoError(t, err)
})
}
94 changes: 94 additions & 0 deletions apps/srv/internal/domain/authentication/mocks/AccessTokenStore.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading