Merge pull request #205 from anik-ghosh-au7/feat/2fa
update: verify otp resolver and test added
This commit is contained in:
commit
8db6649e5c
|
@ -45,7 +45,7 @@ func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models
|
|||
|
||||
// GetOTPByEmail to get otp for a given email address
|
||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||
var otp *models.OTP
|
||||
var otp models.OTP
|
||||
query := fmt.Sprintf("FOR d in %s FILTER d.email == @email RETURN d", models.Collections.OTP)
|
||||
bindVars := map[string]interface{}{
|
||||
"email": emailAddress,
|
||||
|
@ -64,13 +64,13 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
|
|||
}
|
||||
break
|
||||
}
|
||||
_, err := cursor.ReadDocument(ctx, otp)
|
||||
_, err := cursor.ReadDocument(ctx, &otp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return otp, nil
|
||||
return &otp, nil
|
||||
}
|
||||
|
||||
// DeleteOTP to delete otp
|
||||
|
|
|
@ -33,15 +33,15 @@ func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP,
|
|||
|
||||
// GetOTPByEmail to get otp for a given email address
|
||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||
var otp *models.OTP
|
||||
var otp models.OTP
|
||||
|
||||
otpCollection := p.db.Collection(models.Collections.OTP, options.Collection())
|
||||
err := otpCollection.FindOne(ctx, bson.M{"email": emailAddress}).Decode(otp)
|
||||
err := otpCollection.FindOne(ctx, bson.M{"email": emailAddress}).Decode(&otp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return otp, nil
|
||||
return &otp, nil
|
||||
}
|
||||
|
||||
// DeleteOTP to delete otp
|
||||
|
|
|
@ -32,13 +32,13 @@ func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP,
|
|||
|
||||
// GetOTPByEmail to get otp for a given email address
|
||||
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
|
||||
var otp *models.OTP
|
||||
var otp models.OTP
|
||||
|
||||
result := p.db.Where("email = ?", emailAddress).First(otp)
|
||||
result := p.db.Where("email = ?", emailAddress).First(&otp)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return otp, nil
|
||||
return &otp, nil
|
||||
}
|
||||
|
||||
// DeleteOTP to delete otp
|
||||
|
|
|
@ -2,11 +2,111 @@ package resolvers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// VerifyOtpResolver resolver for verify otp mutation
|
||||
func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*model.AuthResponse, error) {
|
||||
return nil, nil
|
||||
var res *model.AuthResponse
|
||||
gc, err := utils.GinContextFromContext(ctx)
|
||||
|
||||
if err != nil {
|
||||
log.Debug("Failed to get GinContext: ", err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
otp, err := db.Provider.GetOTPByEmail(ctx, params.Email)
|
||||
|
||||
if err != nil {
|
||||
log.Debug("Failed to get otp request by email: ", err)
|
||||
return res, fmt.Errorf(`invalid email: %s`, err.Error())
|
||||
}
|
||||
|
||||
expiresIn := otp.ExpiresAt - time.Now().Unix()
|
||||
|
||||
if params.Otp != otp.Otp || expiresIn < 0 {
|
||||
log.Debug("Failed to verify otp request: ", err)
|
||||
return res, fmt.Errorf(`invalid otp: %s`, err.Error())
|
||||
}
|
||||
|
||||
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
|
||||
|
||||
if err != nil {
|
||||
log.Debug("Failed to get user by email: ", err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
isSignUp := user.EmailVerifiedAt == nil
|
||||
|
||||
// TODO - Add Login method in DB
|
||||
|
||||
loginMethod := constants.AuthRecipeMethodBasicAuth
|
||||
|
||||
roles := strings.Split(user.Roles, ",")
|
||||
scope := []string{"openid", "email", "profile"}
|
||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope, loginMethod)
|
||||
|
||||
if err != nil {
|
||||
log.Debug("Failed to create auth token: ", err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
err = db.Provider.DeleteOTP(gc, otp)
|
||||
|
||||
if err != nil {
|
||||
log.Debug("Failed to delete otp: ", err)
|
||||
}
|
||||
if isSignUp {
|
||||
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user)
|
||||
} else {
|
||||
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, loginMethod, user)
|
||||
}
|
||||
|
||||
db.Provider.AddSession(ctx, models.Session{
|
||||
UserID: user.ID,
|
||||
UserAgent: utils.GetUserAgent(gc.Request),
|
||||
IP: utils.GetIP(gc.Request),
|
||||
})
|
||||
}()
|
||||
|
||||
authTokenExpiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||
if authTokenExpiresIn <= 0 {
|
||||
authTokenExpiresIn = 1
|
||||
}
|
||||
|
||||
if authTokenExpiresIn <= 0 {
|
||||
authTokenExpiresIn = 1
|
||||
}
|
||||
|
||||
res = &model.AuthResponse{
|
||||
Message: `OTP verified successfully.`,
|
||||
AccessToken: &authToken.AccessToken.Token,
|
||||
IDToken: &authToken.IDToken.Token,
|
||||
ExpiresIn: &authTokenExpiresIn,
|
||||
User: user.AsAPIUser(),
|
||||
}
|
||||
|
||||
sessionKey := loginMethod + ":" + user.ID
|
||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||
|
||||
if authToken.RefreshToken != nil {
|
||||
res.RefreshToken = &authToken.RefreshToken.Token
|
||||
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ func TestResolvers(t *testing.T) {
|
|||
metaTests(t, s)
|
||||
inviteUserTest(t, s)
|
||||
validateJwtTokenTest(t, s)
|
||||
|
||||
verifyOTPTest(t, s)
|
||||
webhookLogsTest(t, s) // get logs after above resolver tests are done
|
||||
deleteWebhookTest(t, s) // delete webhooks (admin resolver)
|
||||
})
|
||||
|
|
42
server/test/verify_otp_test.go
Normal file
42
server/test/verify_otp_test.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func verifyOTPTest(t *testing.T, s TestSetup) {
|
||||
t.Helper()
|
||||
t.Run(`should verify otp`, func(t *testing.T) {
|
||||
_, ctx := createContext(s)
|
||||
email := "verify_otp." + s.TestInfo.Email
|
||||
res, err := resolvers.SignupResolver(ctx, model.SignUpInput{
|
||||
Email: email,
|
||||
Password: s.TestInfo.Password,
|
||||
ConfirmPassword: s.TestInfo.Password,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
otp, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||
Otp: "123456",
|
||||
Email: email,
|
||||
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
||||
})
|
||||
assert.Equal(t, email, otp.Email)
|
||||
assert.Nil(t, res.AccessToken, "access token should be nil")
|
||||
|
||||
verifyRes, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||
Otp: "123456",
|
||||
Email: email,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NotEqual(t, verifyRes.AccessToken, "", "access token should not be empty")
|
||||
cleanData(email)
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user