sessionstore

package
v0.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 27, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package sessionstore persists cloop dashboard sessions in the hub's own state database, sealing the one piece of credential material a session holds (Task 20176).

It is the SQLite half of the split described in pkg/oidcauth: that package owns the policy — two clocks, revocation, IdP revalidation — and is stdlib-only, while this one owns the storage and the crypto. The seam is oidcauth.SessionStore, and it is the same shape as secretbroker.Store/secretstore.

What is encrypted, and what happens without a key

A session row holds a subject, some claims, two timestamps, and a refresh token. Only the last of those is a credential: presented to the identity provider it yields fresh tokens for the user, so it is sealed with the same AES-256-GCM construction as a brokered secret, under the same CLOOP_SECRET_KEY.

When no key is configured, the store keeps working and simply does not retain refresh tokens. That is a deliberate degradation rather than a failure, and the alternatives are worse: writing a live credential in plaintext trades a strong property for a weak one, and refusing to open the store would mean a hub with no key cannot sign anyone in at all. The cost is bounded and visible — Available() reports it, the Active Sessions panel says so, and sessions still end on both timeouts and on explicit revocation. Only the IdP-initiated channel is lost.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is the statedb-backed oidcauth.SessionStore.

func New

func New(db *statedb.DB) (*Store, error)

New adapts a control-plane database.

Which database matters, and it is the same rule as API tokens and executor bindings: sessions belong in the *hub's* own state, never a managed project's. A tenant able to write to the file holding the session table could mint itself a session for any subject, which is a complete authentication bypass dressed up as a file write.

A missing or unusable encryption key is not an error here — it disables refresh-token retention and nothing else.

func (*Store) ApplyRefresh added in v0.0.2

func (s *Store) ApplyRefresh(id string, res oidcauth.RefreshResult) error

func (*Store) Available

func (s *Store) Available() bool

Available reports whether refresh tokens can be sealed, and therefore whether IdP-side revocation is armed on this hub.

func (*Store) CountSealedByKey

func (s *Store) CountSealedByKey() (map[string]int, error)

CountSealedByKey groups sessions holding a refresh token by sealing key.

func (*Store) Delete

func (s *Store) Delete(id string) (bool, error)

func (*Store) DeleteBySubject

func (s *Store) DeleteBySubject(subject, keepID string) ([]oidcauth.SessionRecord, error)

func (*Store) DeleteExpired

func (s *Store) DeleteExpired(absoluteCutoff, idleCutoff time.Time) ([]oidcauth.SessionRecord, error)

func (*Store) DueForRefresh

func (s *Store) DueForRefresh(cutoff time.Time, limit int) ([]oidcauth.SessionRecord, error)

func (*Store) Get

func (s *Store) Get(id string) (oidcauth.SessionRecord, error)

Get returns one session, translating the storage sentinel into the one oidcauth understands.

func (*Store) List

func (s *Store) List() ([]oidcauth.SessionRecord, error)

func (*Store) ListSealedNotUnder

func (s *Store) ListSealedNotUnder(keyID string, limit int) ([]secretbroker.SealedRow, error)

ListSealedNotUnder returns sessions whose refresh token is sealed under some other key. A session's associated data is its own ID, matching what seal bound it with.

func (*Store) Put

func (s *Store) Put(rec oidcauth.SessionRecord) error

Put writes a new session.

func (*Store) ReplaceSealed

func (s *Store) ReplaceSealed(id string, expect, next secretbroker.Envelope) (bool, error)

ReplaceSealed swaps a session's sealed refresh token under compare-and-swap.

func (*Store) SealedSetName

func (s *Store) SealedSetName() string

SealedSetName identifies sessions in rotation reports and namespaces every sealed refresh token's associated data.

func (*Store) Touch

func (s *Store) Touch(id string, t time.Time) error

func (*Store) WithKeyring

func (s *Store) WithKeyring(kr *secretbroker.Keyring) *Store

WithKeyring reuses an already-opened keyring instead of deriving one.

Key derivation is 200 000 SHA-256 rounds per KEK. A hub that opens the broker and the session store separately pays it twice at every start for no benefit, and the two would silently diverge if one were opened before a rotation and the other after.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL