Skip to content

Commit

Permalink
fix: add email validation in Authenticate api (#847)
Browse files Browse the repository at this point in the history
* chore: update proton version

* tests: setup test for Authenticate handler

* feat: add basic test for Authenticate handler

* feat: add email validation in Authenticate api

* Revert "chore: update proton version"

This reverts commit 0462438.

* fix: lint issue
  • Loading branch information
rsbh authored Jan 15, 2025
1 parent a5fccc2 commit bf8ab44
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 0 deletions.
4 changes: 4 additions & 0 deletions internal/api/v1beta1/authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ func (h Handler) Authenticate(ctx context.Context, request *frontierv1beta1.Auth
return nil, status.Error(codes.Internal, err.Error())
}

if (request.GetStrategyName() == authenticate.MailLinkAuthMethod.String() || request.GetStrategyName() == authenticate.MailOTPAuthMethod.String()) && !isValidEmail(request.GetEmail()) {
return nil, status.Error(codes.InvalidArgument, "Invalid email")
}

// not logged in, try registration
response, err := h.authnService.StartFlow(ctx, authenticate.RegistrationStartRequest{
Method: request.GetStrategyName(),
Expand Down
132 changes: 132 additions & 0 deletions internal/api/v1beta1/authenticate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package v1beta1

import (
"context"
"testing"
"time"

"github.com/raystack/frontier/core/authenticate"
frontiersession "github.com/raystack/frontier/core/authenticate/session"
"github.com/raystack/frontier/internal/api/v1beta1/mocks"
"github.com/raystack/frontier/pkg/errors"
frontierv1beta1 "github.com/raystack/frontier/proto/v1beta1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func TestHandler_Authenticate(t *testing.T) {
tests := []struct {
name string
setup func(authn *mocks.AuthnService, session *mocks.SessionService)
request *frontierv1beta1.AuthenticateRequest
want *frontierv1beta1.AuthenticateResponse
wantErr error
}{
{
name: "should return an error if session service returns an error",
setup: func(authn *mocks.AuthnService, session *mocks.SessionService) {
authn.EXPECT().SanitizeReturnToURL("").Return("")
authn.EXPECT().SanitizeCallbackURL("").Return("")
session.EXPECT().ExtractFromContext(mock.AnythingOfType("context.backgroundCtx")).Return(nil, errors.New("new-error"))
},
request: &frontierv1beta1.AuthenticateRequest{},
wantErr: status.Error(codes.Internal, "new-error"),
want: nil,
},
{
name: "should return empty response if session is alreay there",
setup: func(authn *mocks.AuthnService, session *mocks.SessionService) {
authn.EXPECT().SanitizeReturnToURL("").Return("")
authn.EXPECT().SanitizeCallbackURL("").Return("")
session.EXPECT().ExtractFromContext(mock.AnythingOfType("context.backgroundCtx")).Return(&frontiersession.Session{
ExpiresAt: time.Now().Add(1 * time.Hour),
AuthenticatedAt: time.Now(),
}, nil)
},
request: &frontierv1beta1.AuthenticateRequest{},
wantErr: nil,
want: &frontierv1beta1.AuthenticateResponse{},
},
{
name: "should return an error if auth service returns an error",
setup: func(authn *mocks.AuthnService, session *mocks.SessionService) {
authn.EXPECT().SanitizeReturnToURL("").Return("")
authn.EXPECT().SanitizeCallbackURL("").Return("")
session.EXPECT().ExtractFromContext(mock.AnythingOfType("context.backgroundCtx")).Return(nil, frontiersession.ErrNoSession)
authn.EXPECT().StartFlow(mock.AnythingOfType("context.backgroundCtx"), authenticate.RegistrationStartRequest{}).Return(nil, errors.New("new-error"))
},
request: &frontierv1beta1.AuthenticateRequest{},
wantErr: status.Error(codes.Internal, "new-error"),
want: nil,
},
{
name: "should create state and endpoint for callback",
setup: func(authn *mocks.AuthnService, session *mocks.SessionService) {
authn.EXPECT().SanitizeReturnToURL("").Return("")
authn.EXPECT().SanitizeCallbackURL("").Return("")
session.EXPECT().ExtractFromContext(mock.AnythingOfType("context.backgroundCtx")).Return(nil, frontiersession.ErrNoSession)
authn.EXPECT().StartFlow(mock.AnythingOfType("context.backgroundCtx"), authenticate.RegistrationStartRequest{
Email: "[email protected]",
Method: authenticate.MailOTPAuthMethod.String(),
ReturnToURL: "",
CallbackUrl: "",
}).Return(&authenticate.RegistrationStartResponse{
Flow: &authenticate.Flow{
StartURL: "",
},
State: "",
}, nil)
},
request: &frontierv1beta1.AuthenticateRequest{
StrategyName: authenticate.MailOTPAuthMethod.String(),
Email: "[email protected]",
},
wantErr: nil,
want: &frontierv1beta1.AuthenticateResponse{
Endpoint: "",
State: "",
},
},
{
name: "should throw error if email is invalid in mailotp",
setup: func(authn *mocks.AuthnService, session *mocks.SessionService) {
authn.EXPECT().SanitizeReturnToURL("").Return("")
authn.EXPECT().SanitizeCallbackURL("").Return("")
session.EXPECT().ExtractFromContext(mock.AnythingOfType("context.backgroundCtx")).Return(nil, frontiersession.ErrNoSession)
authn.EXPECT().StartFlow(mock.AnythingOfType("context.backgroundCtx"), authenticate.RegistrationStartRequest{
Email: "frontier",
Method: authenticate.MailOTPAuthMethod.String(),
ReturnToURL: "",
CallbackUrl: "",
}).Return(&authenticate.RegistrationStartResponse{
Flow: &authenticate.Flow{
StartURL: "",
},
State: "",
}, nil)
},
request: &frontierv1beta1.AuthenticateRequest{
StrategyName: authenticate.MailOTPAuthMethod.String(),
Email: "frontier",
},
wantErr: status.Error(codes.InvalidArgument, "Invalid email"),
want: nil,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockAuthnSrv := new(mocks.AuthnService)
mockSessionSrv := new(mocks.SessionService)
if tt.setup != nil {
tt.setup(mockAuthnSrv, mockSessionSrv)
}
mockDep := Handler{authnService: mockAuthnSrv, sessionService: mockSessionSrv}
resp, err := mockDep.Authenticate(context.Background(), tt.request)
assert.EqualValues(t, tt.want, resp)
assert.EqualValues(t, tt.wantErr, err)
})
}
}

0 comments on commit bf8ab44

Please sign in to comment.