Module: Parse::AtlasSearch::Session

Defined in:
lib/parse/atlas_search/session.rb

Overview

Resolves session tokens to user identities and inherited role sets for ACL-scoped Atlas Search queries.

Atlas Search runs aggregations directly against MongoDB and therefore bypasses Parse Server's per-request ACL enforcement. To compile a +_rperm+ +$match+ stage (see Parse::ACL.read_predicate) the caller needs to know two things about the requesting session:

  1. The +_User.objectId+ that owns the session.
  2. The transitive upward closure of role names that user inherits permissions from (cf. Role.all_for_user).

Both lookups can be expensive — token → user requires a +/users/me+ round-trip, and user → roles can require multiple +_Role+ queries to walk the inheritance graph. Both are cached separately so a single agent turn that runs several Atlas Search tools amortizes the cost.

Two distinct caches:

  • +session_cache+: maps +session_token+ to +user_id+. Long TTL (1 hour default), invalidation profile is logout. Apps that need sub-TTL revocation must call Session.invalidate explicitly from their logout path.

  • +role_cache+: maps +user_id+ to a +Set+ of role names. Short TTL (2 minutes default), invalidation profile is role-graph mutation. Stale role data here yields incorrect ACL decisions, so the default is conservatively short.

The default cache implementation is process-local (MemoryCache) and guarded by a +Mutex+. Apps that need shared cross-process caching (Redis, Memcached) may install a replacement via session_cache= / role_cache=; the replacement must respond to +get(key)+, +set(key, value, ttl:)+, and +invalidate(key)+.

Defined Under Namespace

Classes: InvalidSession, MemoryCache, Resolved

Class Method Summary collapse

Class Method Details

.invalidate(session_token) ⇒ Object

Forget a +session_token+ entry from the session-token cache. Apps that revoke sessions out-of-band (logout, password reset, admin revoke) should call this from the same path so subsequent Atlas Search requests don't act on the stale +user_id+ mapping. The +role_names+ cache is keyed on +user_id+ and is not affected — call invalidate_user_roles to clear that separately.

Parameters:



161
162
163
164
# File 'lib/parse/atlas_search/session.rb', line 161

def invalidate(session_token)
  return if session_token.nil?
  Parse::AtlasSearch.session_cache.invalidate(session_token.to_s)
end

.invalidate_user_roles(user_id) ⇒ Object

Forget cached role membership for a +user_id+. Call after any +_Role.users+ mutation that affects this user (role grant / revoke, role-graph reshape).

Parameters:



170
171
172
173
# File 'lib/parse/atlas_search/session.rb', line 170

def invalidate_user_roles(user_id)
  return if user_id.nil?
  Parse::AtlasSearch.role_cache.invalidate(user_id.to_s)
end

.reset_caches!Object

Drop every cached entry across both caches. Useful in tests and in startup hooks for processes that fork after warming the cache.



178
179
180
181
# File 'lib/parse/atlas_search/session.rb', line 178

def reset_caches!
  Parse::AtlasSearch.session_cache.clear if Parse::AtlasSearch.session_cache.respond_to?(:clear)
  Parse::AtlasSearch.role_cache.clear if Parse::AtlasSearch.role_cache.respond_to?(:clear)
end

.resolve(session_token) ⇒ Resolved

Resolve a +session_token+ to the requesting user and the transitive set of role names whose +role:NAME+ permission strings should be checked against +_rperm+.

+nil+ or empty +session_token+ → anonymous Resolved with +user_id: nil+ and an empty +role_names+ set. The caller decides whether to refuse the request (the +require_session_token+ toggle on Parse::AtlasSearch) or treat as public-only.

Cache layering: token-to-user_id is checked first; on hit the slower +/users/me+ round-trip is skipped. User-to-roles is then checked independently (a single user shared across sessions amortizes the role lookup).

Parameters:

  • session_token (String, nil)

    the +X-Parse-Session-Token+ value from the requesting session.

Returns:

Raises:

  • (InvalidSession)

    when the token cannot be resolved by +/users/me+ (404 / 209 invalid session token / 401).



145
146
147
148
149
150
151
# File 'lib/parse/atlas_search/session.rb', line 145

def resolve(session_token)
  return Resolved.new(nil, Set.new) if session_token.nil? || session_token.to_s.empty?

  user_id = lookup_user_id(session_token.to_s)
  role_names = lookup_role_names(user_id)
  Resolved.new(user_id, role_names)
end