Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/security mode improvements #153

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ ifeq ($(db_setup),cluster)
endif

compose-new:
sudo docker-compose -f ${mongo_compose_file} up -d
docker compose -f ${mongo_compose_file} up -d

compose-start:
sudo docker-compose -f ${mongo_compose_file} start
docker compose -f ${mongo_compose_file} start

compose-stop:
sudo docker-compose -f ${mongo_compose_file} stop
docker compose -f ${mongo_compose_file} stop

compose-rm:
sudo docker-compose -f ${mongo_compose_file} down
docker compose -f ${mongo_compose_file} down
4 changes: 2 additions & 2 deletions cmd/multi-factor-auth/swagger/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ type _ struct {
type _ struct {
// in:body
Body struct {
// SignMultipleTransactions
// SignMultipleTransactionsResponse
// x-nullable:true
Data requests.SignMultipleTransactions `json:"data"`
Data requests.SignMultipleTransactionsResponse `json:"data"`
// HTTP status code
Code string `json:"code"`
// Internal error
Expand Down
108 changes: 42 additions & 66 deletions cmd/multi-factor-auth/swagger/ui/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,54 +77,43 @@
}
}
},
"/sign-multiple-transactions": {
"/sign-message": {
"post": {
"description": "Signs the provided transactions with the provided guardian",
"description": "Signs the provided message with the provided guardian",
"tags": [
"Guardian"
],
"summary": "Sign multiple transactions.",
"operationId": "signMultipleTransactionsRequest",
"parameters": [
{
"description": "Sign multiple transactions payload",
"name": "Payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/SignMultipleTransactions"
}
}
],
"summary": "Sign message.",
"operationId": "signMessageRequest",
"responses": {
"200": {
"$ref": "#/responses/signMultipleTransactionsResponse"
"$ref": "#/responses/signMessageResponse"
}
}
}
},
"/sign-message": {
"/sign-multiple-transactions": {
"post": {
"description": "Signs the provided message with the provided guardian",
"description": "Signs the provided transactions with the provided guardian",
"tags": [
"Guardian"
],
"summary": "Sign message.",
"operationId": "signMessageRequest",
"summary": "Sign multiple transactions.",
"operationId": "signMultipleTransactionsRequest",
"parameters": [
{
"description": "Sign message payload",
"description": "Sign multiple transactions payload",
"name": "Payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/SignMessage"
"$ref": "#/definitions/SignMultipleTransactions"
}
}
],
"responses": {
"200": {
"$ref": "#/responses/signMessageResponse"
"$ref": "#/responses/signMultipleTransactionsResponse"
}
}
}
Expand Down Expand Up @@ -422,6 +411,21 @@
},
"x-go-package": "github.com/multiversx/mx-multi-factor-auth-go-service/core/requests"
},
"SignMessageResponse": {
"description": "SignMessageResponse is the service response to the sign message request",
"type": "object",
"properties": {
"message": {
"type": "string",
"x-go-name": "Message"
},
"signature": {
"type": "string",
"x-go-name": "Signature"
}
},
"x-go-package": "github.com/multiversx/mx-multi-factor-auth-go-service/core/requests"
},
"SignMultipleTransactions": {
"description": "SignMultipleTransactions is the JSON request the service is receiving\nwhen a user sends multiple transactions to be signed by the guardian",
"type": "object",
Expand All @@ -444,29 +448,16 @@
},
"x-go-package": "github.com/multiversx/mx-multi-factor-auth-go-service/core/requests"
},
"SignMessage": {
"description": "SignMessage is the JSON request the service is receiving\nwhen a user sends a new message to be signed by the guardian",
"SignMultipleTransactionsResponse": {
"description": "SignMultipleTransactionsResponse is the service response to the sign multiple transactions request",
"type": "object",
"properties": {
"code": {
"type": "string",
"x-go-name": "Code"
},
"second-code": {
"type": "string",
"x-go-name": "SecondCode"
},
"message": {
"type": "string",
"x-go-name": "Message"
},
"user": {
"type": "string",
"x-go-name": "UserAddr"
},
"guardian": {
"type": "string",
"x-go-name": "GuardianAddr"
"transactions": {
"type": "array",
"items": {
"$ref": "#/definitions/FrontendTransaction"
},
"x-go-name": "Txs"
}
},
"x-go-package": "github.com/multiversx/mx-multi-factor-auth-go-service/core/requests"
Expand All @@ -489,21 +480,6 @@
},
"x-go-package": "github.com/multiversx/mx-multi-factor-auth-go-service/core/requests"
},
"SignMessageResponse": {
"description": "SignTransactionResponse is the service response to the sign transaction request",
"type": "object",
"properties": {
"message": {
"type": "string",
"x-go-name": "Message"
},
"signature": {
"type": "string",
"x-go-name": "Signature"
}
},
"x-go-package": "github.com/multiversx/mx-multi-factor-auth-go-service/core/requests"
},
"SignTransactionResponse": {
"description": "SignTransactionResponse is the service response to the sign transaction request",
"type": "object",
Expand Down Expand Up @@ -598,8 +574,8 @@
}
}
},
"signMultipleTransactionsResponse": {
"description": "The transactions array with their guardian's signature on them",
"signMessageResponse": {
"description": "The full transaction with its guardian signature on it",
"schema": {
"type": "object",
"properties": {
Expand All @@ -609,7 +585,7 @@
"x-go-name": "Code"
},
"data": {
"$ref": "#/definitions/SignMultipleTransactions"
"$ref": "#/definitions/SignMessageResponse"
},
"error": {
"description": "Internal error",
Expand All @@ -619,8 +595,8 @@
}
}
},
"signMessageResponse": {
"description": "The full transaction with its guardian signature on it",
"signMultipleTransactionsResponse": {
"description": "The transactions array with their guardian's signature on them",
"schema": {
"type": "object",
"properties": {
Expand All @@ -630,7 +606,7 @@
"x-go-name": "Code"
},
"data": {
"$ref": "#/definitions/SignMessageResponse"
"$ref": "#/definitions/SignMultipleTransactionsResponse"
},
"error": {
"description": "Internal error",
Expand Down Expand Up @@ -672,7 +648,7 @@
"x-go-name": "Code"
},
"data": {
"description": "Empty data field",
"description": "Empty data field\nx-nullable:true",
"type": "string",
"x-go-name": "Data"
},
Expand Down
3 changes: 0 additions & 3 deletions core/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ var ErrNilBucket = errors.New("nil bucket")
// ErrNilMongoDBClient signals that a nil mongodb client has been provided
var ErrNilMongoDBClient = errors.New("nil mongodb client")

// ErrNilStorer signals that a nil storer has been provided
var ErrNilStorer = errors.New("nil storer")

// ErrNilHttpClient signals that a nil http client has been provided
var ErrNilHttpClient = errors.New("nil http client")

Expand Down
1 change: 1 addition & 0 deletions handlers/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type SecureOtpHandler interface {
IsVerificationAllowedAndIncreaseTrials(account string, ip string) (*requests.OTPCodeVerifyData, error)
Reset(account string, ip string)
DecrementSecurityModeFailedTrials(account string) error
ExtendSecurityMode(account string) error
IsInterfaceNil() bool
}

Expand Down
5 changes: 5 additions & 0 deletions handlers/secureOtp/secureOtpHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ func (totp *secureOtpHandler) DecrementSecurityModeFailedTrials(account string)
return totp.rateLimiter.DecrementSecurityFailedTrials(account)
}

// ExtendSecurityMode extends the security mode to the maximum limit
func (totp *secureOtpHandler) ExtendSecurityMode(account string) error {
return totp.rateLimiter.ExtendSecurityMode(account)
}

// IsInterfaceNil returns true if there is no value under the interface
func (totp *secureOtpHandler) IsInterfaceNil() bool {
return totp == nil
Expand Down
90 changes: 83 additions & 7 deletions handlers/secureOtp/secureOtpHandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const (
ip = "127.0.0.1"
)

var expectedErr = errors.New("expected error")

func createMockArgsSecureOtpHandler() secureOtp.ArgsSecureOtpHandler {
return secureOtp.ArgsSecureOtpHandler{
RateLimiter: &testscommon.RateLimiterStub{},
Expand Down Expand Up @@ -60,7 +62,6 @@ func TestSecureOtpHandler_IsVerificationAllowedAndIncreaseTrials(t *testing.T) {

args := createMockArgsSecureOtpHandler()

expectedErr := errors.New("expected error")
args.RateLimiter = &testscommon.RateLimiterStub{
CheckAllowedAndIncreaseTrialsCalled: func(key string, _ redis.Mode) (*redis.RateLimiterResult, error) {
return &redis.RateLimiterResult{}, expectedErr
Expand All @@ -74,7 +75,6 @@ func TestSecureOtpHandler_IsVerificationAllowedAndIncreaseTrials(t *testing.T) {
t.Run("on security mode limiter check error, should return error", func(t *testing.T) {
args := createMockArgsSecureOtpHandler()

expectedErr := errors.New("expected error")
args.RateLimiter = &testscommon.RateLimiterStub{
CheckAllowedAndIncreaseTrialsCalled: func(key string, mode redis.Mode) (*redis.RateLimiterResult, error) {
switch mode {
Expand Down Expand Up @@ -244,7 +244,6 @@ func TestSecureOtpHandler_DecrementSecurityModeFailedTrials(t *testing.T) {
args := createMockArgsSecureOtpHandler()

t.Run("on redis limiter error should return err", func(t *testing.T) {
expectedErr := errors.New("expected error")
wasCalled := false
args.RateLimiter = &testscommon.RateLimiterStub{
DecrementSecurityFailuresCalled: func(key string) error {
Expand Down Expand Up @@ -279,18 +278,95 @@ func TestSecureOtpHandler_DecrementSecurityModeFailedTrials(t *testing.T) {
func TestSecureOtpHandler_Reset(t *testing.T) {
t.Parallel()

args := createMockArgsSecureOtpHandler()
t.Run("reset returns error", func(t *testing.T) {
t.Parallel()

args := createMockArgsSecureOtpHandler()

wasCalled := false
args.RateLimiter = &testscommon.RateLimiterStub{
ResetCalled: func(key string) error {
wasCalled = true
return expectedErr
},
}
totp, _ := secureOtp.NewSecureOtpHandler(args)
require.NotNil(t, totp)

totp.Reset(account, ip)

require.True(t, wasCalled)
})
t.Run("should work", func(t *testing.T) {
t.Parallel()

args := createMockArgsSecureOtpHandler()

wasCalled := false
args.RateLimiter = &testscommon.RateLimiterStub{
ResetCalled: func(key string) error {
wasCalled = true
return nil
},
}
totp, _ := secureOtp.NewSecureOtpHandler(args)
require.NotNil(t, totp)

totp.Reset(account, ip)

require.True(t, wasCalled)
})
}

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

wasCalled := false
args := createMockArgsSecureOtpHandler()
args.RateLimiter = &testscommon.RateLimiterStub{
ResetCalled: func(key string) error {
ExtendSecurityModeCalled: func(key string) error {
wasCalled = true
return nil
},
}
totp, _ := secureOtp.NewSecureOtpHandler(args)

totp.Reset(account, ip)
totp, _ := secureOtp.NewSecureOtpHandler(args)
require.NotNil(t, totp)

err := totp.ExtendSecurityMode(account)
require.NoError(t, err)
require.True(t, wasCalled)
}

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

providedNormalModePeriod := time.Second
providedNormalModeRate := 1
providedSecurityModePeriod := time.Minute
providedSecurityModeRate := 100
args := createMockArgsSecureOtpHandler()
args.RateLimiter = &testscommon.RateLimiterStub{
PeriodCalled: func(mode redis.Mode) time.Duration {
if mode == redis.NormalMode {
return providedNormalModePeriod
}

return providedSecurityModePeriod
},
RateCalled: func(mode redis.Mode) int {
if mode == redis.NormalMode {
return providedNormalModeRate
}

return providedSecurityModeRate
},
}
totp, _ := secureOtp.NewSecureOtpHandler(args)
require.NotNil(t, totp)

require.Equal(t, uint64(providedNormalModePeriod.Seconds()), totp.FreezeBackOffTime())
require.Equal(t, uint64(providedNormalModeRate), totp.FreezeMaxFailures())
require.Equal(t, uint64(providedSecurityModePeriod.Seconds()), totp.SecurityModeBackOffTime())
require.Equal(t, uint64(providedSecurityModeRate), totp.SecurityModeMaxFailures())
}
Loading
Loading