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 ¶
- type Store
- func (s *Store) ApplyRefresh(id string, res oidcauth.RefreshResult) error
- func (s *Store) Available() bool
- func (s *Store) CountSealedByKey() (map[string]int, error)
- func (s *Store) Delete(id string) (bool, error)
- func (s *Store) DeleteBySubject(subject, keepID string) ([]oidcauth.SessionRecord, error)
- func (s *Store) DeleteExpired(absoluteCutoff, idleCutoff time.Time) ([]oidcauth.SessionRecord, error)
- func (s *Store) DueForRefresh(cutoff time.Time, limit int) ([]oidcauth.SessionRecord, error)
- func (s *Store) Get(id string) (oidcauth.SessionRecord, error)
- func (s *Store) List() ([]oidcauth.SessionRecord, error)
- func (s *Store) ListSealedNotUnder(keyID string, limit int) ([]secretbroker.SealedRow, error)
- func (s *Store) Put(rec oidcauth.SessionRecord) error
- func (s *Store) ReplaceSealed(id string, expect, next secretbroker.Envelope) (bool, error)
- func (s *Store) SealedSetName() string
- func (s *Store) Touch(id string, t time.Time) error
- func (s *Store) WithKeyring(kr *secretbroker.Keyring) *Store
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 ¶
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 ¶
Available reports whether refresh tokens can be sealed, and therefore whether IdP-side revocation is armed on this hub.
func (*Store) CountSealedByKey ¶
CountSealedByKey groups sessions holding a refresh token by sealing key.
func (*Store) DeleteBySubject ¶
func (s *Store) DeleteBySubject(subject, keepID string) ([]oidcauth.SessionRecord, error)
func (*Store) DeleteExpired ¶
func (*Store) DueForRefresh ¶
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) ListSealedNotUnder ¶
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) ReplaceSealed ¶
ReplaceSealed swaps a session's sealed refresh token under compare-and-swap.
func (*Store) SealedSetName ¶
SealedSetName identifies sessions in rotation reports and namespaces every sealed refresh token's associated data.
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.