mirror of
https://github.com/photoprism/photoprism.git
synced 2026-07-17 16:49:04 +00:00
Auth: Store session login_at as NULL when no client IP is set #5707
This commit is contained in:
parent
b2116154d3
commit
1b572c0da7
5 changed files with 70 additions and 4 deletions
|
|
@ -66,7 +66,7 @@ type Session struct {
|
||||||
data *SessionData `gorm:"-" yaml:"-"`
|
data *SessionData `gorm:"-" yaml:"-"`
|
||||||
RefID string `gorm:"type:VARBINARY(16);default:'';" json:"ID" yaml:"-"`
|
RefID string `gorm:"type:VARBINARY(16);default:'';" json:"ID" yaml:"-"`
|
||||||
LoginIP string `gorm:"size:64;column:login_ip" json:"LoginIP" yaml:"-"`
|
LoginIP string `gorm:"size:64;column:login_ip" json:"LoginIP" yaml:"-"`
|
||||||
LoginAt time.Time `json:"LoginAt" yaml:"-"`
|
LoginAt *time.Time `json:"LoginAt" yaml:"-"`
|
||||||
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt"`
|
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt"`
|
||||||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"UpdatedAt"`
|
UpdatedAt time.Time `json:"UpdatedAt" yaml:"UpdatedAt"`
|
||||||
Status int `gorm:"-" json:"Status" yaml:"-"`
|
Status int `gorm:"-" json:"Status" yaml:"-"`
|
||||||
|
|
@ -1053,7 +1053,7 @@ func (m *Session) SetClientIP(ip string) {
|
||||||
|
|
||||||
if m.LoginIP == "" {
|
if m.LoginIP == "" {
|
||||||
m.LoginIP = ip
|
m.LoginIP = ip
|
||||||
m.LoginAt = Now()
|
m.LoginAt = TimeStamp()
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -95,4 +95,47 @@ func TestAddClientSession(t *testing.T) {
|
||||||
|
|
||||||
t.Logf("sess: %#v", sess)
|
t.Logf("sess: %#v", sess)
|
||||||
})
|
})
|
||||||
|
t.Run("NoClientIPPersistsNullLoginAt", func(t *testing.T) {
|
||||||
|
// Sessions created without a client IP (e.g. via "photoprism auth add")
|
||||||
|
// must persist login_at as SQL NULL, not a zero "0000-00-00" datetime
|
||||||
|
// that strict MySQL/MariaDB sql_modes reject with Error 1292.
|
||||||
|
// A value-typed LoginAt leaves Go's zero time.Time, which go-sql-driver/mysql serializes as the literal 0000-00-00.
|
||||||
|
sess, err := AddClientSession("", unix.Day, "metrics", authn.GrantCLI, nil)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
if sess == nil {
|
||||||
|
t.Fatal("session must not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, sess.LoginAt)
|
||||||
|
|
||||||
|
var nullCount int
|
||||||
|
if err = UnscopedDb().Table("auth_sessions").
|
||||||
|
Where("id = ? AND login_at IS NULL", sess.ID).
|
||||||
|
Count(&nullCount).Error; err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 1, nullCount, "login_at must be NULL when no client IP was set")
|
||||||
|
})
|
||||||
|
t.Run("ClientIPSetsLoginAt", func(t *testing.T) {
|
||||||
|
sess := NewClientSession("", unix.Day, "metrics", authn.GrantClientCredentials, nil)
|
||||||
|
sess.SetClientIP("203.0.113.7")
|
||||||
|
|
||||||
|
assert.NoError(t, sess.Create())
|
||||||
|
|
||||||
|
if sess.LoginAt == nil {
|
||||||
|
t.Fatal("login_at must be set when a client IP is present")
|
||||||
|
}
|
||||||
|
|
||||||
|
var nullCount int
|
||||||
|
if err := UnscopedDb().Table("auth_sessions").
|
||||||
|
Where("id = ? AND login_at IS NULL", sess.ID).
|
||||||
|
Count(&nullCount).Error; err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 0, nullCount, "login_at must not be NULL when a client IP was set")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ var SessionFixtures = SessionMap{
|
||||||
user: UserFixtures.Pointer("bob"),
|
user: UserFixtures.Pointer("bob"),
|
||||||
UserUID: UserFixtures.Pointer("bob").UserUID,
|
UserUID: UserFixtures.Pointer("bob").UserUID,
|
||||||
UserName: UserFixtures.Pointer("bob").UserName,
|
UserName: UserFixtures.Pointer("bob").UserName,
|
||||||
LoginAt: Now().Add(-24),
|
LoginAt: TimePointer(Now().Add(-24)),
|
||||||
CreatedAt: Now().Add(-24),
|
CreatedAt: Now().Add(-24),
|
||||||
UpdatedAt: Now().Add(-24),
|
UpdatedAt: Now().Add(-24),
|
||||||
},
|
},
|
||||||
|
|
@ -184,7 +184,7 @@ var SessionFixtures = SessionMap{
|
||||||
user: UserFixtures.Pointer("friend"),
|
user: UserFixtures.Pointer("friend"),
|
||||||
UserUID: UserFixtures.Pointer("friend").UserUID,
|
UserUID: UserFixtures.Pointer("friend").UserUID,
|
||||||
UserName: UserFixtures.Pointer("friend").UserName,
|
UserName: UserFixtures.Pointer("friend").UserName,
|
||||||
LoginAt: Now().Add(-12),
|
LoginAt: TimePointer(Now().Add(-12)),
|
||||||
CreatedAt: Now().Add(-20),
|
CreatedAt: Now().Add(-20),
|
||||||
UpdatedAt: Now().Add(-12),
|
UpdatedAt: Now().Add(-12),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,15 @@ func TimeStamp() *time.Time {
|
||||||
return &t
|
return &t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TimePointer returns a reference to the specified time, or nil if it is the zero value.
|
||||||
|
func TimePointer(t time.Time) *time.Time {
|
||||||
|
if t.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &t
|
||||||
|
}
|
||||||
|
|
||||||
// Time returns a reference to the specified time in UTC, truncated to seconds, or nil if it is invalid.
|
// Time returns a reference to the specified time in UTC, truncated to seconds, or nil if it is invalid.
|
||||||
func Time(s string) *time.Time {
|
func Time(s string) *time.Time {
|
||||||
if t, err := time.Parse(time.RFC3339, s); err == nil {
|
if t, err := time.Parse(time.RFC3339, s); err == nil {
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,20 @@ func TestTimeStamp(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTimePointer(t *testing.T) {
|
||||||
|
t.Run("NonZero", func(t *testing.T) {
|
||||||
|
now := Now()
|
||||||
|
result := TimePointer(now)
|
||||||
|
if result == nil {
|
||||||
|
t.Fatal("result must not be nil")
|
||||||
|
}
|
||||||
|
assert.Equal(t, now, *result)
|
||||||
|
})
|
||||||
|
t.Run("Zero", func(t *testing.T) {
|
||||||
|
assert.Nil(t, TimePointer(time.Time{}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestTime(t *testing.T) {
|
func TestTime(t *testing.T) {
|
||||||
result := Time("2022-01-02T13:04:05+01:00")
|
result := Time("2022-01-02T13:04:05+01:00")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue