mirror of
https://github.com/jsiebens/ionscale.git
synced 2026-03-31 15:07:49 +01:00
improvement: set last authentication timestamp on user and use it to check ssh access
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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": ×tamp})
|
||||
|
||||
if tx.Error != nil {
|
||||
return tx.Error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
Reference in New Issue
Block a user