fix: persist login sessions for workbench auth
This commit is contained in:
+16
-1
@@ -1317,7 +1317,22 @@ func (s *Session) onLogin(msgID string, timestamp time.Time, rec *auth.Rec, miss
|
||||
// GenSecret fails only if tokenLifetime is < 0. It can't be < 0 here,
|
||||
// otherwise login would have failed earlier.
|
||||
rec.Features = features
|
||||
params["token"], params["expires"], _ = store.Store.GetLogicalAuthHandler("token").GenSecret(rec)
|
||||
token, expires, _ := store.Store.GetLogicalAuthHandler("token").GenSecret(rec)
|
||||
params["token"], params["expires"] = token, expires
|
||||
if !s.uid.IsZero() && features&auth.FeatureNoLogin == 0 {
|
||||
if enabled, err := store.StoreLoginSession(token, store.LoginSession{
|
||||
UserID: store.DecodeUid(rec.Uid),
|
||||
TenantID: int64(s.tenantID),
|
||||
TenantCode: s.tenantCode,
|
||||
DeviceID: s.deviceID,
|
||||
AuthLevel: rec.AuthLevel.String(),
|
||||
State: "active",
|
||||
ExpiresAt: expires.Format(time.RFC3339),
|
||||
IssuedAt: time.Now().UTC().Format(time.RFC3339),
|
||||
}, time.Until(expires)); enabled && err != nil {
|
||||
logs.Warn.Println("s.onLogin: failed to store login session", rec.Uid, err, s.sid)
|
||||
}
|
||||
}
|
||||
|
||||
reply.Ctrl.Params = params
|
||||
return reply
|
||||
|
||||
@@ -62,6 +62,17 @@ type RealtimeFanoutEnvelope struct {
|
||||
Message json.RawMessage `json:"message"`
|
||||
}
|
||||
|
||||
type LoginSession struct {
|
||||
UserID int64 `json:"user_id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
TenantCode string `json:"tenant_code"`
|
||||
DeviceID string `json:"device_id,omitempty"`
|
||||
AuthLevel string `json:"auth_level"`
|
||||
State string `json:"state"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
IssuedAt string `json:"issued_at"`
|
||||
}
|
||||
|
||||
type groupMessageRuntime interface {
|
||||
Close() error
|
||||
Claim(tenantID types.TenantID, topic string, from types.Uid, clientMsgID string) (*groupMessageUniqueRecord, bool, error)
|
||||
@@ -95,6 +106,7 @@ type groupMessageRuntime interface {
|
||||
ClaimShortState(namespace, id string, ttl time.Duration) (bool, error)
|
||||
ClaimShortStateValue(namespace, id, value string, ttl time.Duration) (bool, bool, error)
|
||||
ShortStateExists(namespace, id string) (bool, error)
|
||||
StoreLoginSession(token []byte, session LoginSession, ttl time.Duration) error
|
||||
}
|
||||
|
||||
var groupMsgRuntime groupMessageRuntime
|
||||
@@ -190,6 +202,13 @@ func IsLoginTokenRevoked(tenantID types.TenantID, token []byte) (bool, bool, err
|
||||
return revoked, true, err
|
||||
}
|
||||
|
||||
func StoreLoginSession(token []byte, session LoginSession, ttl time.Duration) (bool, error) {
|
||||
if groupMsgRuntime == nil || len(token) == 0 || ttl <= 0 {
|
||||
return false, nil
|
||||
}
|
||||
return true, groupMsgRuntime.StoreLoginSession(token, session, ttl)
|
||||
}
|
||||
|
||||
func RefreshUserPresence(tenantID types.TenantID, uid types.Uid, sid, nodeID string) error {
|
||||
if groupMsgRuntime == nil || !tenantID.IsValid() || uid.IsZero() || sid == "" {
|
||||
return nil
|
||||
@@ -990,6 +1009,18 @@ func (r *redisGroupMessageRuntime) ShortStateExists(namespace, id string) (bool,
|
||||
return count > 0, err
|
||||
}
|
||||
|
||||
func (r *redisGroupMessageRuntime) StoreLoginSession(token []byte, session LoginSession, ttl time.Duration) error {
|
||||
if len(token) == 0 || ttl <= 0 {
|
||||
return nil
|
||||
}
|
||||
digest := sha256.Sum256(token)
|
||||
payload, err := json.Marshal(session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.client.Set(context.Background(), r.loginSessionKey(hex.EncodeToString(digest[:])), payload, ttl).Err()
|
||||
}
|
||||
|
||||
func (r *redisGroupMessageRuntime) hotSeqIDs(tenantID types.TenantID, topic string, opts *types.QueryOpt, limit int) ([]int64, bool, error) {
|
||||
if opts != nil && len(opts.IdRanges) > 0 {
|
||||
seqs := expandRanges(opts.IdRanges, limit)
|
||||
@@ -1133,6 +1164,10 @@ func (r *redisGroupMessageRuntime) shortStateKey(namespace, id string) string {
|
||||
return r.key(types.ZeroTenantID, "short", namespace, id)
|
||||
}
|
||||
|
||||
func (r *redisGroupMessageRuntime) loginSessionKey(tokenHash string) string {
|
||||
return strings.TrimSuffix(r.prefix, ":") + ":session:token:" + tokenHash
|
||||
}
|
||||
|
||||
func (r *redisGroupMessageRuntime) cacheTTL(namespace string) time.Duration {
|
||||
ttl := r.cfg.CacheTTL
|
||||
if namespace == "verification" || namespace == "action_token" {
|
||||
|
||||
@@ -171,6 +171,10 @@ func (r *testGroupMessageRuntime) ShortStateExists(namespace, id string) (bool,
|
||||
return r.shortStates[namespace+":"+id], nil
|
||||
}
|
||||
|
||||
func (r *testGroupMessageRuntime) StoreLoginSession([]byte, LoginSession, time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestLoginTokenRevocation(t *testing.T) {
|
||||
oldRuntime := groupMsgRuntime
|
||||
groupMsgRuntime = newTestGroupMessageRuntime()
|
||||
|
||||
Reference in New Issue
Block a user