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,
|
// GenSecret fails only if tokenLifetime is < 0. It can't be < 0 here,
|
||||||
// otherwise login would have failed earlier.
|
// otherwise login would have failed earlier.
|
||||||
rec.Features = features
|
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
|
reply.Ctrl.Params = params
|
||||||
return reply
|
return reply
|
||||||
|
|||||||
@@ -62,6 +62,17 @@ type RealtimeFanoutEnvelope struct {
|
|||||||
Message json.RawMessage `json:"message"`
|
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 {
|
type groupMessageRuntime interface {
|
||||||
Close() error
|
Close() error
|
||||||
Claim(tenantID types.TenantID, topic string, from types.Uid, clientMsgID string) (*groupMessageUniqueRecord, bool, 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)
|
ClaimShortState(namespace, id string, ttl time.Duration) (bool, error)
|
||||||
ClaimShortStateValue(namespace, id, value string, ttl time.Duration) (bool, bool, error)
|
ClaimShortStateValue(namespace, id, value string, ttl time.Duration) (bool, bool, error)
|
||||||
ShortStateExists(namespace, id string) (bool, error)
|
ShortStateExists(namespace, id string) (bool, error)
|
||||||
|
StoreLoginSession(token []byte, session LoginSession, ttl time.Duration) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var groupMsgRuntime groupMessageRuntime
|
var groupMsgRuntime groupMessageRuntime
|
||||||
@@ -190,6 +202,13 @@ func IsLoginTokenRevoked(tenantID types.TenantID, token []byte) (bool, bool, err
|
|||||||
return revoked, true, 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 {
|
func RefreshUserPresence(tenantID types.TenantID, uid types.Uid, sid, nodeID string) error {
|
||||||
if groupMsgRuntime == nil || !tenantID.IsValid() || uid.IsZero() || sid == "" {
|
if groupMsgRuntime == nil || !tenantID.IsValid() || uid.IsZero() || sid == "" {
|
||||||
return nil
|
return nil
|
||||||
@@ -990,6 +1009,18 @@ func (r *redisGroupMessageRuntime) ShortStateExists(namespace, id string) (bool,
|
|||||||
return count > 0, err
|
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) {
|
func (r *redisGroupMessageRuntime) hotSeqIDs(tenantID types.TenantID, topic string, opts *types.QueryOpt, limit int) ([]int64, bool, error) {
|
||||||
if opts != nil && len(opts.IdRanges) > 0 {
|
if opts != nil && len(opts.IdRanges) > 0 {
|
||||||
seqs := expandRanges(opts.IdRanges, limit)
|
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)
|
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 {
|
func (r *redisGroupMessageRuntime) cacheTTL(namespace string) time.Duration {
|
||||||
ttl := r.cfg.CacheTTL
|
ttl := r.cfg.CacheTTL
|
||||||
if namespace == "verification" || namespace == "action_token" {
|
if namespace == "verification" || namespace == "action_token" {
|
||||||
|
|||||||
@@ -171,6 +171,10 @@ func (r *testGroupMessageRuntime) ShortStateExists(namespace, id string) (bool,
|
|||||||
return r.shortStates[namespace+":"+id], nil
|
return r.shortStates[namespace+":"+id], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *testGroupMessageRuntime) StoreLoginSession([]byte, LoginSession, time.Duration) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoginTokenRevocation(t *testing.T) {
|
func TestLoginTokenRevocation(t *testing.T) {
|
||||||
oldRuntime := groupMsgRuntime
|
oldRuntime := groupMsgRuntime
|
||||||
groupMsgRuntime = newTestGroupMessageRuntime()
|
groupMsgRuntime = newTestGroupMessageRuntime()
|
||||||
|
|||||||
Reference in New Issue
Block a user