Skip to content

Commit

Permalink
fix(audit log): add missing audit log statements
Browse files Browse the repository at this point in the history
* add missing failure statements to registration and login
* add missing success to registration and login

Related to: #7
  • Loading branch information
Stefan Jacobi committed Nov 9, 2023
1 parent 416ca39 commit eb1c847
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 1 deletion.
49 changes: 49 additions & 0 deletions server/api/handler/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/labstack/echo/v4"
"github.com/teamhanko/passkey-server/api/dto/intern"
"github.com/teamhanko/passkey-server/api/dto/response"
auditlog "github.com/teamhanko/passkey-server/audit_log"
"github.com/teamhanko/passkey-server/crypto/jwt"
"github.com/teamhanko/passkey-server/persistence"
"github.com/teamhanko/passkey-server/persistence/models"
Expand Down Expand Up @@ -45,12 +46,24 @@ func (lh *loginHandler) Init(ctx echo.Context) error {
webauthn.WithUserVerification(h.config.WebauthnConfig.UserVerification),
)
if err != nil {
auditErr := h.auditLog.Create(ctx, h.tenant, models.AuditLogWebAuthnAuthenticationInitFailed, nil, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return fmt.Errorf("failed to create webauthn assertion options for discoverable login: %w", err)
}

err = lh.persister.GetWebauthnSessionDataPersister(nil).Create(*intern.WebauthnSessionDataToModel(sessionData, h.tenant.ID, models.WebauthnOperationAuthentication))
if err != nil {
auditErr := h.auditLog.Create(ctx, h.tenant, models.AuditLogWebAuthnAuthenticationInitFailed, nil, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return fmt.Errorf("failed to store webauthn assertion session data: %w", err)
}
Expand All @@ -61,6 +74,12 @@ func (lh *loginHandler) Init(ctx echo.Context) error {
options.Response.AllowedCredentials[i].Transport = nil
}

auditErr := h.auditLog.Create(ctx, h.tenant, models.AuditLogWebAuthnAuthenticationInitSucceeded, nil, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

return ctx.JSON(http.StatusOK, options)
}

Expand All @@ -84,13 +103,25 @@ func (lh *loginHandler) Finish(ctx echo.Context) error {

sessionData, err := lh.getSessionDataByChallenge(parsedRequest.Response.CollectedClientData.Challenge, sessionDataPersister, h.tenant.ID)
if err != nil {
auditErr := h.auditLog.Create(ctx, h.tenant, models.AuditLogWebAuthnAuthenticationFinalFailed, nil, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return echo.NewHTTPError(http.StatusUnauthorized, "failed to get session data").SetInternal(err)
}
sessionDataModel := intern.WebauthnSessionDataFromModel(sessionData)

webauthnUser, err := lh.getWebauthnUserByUserHandle(parsedRequest.Response.UserHandle, h.tenant.ID, webauthnUserPersister)
if err != nil {
auditErr := h.auditLog.Create(ctx, h.tenant, models.AuditLogWebAuthnAuthenticationFinalFailed, &webauthnUser.UserId, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return echo.NewHTTPError(http.StatusUnauthorized, "failed to get user handle").SetInternal(err)
}
Expand All @@ -100,6 +131,12 @@ func (lh *loginHandler) Finish(ctx echo.Context) error {
}, *sessionDataModel, parsedRequest)

if err != nil {
auditErr := h.auditLog.Create(ctx, h.tenant, models.AuditLogWebAuthnAuthenticationFinalFailed, &webauthnUser.UserId, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return echo.NewHTTPError(http.StatusUnauthorized, "failed to validate assertion").SetInternal(err)
}
Expand All @@ -114,6 +151,12 @@ func (lh *loginHandler) Finish(ctx echo.Context) error {
dbCred.LastUsedAt = &now
err = credentialPersister.Update(dbCred)
if err != nil {
auditErr := h.auditLog.Create(ctx, h.tenant, models.AuditLogWebAuthnAuthenticationFinalFailed, &webauthnUser.UserId, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return fmt.Errorf("failed to update webauthn credential: %w", err)
}
Expand All @@ -132,6 +175,12 @@ func (lh *loginHandler) Finish(ctx echo.Context) error {
return fmt.Errorf("failed to generate jwt: %w", err)
}

auditErr := h.auditLog.Create(ctx, h.tenant, models.AuditLogWebAuthnAuthenticationFinalSucceeded, &webauthnUser.UserId, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

return ctx.JSON(http.StatusOK, &response.TokenDto{Token: token})
})
}
Expand Down
37 changes: 36 additions & 1 deletion server/api/handler/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/teamhanko/passkey-server/api/dto/intern"
"github.com/teamhanko/passkey-server/api/dto/request"
"github.com/teamhanko/passkey-server/api/dto/response"
auditlog "github.com/teamhanko/passkey-server/audit_log"
"github.com/teamhanko/passkey-server/crypto/jwt"
"github.com/teamhanko/passkey-server/persistence"
"github.com/teamhanko/passkey-server/persistence/models"
Expand Down Expand Up @@ -84,17 +85,33 @@ func (r *registrationHandler) Init(ctx echo.Context) error {
webauthn.WithConveyancePreference(protocol.PreferNoAttestation),
// don't set the excludeCredentials list, so an already registered device can be re-registered
)
if err != nil {
auditErr := h.auditLog.CreateWithConnection(tx, ctx, h.tenant, models.AuditLogWebAuthnRegistrationInitFailed, &webauthnUser.UserID, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return fmt.Errorf("failed to begin registration: %w", err)
}

err = webauthnSessionPersister.Create(*intern.WebauthnSessionDataToModel(sessionData, h.tenant.ID, models.WebauthnOperationRegistration))
if err != nil {
auditErr := h.auditLog.CreateWithConnection(tx, ctx, h.tenant, models.AuditLogWebAuthnRegistrationInitFailed, &webauthnUser.UserID, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return fmt.Errorf("failed to create session data: %w", err)
}

err = h.auditLog.CreateWithConnection(tx, ctx, h.tenant, models.AuditLogWebAuthnRegistrationInitSucceeded, &webauthnUser.UserID, nil)
if err != nil {
ctx.Logger().Error(err)
return fmt.Errorf("failed to create audit log: %w", err)
return fmt.Errorf(auditlog.CreationFailureFormat, err)
}

return ctx.JSON(http.StatusOK, options)
Expand Down Expand Up @@ -152,6 +169,12 @@ func (r *registrationHandler) Finish(ctx echo.Context) error {
errorStatus = http.StatusUnprocessableEntity
}

auditErr := h.auditLog.CreateWithConnection(tx, ctx, h.tenant, models.AuditLogWebAuthnRegistrationFinalFailed, &webauthnUser.UserId, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return echo.NewHTTPError(errorStatus, errorMessage).SetInternal(err)
}
Expand All @@ -160,6 +183,12 @@ func (r *registrationHandler) Finish(ctx echo.Context) error {
model := intern.WebauthnCredentialToModel(credential, sessionData.UserId, userModel.ID, flags.HasBackupEligible(), flags.HasBackupState())
err = r.persister.GetWebauthnCredentialPersister(tx).Create(model)
if err != nil {
auditErr := h.auditLog.CreateWithConnection(tx, ctx, h.tenant, models.AuditLogWebAuthnRegistrationFinalFailed, &webauthnUser.UserId, nil)
if auditErr != nil {
ctx.Logger().Error(auditErr)
return fmt.Errorf(auditlog.CreationFailureFormat, auditErr)
}

ctx.Logger().Error(err)
return fmt.Errorf("failed to store webauthn credential: %w", err)
}
Expand All @@ -176,6 +205,12 @@ func (r *registrationHandler) Finish(ctx echo.Context) error {
return fmt.Errorf("failed to generate jwt: %w", err)
}

err = h.auditLog.CreateWithConnection(tx, ctx, h.tenant, models.AuditLogWebAuthnRegistrationFinalSucceeded, &webauthnUser.UserId, nil)
if err != nil {
ctx.Logger().Error(err)
return fmt.Errorf(auditlog.CreationFailureFormat, err)
}

return ctx.JSON(http.StatusOK, &response.TokenDto{Token: token})
})
}
Expand Down
4 changes: 4 additions & 0 deletions server/audit_log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ type logger struct {
consoleLoggingEnabled bool
}

const (
CreationFailureFormat = "failed to create audit log: %w"
)

func NewLogger(persister persistence.Persister, cfg models.AuditLogConfig) Logger {
var loggerOutput *os.File = nil
switch cfg.OutputStream {
Expand Down

0 comments on commit eb1c847

Please sign in to comment.