Add check on db if session is expired

Fixes #76
This commit is contained in:
itsscb 2023-10-09 00:25:57 +02:00
parent a645765d43
commit ab2b04c3cd
10 changed files with 70 additions and 39 deletions

View File

@ -22,7 +22,10 @@ func addAuthorization(
email string, email string,
duration time.Duration, duration time.Duration,
) { ) {
token, payload, err := tokenMaker.CreateToken(email, duration) id, err := tokenMaker.NewTokenID()
require.NoError(t, err)
token, payload, err := tokenMaker.CreateToken(email, id, duration)
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, payload) require.NotEmpty(t, payload)

View File

@ -50,19 +50,22 @@ func (server *Server) loginAccount(ctx *gin.Context) {
return return
} }
accessToken, accessPayload, err := server.tokenMaker.CreateToken( id, err := server.tokenMaker.NewTokenID()
account.Email,
server.config.AccessTokenDuration,
)
if err != nil { if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err)) ctx.JSON(http.StatusInternalServerError, errorResponse(errors.New("failed to create session token")))
return
} }
refreshToken, refreshPayload, err := server.tokenMaker.CreateToken( refreshToken, refreshPayload, err := server.tokenMaker.CreateToken(
account.Email, account.Email,
id,
server.config.RefreshTokenDuration, server.config.RefreshTokenDuration,
) )
accessToken, accessPayload, err := server.tokenMaker.CreateToken(
account.Email,
id,
server.config.AccessTokenDuration,
)
if err != nil { if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err)) ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return return

View File

@ -66,10 +66,16 @@ func (server *Server) renewAccessToken(ctx *gin.Context) {
return return
} }
id, err := server.tokenMaker.NewTokenID()
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(errors.New("failed to create session token")))
}
accessToken, accessPayload, err := server.tokenMaker.CreateToken( accessToken, accessPayload, err := server.tokenMaker.CreateToken(
refreshPayload.Email, refreshPayload.Email,
id,
server.config.AccessTokenDuration, server.config.AccessTokenDuration,
) )
if err != nil { if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err)) ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return return

View File

@ -2,8 +2,10 @@ package gapi
import ( import (
"context" "context"
"database/sql"
"fmt" "fmt"
"strings" "strings"
"time"
"github.com/itsscb/df/bff/token" "github.com/itsscb/df/bff/token"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
@ -42,18 +44,17 @@ func (server *Server) authorizeUser(ctx context.Context) (*token.Payload, error)
return nil, fmt.Errorf("invalid access token: %s", err) return nil, fmt.Errorf("invalid access token: %s", err)
} }
// TODO: #76 Add check on db if session is expired session, err := server.store.GetSession(ctx, payload.ID)
// session, err := server.store.GetSession(ctx, payload.ID) if err != nil {
// if err != nil { if err == sql.ErrNoRows {
// if err == sql.ErrNoRows { return nil, fmt.Errorf("no valid session found")
// return nil, fmt.Errorf("no valid session found") }
// } return nil, fmt.Errorf("could not get session")
// return nil, fmt.Errorf("could not get session") }
// }
// if session.IsBlocked || time.Now().After(session.ExpiresAt) { if session.IsBlocked || time.Now().After(session.ExpiresAt) {
// return nil, fmt.Errorf("blocked or expired") return nil, fmt.Errorf("session blocked or expired")
// } }
return payload, nil return payload, nil
} }

View File

