Skip to content

Commit

Permalink
fix: create session in DB for old endpoints (#2052)
Browse files Browse the repository at this point in the history
* fix: create session in DB for old endpoints

The old endpoints do not store the session in the DB, this leads to an unauthorized error in old hanko elements versions prior 1.0.0 when any endpoint is called that requires a session because they check if the session is stored in the DB.

* test: fix test
  • Loading branch information
FreddyDevelop authored Feb 14, 2025
1 parent 480e428 commit c9684d1
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 4 deletions.
7 changes: 6 additions & 1 deletion backend/handler/passcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ func (h *PasscodeHandler) Finish(c echo.Context) error {
emailJwt = dto.JwtFromEmailModel(e)
}

token, _, err := h.sessionManager.GenerateJWT(*passcode.UserId, emailJwt)
token, rawToken, err := h.sessionManager.GenerateJWT(*passcode.UserId, emailJwt)
if err != nil {
return fmt.Errorf("failed to generate jwt: %w", err)
}
Expand All @@ -411,6 +411,11 @@ func (h *PasscodeHandler) Finish(c echo.Context) error {
return fmt.Errorf("failed to create session token: %w", err)
}

err = storeSession(h.cfg, h.persister, *passcode.UserId, rawToken, c, tx)
if err != nil {
return fmt.Errorf("failed to store session in DB: %w", err)
}

c.Response().Header().Set("X-Session-Lifetime", fmt.Sprintf("%d", cookie.MaxAge))

if h.cfg.Session.EnableAuthTokenHeader {
Expand Down
7 changes: 6 additions & 1 deletion backend/handler/password.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func (h *PasswordHandler) Login(c echo.Context) error {
emailJwt = dto.JwtFromEmailModel(e)
}

token, _, err := h.sessionManager.GenerateJWT(pw.UserId, emailJwt)
token, rawToken, err := h.sessionManager.GenerateJWT(pw.UserId, emailJwt)
if err != nil {
return fmt.Errorf("failed to generate jwt: %w", err)
}
Expand All @@ -233,6 +233,11 @@ func (h *PasswordHandler) Login(c echo.Context) error {
return fmt.Errorf("failed to create session cookie: %w", err)
}

err = storeSession(h.cfg, h.persister, userId, rawToken, c, h.persister.GetConnection())
if err != nil {
return fmt.Errorf("failed to store session in DB: %w", err)
}

c.Response().Header().Set("X-Session-Lifetime", fmt.Sprintf("%d", cookie.MaxAge))

if h.cfg.Session.EnableAuthTokenHeader {
Expand Down
7 changes: 6 additions & 1 deletion backend/handler/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (h TokenHandler) Validate(c echo.Context) error {
emailJwt = dto.JwtFromEmailModel(e)
}

jwtToken, _, err := h.sessionManager.GenerateJWT(token.UserID, emailJwt)
jwtToken, rawToken, err := h.sessionManager.GenerateJWT(token.UserID, emailJwt)
if err != nil {
return fmt.Errorf("failed to generate jwt: %w", err)
}
Expand All @@ -102,6 +102,11 @@ func (h TokenHandler) Validate(c echo.Context) error {
return fmt.Errorf("failed to create session token: %w", err)
}

err = storeSession(h.cfg, h.persister, token.UserID, rawToken, c, h.persister.GetConnection())
if err != nil {
return fmt.Errorf("failed to store session in DB: %w", err)
}

c.Response().Header().Set("X-Session-Lifetime", fmt.Sprintf("%d", cookie.MaxAge))

if h.cfg.Session.EnableAuthTokenHeader {
Expand Down
52 changes: 52 additions & 0 deletions backend/handler/utils.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package handler

import (
"fmt"
"github.com/gobuffalo/nulls"
"github.com/gobuffalo/pop/v6"
"github.com/gofrs/uuid"
"github.com/labstack/echo/v4"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/teamhanko/hanko/backend/config"
"github.com/teamhanko/hanko/backend/persistence"
"github.com/teamhanko/hanko/backend/persistence/models"
"net/http"
)

Expand All @@ -21,3 +29,47 @@ func loadDto[I any](ctx echo.Context) (*I, error) {

return &adminDto, nil
}

func storeSession(cfg *config.Config, persister persistence.Persister, userId uuid.UUID, rawToken jwt.Token, httpContext echo.Context, tx *pop.Connection) error {
activeSessions, err := persister.GetSessionPersisterWithConnection(tx).ListActive(userId)
if err != nil {
return fmt.Errorf("failed to list active sessions: %w", err)
}

// remove all server side sessions that exceed the limit
if len(activeSessions) >= cfg.Session.Limit {
for i := cfg.Session.Limit - 1; i < len(activeSessions); i++ {
err = persister.GetSessionPersisterWithConnection(tx).Delete(activeSessions[i])
if err != nil {
return fmt.Errorf("failed to remove latest session: %w", err)
}
}
}

sessionID, _ := rawToken.Get("session_id")

expirationTime := rawToken.Expiration()
sessionModel := models.Session{
ID: uuid.FromStringOrNil(sessionID.(string)),
UserID: userId,
CreatedAt: rawToken.IssuedAt(),
UpdatedAt: rawToken.IssuedAt(),
ExpiresAt: &expirationTime,
LastUsed: rawToken.IssuedAt(),
}

if cfg.Session.AcquireIPAddress {
sessionModel.IpAddress = nulls.NewString(httpContext.RealIP())
}

if cfg.Session.AcquireUserAgent {
sessionModel.UserAgent = nulls.NewString(httpContext.Request().UserAgent())
}

err = persister.GetSessionPersisterWithConnection(tx).Create(sessionModel)
if err != nil {
return fmt.Errorf("failed to store session: %w", err)
}

return nil
}
7 changes: 6 additions & 1 deletion backend/handler/webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func (h *WebauthnHandler) FinishAuthentication(c echo.Context) error {
emailJwt = dto.JwtFromEmailModel(e)
}

token, _, err := h.sessionManager.GenerateJWT(webauthnUser.UserId, emailJwt)
token, rawToken, err := h.sessionManager.GenerateJWT(webauthnUser.UserId, emailJwt)
if err != nil {
return fmt.Errorf("failed to generate jwt: %w", err)
}
Expand All @@ -433,6 +433,11 @@ func (h *WebauthnHandler) FinishAuthentication(c echo.Context) error {
return fmt.Errorf("failed to create session cookie: %w", err)
}

err = storeSession(h.cfg, h.persister, webauthnUser.UserId, rawToken, c, tx)
if err != nil {
return fmt.Errorf("failed to store session in DB: %w", err)
}

c.Response().Header().Set("X-Session-Lifetime", fmt.Sprintf("%d", cookie.MaxAge))

if h.cfg.Session.EnableAuthTokenHeader {
Expand Down
1 change: 1 addition & 0 deletions backend/test/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var DefaultConfig = config.Config{
Cookie: config.Cookie{
SameSite: "none",
},
Limit: 5,
},
Service: config.Service{
Name: "Test",
Expand Down

0 comments on commit c9684d1

Please sign in to comment.