improvement: set last authentication timestamp on user and use it to check ssh access

This commit is contained in:
Johan Siebens
2024-02-12 10:27:58 +01:00
parent 7c2d5f723a
commit e39eb5824b
7 changed files with 71 additions and 14 deletions
@@ -0,0 +1,23 @@
package migration
import (
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
"time"
)
func m202402120800_user_last_authenticated() *gormigrate.Migration {
return &gormigrate.Migration{
ID: "202402120800",
Migrate: func(db *gorm.DB) error {
type User struct {
LastAuthenticated *time.Time
}
return db.AutoMigrate(
&User{},
)
},
Rollback: nil,
}
}
@@ -19,6 +19,7 @@ func Migrations() []*gormigrate.Migration {
m202312271200_account_last_authenticated(),
m202312290900_machine_indeces(),
m202401061400_machine_indeces(),
m202402120800_user_last_authenticated(),
}
return migrations
}
+3 -4
View File
@@ -9,10 +9,9 @@ import (
)
type Account struct {
ID uint64 `gorm:"primary_key"`
ExternalID string
LoginName string
LastAuthenticated *time.Time
ID uint64 `gorm:"primary_key"`
ExternalID string
LoginName string
}
func (r *repository) GetOrCreateAccount(ctx context.Context, externalID, loginName string) (*Account, bool, error) {
+1
View File
@@ -55,6 +55,7 @@ type Repository interface {
DeleteUser(ctx context.Context, userID uint64) error
ListUsers(ctx context.Context, tailnetID uint64) (Users, error)
DeleteUsersByTailnet(ctx context.Context, tailnetID uint64) error
SetUserLastAuthenticated(ctx context.Context, userID uint64, timestamp time.Time) error
SaveMachine(ctx context.Context, m *Machine) error
DeleteMachine(ctx context.Context, id uint64) (bool, error)
+22 -7
View File
@@ -5,6 +5,7 @@ import (
"errors"
"github.com/jsiebens/ionscale/internal/util"
"gorm.io/gorm"
"time"
)
type SystemRole string
@@ -38,13 +39,14 @@ func (s UserRole) IsAdmin() bool {
}
type User struct {
ID uint64 `gorm:"primary_key"`
Name string
UserType UserType
TailnetID uint64
Tailnet Tailnet
AccountID *uint64
Account *Account
ID uint64 `gorm:"primary_key"`
Name string
UserType UserType
LastAuthenticated *time.Time
TailnetID uint64
Tailnet Tailnet
AccountID *uint64
Account *Account
}
type Users []User
@@ -117,3 +119,16 @@ func (r *repository) DeleteUser(ctx context.Context, userID uint64) error {
tx := r.withContext(ctx).Delete(&User{ID: userID})
return tx.Error
}
func (r *repository) SetUserLastAuthenticated(ctx context.Context, userID uint64, timestamp time.Time) error {
tx := r.withContext(ctx).
Model(User{}).
Where("id = ?", userID).
Updates(map[string]interface{}{"last_authenticated": &timestamp})
if tx.Error != nil {
return tx.Error
}
return nil
}
+19 -1
View File
@@ -193,9 +193,20 @@ func (h *AuthenticationHandlers) Callback(c echo.Context) error {
if !machine.HasTags() && machine.User.AccountID != nil && *machine.User.AccountID == account.ID {
sshActionReq.Action = "accept"
if err := h.repository.SaveSSHActionRequest(ctx, sshActionReq); err != nil {
err := h.repository.Transaction(func(rp domain.Repository) error {
if err := rp.SetUserLastAuthenticated(ctx, machine.UserID, time.Now().UTC()); err != nil {
return err
}
if err := rp.SaveSSHActionRequest(ctx, sshActionReq); err != nil {
return err
}
return nil
})
if err != nil {
return logError(err)
}
return c.Redirect(http.StatusFound, "/a/success")
}
@@ -361,6 +372,9 @@ func (h *AuthenticationHandlers) endCliAuthenticationFlow(c echo.Context, form E
req.TailnetID = &tailnet.ID
err = h.repository.Transaction(func(rp domain.Repository) error {
if err := rp.SetUserLastAuthenticated(ctx, user.ID, time.Now().UTC()); err != nil {
return err
}
if err := rp.SaveApiKey(ctx, apiKey); err != nil {
return err
}
@@ -522,6 +536,10 @@ func (h *AuthenticationHandlers) endMachineRegistrationFlow(c echo.Context, form
registrationRequest.Error = ""
registrationRequest.UserID = user.ID
if err := rp.SetUserLastAuthenticated(ctx, m.UserID, time.Now().UTC()); err != nil {
return err
}
if err := rp.SaveMachine(ctx, m); err != nil {
return err
}
+2 -2
View File
@@ -52,8 +52,8 @@ func (h *SSHActionHandlers) StartAuth(c echo.Context) error {
return logError(err)
}
if machine.User.Account != nil && machine.User.Account.LastAuthenticated != nil {
sinceLastAuthentication := time.Since(*machine.User.Account.LastAuthenticated)
if machine.User.Account != nil && machine.User.LastAuthenticated != nil {
sinceLastAuthentication := time.Since(*machine.User.LastAuthenticated)
if sinceLastAuthentication < checkPeriod {
resp := &tailcfg.SSHAction{