@ -35,16 +35,14 @@ func (server *Server) Login(ctx context.Context, req *pb.LoginRequest) (*pb.Logi
return nil, status.Error(codes.PermissionDenied, "invalid password") return nil, status.Error(codes.PermissionDenied, "invalid password")
} }
accessToken, accessPayload, err := server.tokenMaker.CreateToken( id, err := server.tokenMaker.NewTokenID()
account.Email,
server.config.AccessTokenDuration,
)
if err != nil { if err != nil {
return nil, status.Error(codes.Internal, "failed to create access token") return nil, status.Error(codes.Internal, "failed to create token id")
} }
refreshToken, refreshPayload, err := server.tokenMaker.CreateToken( refreshToken, refreshPayload, err := server.tokenMaker.CreateToken(
account.Email, account.Email,
id,
server.config.RefreshTokenDuration, server.config.RefreshTokenDuration,
) )
if err != nil { if err != nil {
@ -52,9 +50,18 @@ func (server *Server) Login(ctx context.Context, req *pb.LoginRequest) (*pb.Logi
} }
accessToken, accessPayload, err := server.tokenMaker.CreateToken(
account.Email,
id,
server.config.AccessTokenDuration,
)
if err != nil {
return nil, status.Error(codes.Internal, "failed to create access token")
}
mtdt := server.extractMetadata(ctx) mtdt := server.extractMetadata(ctx)
session, err := server.store.CreateSession(ctx, db.CreateSessionParams{ _, err = server.store.CreateSession(ctx, db.CreateSessionParams{
ID: refreshPayload.ID, ID: refreshPayload.ID,
Email: account.Email, Email: account.Email,
RefreshToken: refreshToken, RefreshToken: refreshToken,
@ -69,7 +76,7 @@ func (server *Server) Login(ctx context.Context, req *pb.LoginRequest) (*pb.Logi
} }
rsp := &pb.LoginResponse{ rsp := &pb.LoginResponse{
SessionId: session.ID.String(), SessionId: refreshPayload.ID.String(),
AccessToken: accessToken, AccessToken: accessToken,
AccessTokenExpiresAt: timestamppb.New(accessPayload.ExpiredAt), AccessTokenExpiresAt: timestamppb.New(accessPayload.ExpiredAt),
RefreshToken: refreshToken, RefreshToken: refreshToken,

View File

@ -52,12 +52,17 @@ func (server *Server) RefreshToken(ctx context.Context, req *pb.RefreshTokenRequ
return nil, status.Error(codes.PermissionDenied, "session expired") return nil, status.Error(codes.PermissionDenied, "session expired")
} }
id, err := server.tokenMaker.NewTokenID()
if err != nil {
return nil, status.Error(codes.Internal, "failed to create session token")
}
accessToken, accessPayload, err := server.tokenMaker.CreateToken( accessToken, accessPayload, err := server.tokenMaker.CreateToken(
refreshPayload.Email, refreshPayload.Email,
id,
server.config.AccessTokenDuration, server.config.AccessTokenDuration,
) )
if err != nil { if err != nil {
return nil, status.Error(codes.Internal, "cannot create session token") return nil, status.Error(codes.Internal, "failed to create session token")
} }
rsp := &pb.RefreshTokenResponse{ rsp := &pb.RefreshTokenResponse{

View File

@ -2,12 +2,15 @@ package token
import ( import (
"time" "time"
"github.com/google/uuid"
) )
// Maker is an interface for managing tokens // Maker is an interface for managing tokens
type Maker interface { type Maker interface {
NewTokenID() (uuid.UUID, error)
// CreateToken creates a new token for a specific username and duration // CreateToken creates a new token for a specific username and duration
CreateToken(email string, duration time.Duration) (string, *Payload, error) CreateToken(email string, id uuid.UUID, duration time.Duration) (string, *Payload, error)
// VerifyToken checks if the token is valid or not // VerifyToken checks if the token is valid or not
VerifyToken(token string) (*Payload, error) VerifyToken(token string) (*Payload, error)

View File

@ -30,9 +30,13 @@ func NewPasetoMaker(privateKeyHex string) (Maker, error) {
return maker, nil return maker, nil
} }
func (maker *PasetoMaker) NewTokenID() (uuid.UUID, error) {
return uuid.NewRandom()
}
// CreateToken creates a new token for a specific username and duration // CreateToken creates a new token for a specific username and duration
func (maker *PasetoMaker) CreateToken(email string, duration time.Duration) (string, *Payload, error) { func (maker *PasetoMaker) CreateToken(email string, id uuid.UUID, duration time.Duration) (string, *Payload, error) {
payload, err := NewPayload(email, duration) payload, err := NewPayload(email, id, duration)
if err != nil { if err != nil {
return "", payload, err return "", payload, err
} }
@ -41,7 +45,7 @@ func (maker *PasetoMaker) CreateToken(email string, duration time.Duration) (str
token.SetNotBefore(time.Now()) token.SetNotBefore(time.Now())
token.SetIssuedAt(payload.IssuedAt) token.SetIssuedAt(payload.IssuedAt)
token.SetExpiration(payload.ExpiredAt) token.SetExpiration(payload.ExpiredAt)
token.SetString("id", payload.ID.String()) token.SetString("id", id.String())
token.SetString("email", payload.Email) token.SetString("email", payload.Email)
signed := token.V4Sign(maker.privateKey, nil) signed := token.V4Sign(maker.privateKey, nil)

View File

@ -18,7 +18,9 @@ func TestPasetoMaker(t *testing.T) {
issuedAt := time.Now() issuedAt := time.Now()
expiredAt := issuedAt.Add(duration) expiredAt := issuedAt.Add(duration)
token, payload, err := maker.CreateToken(email, duration) id, err := maker.NewTokenID()
require.NoError(t, err)
token, payload, err := maker.CreateToken(email, id, duration)
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, token) require.NotEmpty(t, token)
require.NotEmpty(t, payload) require.NotEmpty(t, payload)
@ -37,7 +39,9 @@ func TestExpiredPasetoToken(t *testing.T) {
maker, err := NewPasetoMaker(devPrivateKeyHex) maker, err := NewPasetoMaker(devPrivateKeyHex)
require.NoError(t, err) require.NoError(t, err)
token, payload, err := maker.CreateToken(util.RandomEmail(), -time.Minute) id, err := maker.NewTokenID()
require.NoError(t, err)
token, payload, err := maker.CreateToken(util.RandomEmail(), id, -time.Minute)
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, token) require.NotEmpty(t, token)
require.NotEmpty(t, payload) require.NotEmpty(t, payload)

View File

@ -22,12 +22,7 @@ type Payload struct {
} }
// NewPayload creates a new token payload with a specific accountID and duration // NewPayload creates a new token payload with a specific accountID and duration
func NewPayload(email string, duration time.Duration) (*Payload, error) { func NewPayload(email string, tokenID uuid.UUID, duration time.Duration) (*Payload, error) {
tokenID, err := uuid.NewRandom()
if err != nil {
return nil, err
}
payload := &Payload{ payload := &Payload{
ID: tokenID, ID: tokenID,
Email: email, Email: email,