Merge pull request #79 from itsscb:itsscb/issue76

Add check on db if session is expired
This commit is contained in:
itsscb 2023-10-08 22:28:58 +02:00 committed by GitHub
commit dcc5c4d76d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 70 additions and 39 deletions

View File

@ -22,7 +22,10 @@ func addAuthorization(
email string,
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.NotEmpty(t, payload)

View File

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

View File

@ -66,10 +66,16 @@ func (server *Server) renewAccessToken(ctx *gin.Context) {
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(
refreshPayload.Email,
id,
server.config.AccessTokenDuration,
)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return

View File

@ -2,8 +2,10 @@ package gapi
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"github.com/itsscb/df/bff/token"
"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)
}
// TODO: #76 Add check on db if session is expired
// session, err := server.store.GetSession(ctx, payload.ID)
// if err != nil {
// if err == sql.ErrNoRows {
// return nil, fmt.Errorf("no valid session found")
// }
// return nil, fmt.Errorf("could not get session")
// }
session, err := server.store.GetSession(ctx, payload.ID)
if err != nil {
if err == sql.ErrNoRows {
return nil, fmt.Errorf("no valid session found")
}
return nil, fmt.Errorf("could not get session")
}
// if session.IsBlocked || time.Now().After(session.ExpiresAt) {
// return nil, fmt.Errorf("blocked or expired")
// }
if session.IsBlocked || time.Now().After(session.ExpiresAt) {
return nil, fmt.Errorf("session blocked or expired")
}
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")
}
accessToken, accessPayload, err := server.tokenMaker.CreateToken(
account.Email,
server.config.AccessTokenDuration,
)
id, err := server.tokenMaker.NewTokenID()
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(
account.Email,
id,
server.config.RefreshTokenDuration,
)
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)
session, err := server.store.CreateSession(ctx, db.CreateSessionParams{
_, err = server.store.CreateSession(ctx, db.CreateSessionParams{
ID: refreshPayload.ID,
Email: account.Email,
RefreshToken: refreshToken,
@ -69,7 +76,7 @@ func (server *Server) Login(ctx context.Context, req *pb.LoginRequest) (*pb.Logi
}
rsp := &pb.LoginResponse{
SessionId: session.ID.String(),
SessionId: refreshPayload.ID.String(),
AccessToken: accessToken,
AccessTokenExpiresAt: timestamppb.New(accessPayload.ExpiredAt),
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")
}
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(
refreshPayload.Email,
id,
server.config.AccessTokenDuration,
)
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{

View File

@ -2,12 +2,15 @@ package token
import (
"time"
"github.com/google/uuid"
)
// Maker is an interface for managing tokens
type Maker interface {
NewTokenID() (uuid.UUID, error)
// 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(token string) (*Payload, error)

View File

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

View File

@ -18,7 +18,9 @@ func TestPasetoMaker(t *testing.T) {
issuedAt := time.Now()
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.NotEmpty(t, token)
require.NotEmpty(t, payload)
@ -37,7 +39,9 @@ func TestExpiredPasetoToken(t *testing.T) {
maker, err := NewPasetoMaker(devPrivateKeyHex)
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.NotEmpty(t, token)
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
func NewPayload(email string, duration time.Duration) (*Payload, error) {
tokenID, err := uuid.NewRandom()
if err != nil {
return nil, err
}
func NewPayload(email string, tokenID uuid.UUID, duration time.Duration) (*Payload, error) {
payload := &Payload{
ID: tokenID,
Email: email,