rack_jwt_aegis 0.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RackJwtAegis
4
+ # Role-Based Access Control (RBAC) manager
5
+ #
6
+ # Handles authorization by checking user permissions against cached RBAC data.
7
+ # Supports both simple boolean permissions and complex permission structures.
8
+ # Uses a two-tier caching system for performance optimization.
9
+ #
10
+ # @author Ken Camajalan Demanawa
11
+ # @since 0.1.0
12
+ #
13
+ # @example Basic usage
14
+ # config = Configuration.new(jwt_secret: 'secret', rbac_enabled: true, rbac_cache_store: :memory)
15
+ # manager = RbacManager.new(config)
16
+ # manager.authorize(request, jwt_payload)
4
17
  class RbacManager
18
+ include DebugLogger
19
+
5
20
  CACHE_TTL = 300 # 5 minutes default cache TTL
6
- LAST_UPDATE_KEY = 'last-update'
7
21
 
22
+ # Initialize the RBAC manager
23
+ #
24
+ # @param config [Configuration] the configuration instance
8
25
  def initialize(config)
9
26
  @config = config
10
27
  setup_cache_adapters
11
28
  end
12
29
 
30
+ # Authorize a request against RBAC permissions
31
+ #
32
+ # @param request [Rack::Request] the incoming request
33
+ # @param payload [Hash] the JWT payload containing user information
34
+ # @raise [AuthorizationError] if user lacks sufficient permissions
13
35
  def authorize(request, payload)
14
36
  user_id = payload[@config.payload_key(:user_id).to_s]
15
37
  raise AuthorizationError, 'User ID missing from JWT payload' if user_id.nil?
@@ -61,137 +83,355 @@ module RackJwtAegis
61
83
  end
62
84
 
63
85
  def build_permission_key(user_id, request)
64
- "#{user_id}:#{request.host}:#{request.path}:#{request.request_method}"
86
+ full_url = "#{request.host}#{request.path}"
87
+ "#{user_id}:#{full_url}:#{request.request_method.downcase}"
65
88
  end
66
89
 
67
90
  def check_cached_permission(permission_key)
68
91
  return nil unless @permission_cache
69
92
 
70
93
  begin
71
- # Get cached permission entry
72
- cached_entry = @permission_cache.read(permission_key)
73
- return nil if cached_entry.nil?
94
+ # Get the user permissions cache using new format
95
+ user_permissions = @permission_cache.read('user_permissions')
96
+ return nil if user_permissions.nil? || !user_permissions.is_a?(Hash)
97
+
98
+ # First check: If RBAC permissions were updated recently, nuke ALL cached permissions
99
+ rbac_last_update = rbac_last_update_timestamp
100
+ if rbac_last_update
101
+ current_time = Time.now.to_i
102
+ rbac_update_age = current_time - rbac_last_update
103
+
104
+ # If RBAC was updated within the TTL period, all cached permissions are invalid
105
+ if rbac_update_age <= @config.user_permissions_ttl
106
+ nuke_user_permissions_cache("RBAC permissions updated recently (#{rbac_update_age}s ago, within TTL)")
107
+ return nil
108
+ end
109
+ end
74
110
 
75
- # Check if cached entry is still valid based on last-update timestamp
76
- if cached_entry.is_a?(Hash) && cached_entry['timestamp'] && cached_entry['permission']
77
- last_update_time = last_update_timestamp
111
+ # Check if permission exists in new format: {"user_id:full_url:method" => timestamp}
112
+ cached_timestamp = user_permissions[permission_key]
113
+ return nil unless cached_timestamp.is_a?(Integer)
78
114
 
79
- return cached_entry['permission'] if last_update_time && cached_entry['timestamp'] >= last_update_time
115
+ current_time = Time.now.to_i
116
+ permission_age = current_time - cached_timestamp
80
117
 
81
- # Cached entry is stale, remove it
82
- @permission_cache.delete(permission_key)
118
+ # Second check: TTL expiration
119
+ if permission_age > @config.user_permissions_ttl
120
+ # This specific permission expired due to TTL
121
+ remove_stale_permission(permission_key,
122
+ "TTL expired (#{permission_age}s > #{@config.user_permissions_ttl}s)")
83
123
  return nil
84
-
85
124
  end
86
125
 
87
- # Invalid cached entry format
88
- @permission_cache.delete(permission_key)
89
- nil
126
+ # Permission is fresh
127
+ debug_log("Cache hit: #{permission_key} (permission age: \
128
+ #{permission_age}s, RBAC age: #{rbac_update_age || 'unknown'}s)".squeeze)
129
+ true
90
130
  rescue CacheError => e
91
131
  # Log cache error but don't fail the request
92
- warn "RbacManager cache read error: #{e.message}" if @config.debug_mode?
132
+ debug_log("RbacManager cache read error: #{e.message}", :warn)
93
133
  nil
94
134
  end
95
135
  end
96
136
 
97
137
  def check_rbac_permission(user_id, request)
98
- # Build RBAC lookup key
99
- rbac_key = build_rbac_key(user_id, request.host, request.path, request.request_method)
100
-
101
- # Check RBAC cache store for permission
102
- permission_data = @rbac_cache.read(rbac_key)
138
+ rbac_data = @rbac_cache.read('permissions')
103
139
 
104
- if permission_data.nil?
105
- # No explicit permission found - default to deny
106
- false
107
- else
108
- # Permission data found - check if it grants access
109
- case permission_data
110
- when true, 'true', 1, '1'
111
- true
112
- when false, 'false', 0, '0'
113
- false
114
- else
115
- # Complex permission data - delegate to custom logic if available
116
- evaluate_complex_permission?(permission_data, user_id, request)
117
- end
140
+ # Check if RBAC data exists and is valid
141
+ if rbac_data.is_a?(Hash) && validate_rbac_cache_format(rbac_data)
142
+ return check_rbac_format?(user_id, request, rbac_data)
118
143
  end
144
+
145
+ # No valid RBAC data found
146
+ false
119
147
  rescue CacheError => e
120
148
  # Cache error - fail secure (deny access)
121
- warn "RbacManager RBAC cache error: #{e.message}" if @config.debug_mode?
149
+ debug_log("RbacManager RBAC cache error: #{e.message}", :warn)
122
150
  false
123
151
  end
124
152
 
125
153
  def cache_permission_result(permission_key, has_permission)
126
154
  return unless @permission_cache
155
+ return unless has_permission # Only cache positive permissions
127
156
 
128
157
  begin
129
158
  current_time = Time.now.to_i
130
- cache_entry = {
131
- 'permission' => has_permission,
132
- 'timestamp' => current_time,
133
- }
134
159
 
135
- @permission_cache.write(permission_key, cache_entry, expires_in: CACHE_TTL)
160
+ # Get existing user permissions cache or create new one
161
+ user_permissions = @permission_cache.read('user_permissions') || {}
162
+
163
+ # Store permission with new format: {"user_id:full_url:method" => timestamp}
164
+ user_permissions[permission_key] = current_time
165
+
166
+ # Write back to cache
167
+ @permission_cache.write('user_permissions', user_permissions, expires_in: CACHE_TTL)
168
+
169
+ debug_log("Cached permission: #{permission_key} => #{current_time}")
136
170
  rescue CacheError => e
137
171
  # Log cache error but don't fail the request
138
- warn "RbacManager permission cache write error: #{e.message}" if @config.debug_mode?
172
+ debug_log("RbacManager permission cache write error: #{e.message}", :warn)
139
173
  end
140
174
  end
141
175
 
142
- def last_update_timestamp
143
- @rbac_cache.read(LAST_UPDATE_KEY)
144
- rescue CacheError => e
145
- warn "RbacManager last-update read error: #{e.message}" if @config.debug_mode?
146
- nil
147
- end
176
+ def check_rbac_format?(user_id, request, rbac_data)
177
+ # Extract user roles from JWT payload
178
+ user_roles = extract_user_roles_from_request(request)
179
+ if user_roles.nil? || user_roles.empty?
180
+ debug_log('RbacManager: No user roles found in request context', :warn)
181
+ return false
182
+ end
183
+
184
+ # Check permissions for each user role
185
+ rbac_data['permissions'].each do |role_permissions|
186
+ user_roles.each do |role_id|
187
+ next unless role_permissions.key?(role_id.to_s) || role_permissions.key?(role_id.to_i)
188
+
189
+ permissions = role_permissions[role_id.to_s] || role_permissions[role_id.to_i]
190
+ matched_permission = find_matching_permission(permissions, request)
191
+
192
+ next unless matched_permission
193
+
194
+ # Cache this specific permission match for faster future lookups
195
+ if @permission_cache && @config.cache_write_enabled?
196
+ cache_permission_match(user_id, request, role_id, matched_permission)
197
+ end
198
+ return true
199
+ end
200
+ end
148
201
 
149
- def build_rbac_key(user_id, host, path, method)
150
- # Standard RBAC key format as defined in architecture
151
- "#{user_id}:#{host}:#{path}:#{method}"
202
+ false
152
203
  end
153
204
 
154
- def evaluate_complex_permission?(permission_data, user_id, request)
155
- # Handle complex permission data structures
156
- case permission_data
157
- when Hash
158
- # Permission data is a hash - could contain role-based rules
159
- evaluate_hash_permission?(permission_data, user_id, request)
160
- when Array
161
- # Permission data is an array - could be list of allowed actions
162
- evaluate_array_permission?(permission_data, request.request_method)
163
- else
164
- # Unknown format - default to deny
165
- false
205
+ # Get RBAC permissions collection last_update timestamp
206
+ def rbac_last_update_timestamp
207
+ return nil unless @rbac_cache
208
+
209
+ begin
210
+ rbac_data = @rbac_cache.read('permissions')
211
+ if rbac_data.is_a?(Hash) && (rbac_data['last_update'] || rbac_data[:last_update])
212
+ return rbac_data['last_update'] || rbac_data[:last_update]
213
+ end
214
+
215
+ nil
216
+ rescue CacheError => e
217
+ debug_log("RbacManager RBAC last-update read error: #{e.message}", :warn)
218
+ nil
166
219
  end
167
220
  end
168
221
 
169
- def evaluate_hash_permission?(permission_hash, _user_id, request)
170
- # Example: {"allowed_methods": ["GET", "POST"], "roles": ["admin"]}
222
+ # Remove a specific stale permission
223
+ def remove_stale_permission(permission_key, reason)
224
+ return unless @permission_cache
225
+
226
+ begin
227
+ user_permissions = @permission_cache.read('user_permissions')
228
+ return unless user_permissions.is_a?(Hash)
229
+
230
+ # Remove the specific permission key
231
+ user_permissions.delete(permission_key)
171
232
 
172
- # Check allowed methods
173
- if permission_hash['allowed_methods']
174
- allowed_methods = Array(permission_hash['allowed_methods'])
175
- return allowed_methods.include?(request.request_method)
233
+ # If no permissions remain, remove the entire cache
234
+ if user_permissions.empty?
235
+ @permission_cache.delete('user_permissions')
236
+ debug_log("Removed last permission, cleared entire cache: #{reason}")
237
+ else
238
+ # Update the cache with the modified permissions
239
+ @permission_cache.write('user_permissions', user_permissions, expires_in: CACHE_TTL)
240
+ debug_log("Removed stale permission #{permission_key}: #{reason}")
241
+ end
242
+ rescue CacheError => e
243
+ debug_log("RbacManager stale permission removal error: #{e.message}", :warn)
176
244
  end
245
+ end
246
+
247
+ # Nuke (delete) the entire user permissions cache
248
+ def nuke_user_permissions_cache(reason)
249
+ return unless @permission_cache
177
250
 
178
- # Check roles (would need role information from JWT payload)
179
- if permission_hash['roles']
180
- # This would require additional JWT payload inspection
181
- # For now, default to allowing if roles are specified
182
- return true
251
+ begin
252
+ @permission_cache.delete('user_permissions')
253
+ debug_log("Nuked user permissions cache: #{reason}")
254
+ rescue CacheError => e
255
+ debug_log("RbacManager cache nuke error: #{e.message}", :warn)
183
256
  end
257
+ end
258
+
259
+ # Extract user roles from request context (stored by middleware)
260
+ def extract_user_roles_from_request(request)
261
+ # Check if roles are stored in request environment by middleware
262
+ request.env['rack_jwt_aegis.user_roles']
263
+ end
184
264
 
185
- # Check boolean permission field
186
- return !!permission_hash['allowed'] if permission_hash.key?('allowed')
265
+ # Check if any role permission matches the request
266
+ def check_role_permissions?(permissions, request)
267
+ return false unless permissions.is_a?(Array)
268
+
269
+ request_path = extract_api_path_from_request(request)
270
+ request_method = request.request_method.downcase
271
+
272
+ permissions.each do |permission|
273
+ return true if permission_matches?(permission, request_path, request_method)
274
+ end
187
275
 
188
- # Default deny for unknown hash structure
189
276
  false
190
277
  end
191
278
 
192
- def evaluate_array_permission?(permission_array, request_method)
193
- # Array of allowed HTTP methods
194
- permission_array.include?(request_method)
279
+ # Find the first matching permission for the request (returns the permission string or nil)
280
+ def find_matching_permission(permissions, request)
281
+ return nil unless permissions.is_a?(Array)
282
+
283
+ request_path = extract_api_path_from_request(request)
284
+ request_method = request.request_method.downcase
285
+
286
+ permissions.each do |permission|
287
+ return permission if permission_matches?(permission, request_path, request_method)
288
+ end
289
+
290
+ nil
291
+ end
292
+
293
+ # Cache the specific permission match for faster future lookups
294
+ # Format: {"user_id:full_url:method" => timestamp}
295
+ def cache_permission_match(user_id, request, _role_id, _matched_permission)
296
+ return unless @permission_cache
297
+
298
+ begin
299
+ current_time = Time.now.to_i
300
+
301
+ # Build the permission key in new format
302
+ host = request.host || 'localhost'
303
+ full_url = "#{host}#{request.path}"
304
+ method = request.request_method.downcase
305
+ permission_key = "#{user_id}:#{full_url}:#{method}"
306
+
307
+ # Get existing user permissions cache or create new one
308
+ user_permissions = @permission_cache.read('user_permissions') || {}
309
+
310
+ # Store permission with new format
311
+ user_permissions[permission_key] = current_time
312
+
313
+ # Write back to cache
314
+ @permission_cache.write('user_permissions', user_permissions, expires_in: CACHE_TTL)
315
+
316
+ debug_log("Cached user permission: #{permission_key} => #{current_time}")
317
+ rescue CacheError => e
318
+ # Log cache error but don't fail the request
319
+ debug_log("RbacManager permission cache write error: #{e.message}", :warn)
320
+ end
321
+ end
322
+
323
+ # Extract the API path portion from the full request path
324
+ # Removes subdomain and pathname slug parts to get the resource endpoint
325
+ def extract_api_path_from_request(request)
326
+ path = request.path
327
+
328
+ # Remove API prefix and pathname slug pattern if configured
329
+ if @config.pathname_slug_pattern
330
+ # Extract the resource path after the pathname slug
331
+ match = path.match(@config.pathname_slug_pattern)
332
+ if match&.captures&.any?
333
+ # Get everything after the slug pattern
334
+ slug_part = match[0]
335
+ resource_path = path.sub(slug_part, '')
336
+ return resource_path.start_with?('/') ? resource_path[1..] : resource_path
337
+ end
338
+ end
339
+
340
+ # Fallback: remove common API prefixes
341
+ path = path.sub(%r{^/api/v\d+/}, '')
342
+ path = path.sub(%r{^/api/}, '')
343
+ path.sub(%r{^/}, '')
344
+ end
345
+
346
+ # Check if a permission string matches the request
347
+ def permission_matches?(permission, resource_path, request_method)
348
+ return false unless permission.is_a?(String)
349
+
350
+ # Parse permission format: "resource-endpoint:http-method"
351
+ parts = permission.split(':')
352
+ return false unless parts.length == 2
353
+
354
+ permission_path, permission_method = parts
355
+
356
+ # Check if method matches
357
+ return false unless method_matches?(permission_method, request_method)
358
+
359
+ # Check if path matches (handle both literal and regex patterns)
360
+ path_matches?(permission_path, resource_path)
361
+ end
362
+
363
+ # Check if HTTP method matches
364
+ def method_matches?(permission_method, request_method)
365
+ permission_method = permission_method.downcase
366
+
367
+ # Wildcard method matches all
368
+ return true if permission_method == '*'
369
+
370
+ # Exact method match
371
+ permission_method == request_method
372
+ end
373
+
374
+ # Check if path matches (handles both literal strings and regex patterns)
375
+ def path_matches?(permission_path, resource_path)
376
+ # Handle regex pattern format: "%r{pattern}"
377
+ if permission_path.start_with?('%r{') && permission_path.end_with?('}')
378
+ regex_pattern = permission_path[3..-2] # Remove %r{ and }
379
+ begin
380
+ regex = Regexp.new(regex_pattern)
381
+ return regex.match?(resource_path)
382
+ rescue RegexpError => e
383
+ debug_log("RbacManager: Invalid regex pattern '#{regex_pattern}': #{e.message}", :warn)
384
+ return false
385
+ end
386
+ end
387
+
388
+ # Exact string match
389
+ permission_path == resource_path
390
+ end
391
+
392
+ # Validate RBAC cache format according to specification
393
+ # Expected format:
394
+ # {
395
+ # last_update: timestamp,
396
+ # permissions: [
397
+ # {role-id: ["{resource-endpoint}:{http-method}"]}
398
+ # ]
399
+ # }
400
+ def validate_rbac_cache_format(rbac_data)
401
+ return false unless rbac_data.is_a?(Hash)
402
+
403
+ # Check required fields
404
+ return false unless rbac_data.key?('last_update') || rbac_data.key?(:last_update)
405
+ return false unless rbac_data.key?('permissions') || rbac_data.key?(:permissions)
406
+
407
+ # Get permissions array
408
+ permissions = rbac_data['permissions'] || rbac_data[:permissions]
409
+ return false unless permissions.is_a?(Array)
410
+
411
+ # Validate each permission entry
412
+ permissions.each do |permission_entry|
413
+ return false unless permission_entry.is_a?(Hash)
414
+
415
+ # Each entry should have at least one role-id key
416
+ return false if permission_entry.empty?
417
+
418
+ # Validate permission values are arrays of strings
419
+ permission_entry.each_value do |role_permissions|
420
+ return false unless role_permissions.is_a?(Array)
421
+
422
+ # Each permission should be a string in format "endpoint:method"
423
+ role_permissions.each do |permission|
424
+ return false unless permission.is_a?(String)
425
+ # Permission must include ':' (resource:method format)
426
+ return false unless permission.include?(':')
427
+ end
428
+ end
429
+ end
430
+
431
+ true
432
+ rescue StandardError => e
433
+ debug_log("RbacManager: Cache format validation error: #{e.message}", :warn)
434
+ false
195
435
  end
196
436
  end
197
437
  end
@@ -1,19 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RackJwtAegis
4
+ # Request context manager for storing JWT authentication data in Rack env
5
+ #
6
+ # Stores authenticated user and tenant information in the Rack environment
7
+ # hash for easy access by downstream application code. Provides both
8
+ # instance methods for setting context and class methods for reading.
9
+ #
10
+ # @author Ken Camajalan Demanawa
11
+ # @since 0.1.0
12
+ #
13
+ # @example Setting context (done by middleware)
14
+ # context = RequestContext.new(config)
15
+ # context.set_context(env, jwt_payload)
16
+ #
17
+ # @example Reading context in application
18
+ # user_id = RequestContext.user_id(request.env)
19
+ # tenant_id = RequestContext.tenant_id(request.env)
20
+ # authenticated = RequestContext.authenticated?(request.env)
4
21
  class RequestContext
5
22
  # Standard environment keys for JWT data
6
23
  JWT_PAYLOAD_KEY = 'rack_jwt_aegis.payload'
7
24
  USER_ID_KEY = 'rack_jwt_aegis.user_id'
8
- COMPANY_GROUP_ID_KEY = 'rack_jwt_aegis.company_group_id'
9
- COMPANY_GROUP_DOMAIN_KEY = 'rack_jwt_aegis.company_group_domain'
10
- COMPANY_SLUGS_KEY = 'rack_jwt_aegis.company_slugs'
25
+ TENANT_ID_KEY = 'rack_jwt_aegis.tenant_id'
26
+ SUBDOMAIN_KEY = 'rack_jwt_aegis.subdomain'
27
+ PATHNAME_SLUGS_KEY = 'rack_jwt_aegis.pathname_slugs'
11
28
  AUTHENTICATED_KEY = 'rack_jwt_aegis.authenticated'
12
29
 
30
+ # Initialize the request context manager
31
+ #
32
+ # @param config [Configuration] the configuration instance
13
33
  def initialize(config)
14
34
  @config = config
15
35
  end
16
36
 
37
+ # Set JWT authentication context in the Rack environment
38
+ #
39
+ # @param env [Hash] the Rack environment hash
40
+ # @param payload [Hash] the validated JWT payload
17
41
  def set_context(env, payload)
18
42
  # Set the full payload
19
43
  env[JWT_PAYLOAD_KEY] = payload
@@ -27,40 +51,57 @@ module RackJwtAegis
27
51
  end
28
52
 
29
53
  # Class methods for easy access from application code
54
+
55
+ # Check if the request is authenticated
56
+ #
57
+ # @param env [Hash] the Rack environment hash
58
+ # @return [Boolean] true if request is authenticated
30
59
  def self.authenticated?(env)
31
60
  !!env[AUTHENTICATED_KEY]
32
61
  end
33
62
 
63
+ # Get the full JWT payload from the request
64
+ #
65
+ # @param env [Hash] the Rack environment hash
66
+ # @return [Hash, nil] the JWT payload or nil if not authenticated
34
67
  def self.payload(env)
35
68
  env[JWT_PAYLOAD_KEY]
36
69
  end
37
70
 
71
+ # Get the authenticated user ID
72
+ #
73
+ # @param env [Hash] the Rack environment hash
74
+ # @return [String, Integer, nil] the user ID or nil if not available
38
75
  def self.user_id(env)
39
76
  env[USER_ID_KEY]
40
77
  end
41
78
 
42
- def self.company_group_id(env)
43
- env[COMPANY_GROUP_ID_KEY]
79
+ # Get the tenant ID
80
+ #
81
+ # @param env [Hash] the Rack environment hash
82
+ # @return [String, Integer, nil] the tenant ID or nil if not available
83
+ def self.tenant_id(env)
84
+ env[TENANT_ID_KEY]
44
85
  end
45
86
 
46
- def self.company_group_domain(env)
47
- env[COMPANY_GROUP_DOMAIN_KEY]
87
+ def self.subdomain(env)
88
+ env[SUBDOMAIN_KEY]
48
89
  end
49
90
 
50
- def self.company_slugs(env)
51
- env[COMPANY_SLUGS_KEY] || []
91
+ def self.pathname_slugs(env)
92
+ env[PATHNAME_SLUGS_KEY] || []
52
93
  end
53
94
 
54
95
  def self.current_user_id(request)
55
96
  user_id(request.env)
56
97
  end
57
98
 
58
- def self.current_company_group_id(request)
59
- company_group_id(request.env)
99
+ def self.current_tenant_id(request)
100
+ tenant_id(request.env)
60
101
  end
61
102
 
62
103
  def self.has_company_access?(env, company_slug)
63
- company_slugs(env).include?(company_slug)
104
+ pathname_slugs(env).include?(company_slug)
64
105
  end
65
106
 
66
107
  private
@@ -74,27 +115,27 @@ module RackJwtAegis
74
115
 
75
116
  def set_tenant_context(env, payload)
76
117
  # Set company group information
77
- if @config.validate_subdomain? || @config.payload_mapping.key?(:company_group_id)
78
- company_group_id_key = @config.payload_key(:company_group_id).to_s
79
- company_group_id = payload[company_group_id_key]
80
- env[COMPANY_GROUP_ID_KEY] = company_group_id
118
+ if @config.validate_subdomain? || @config.payload_mapping.key?(:tenant_id)
119
+ tenant_id_key = @config.payload_key(:tenant_id).to_s
120
+ tenant_id = payload[tenant_id_key]
121
+ env[TENANT_ID_KEY] = tenant_id
81
122
  end
82
123
 
83
124
  if @config.validate_subdomain?
84
- company_domain_key = @config.payload_key(:company_group_domain).to_s
125
+ company_domain_key = @config.payload_key(:subdomain).to_s
85
126
  company_domain = payload[company_domain_key]
86
- env[COMPANY_GROUP_DOMAIN_KEY] = company_domain
127
+ env[SUBDOMAIN_KEY] = company_domain
87
128
  end
88
129
 
89
130
  # Set company slugs for sub-level tenant access
90
- return unless @config.validate_company_slug? || @config.payload_mapping.key?(:company_slugs)
131
+ return unless @config.validate_pathname_slug? || @config.payload_mapping.key?(:pathname_slugs)
91
132
 
92
- company_slugs_key = @config.payload_key(:company_slugs).to_s
93
- company_slugs = payload[company_slugs_key]
133
+ pathname_slugs_key = @config.payload_key(:pathname_slugs).to_s
134
+ pathname_slugs = payload[pathname_slugs_key]
94
135
 
95
136
  # Ensure it's an array
96
- company_slugs = Array(company_slugs) if company_slugs
97
- env[COMPANY_SLUGS_KEY] = company_slugs || []
137
+ pathname_slugs = Array(pathname_slugs) if pathname_slugs
138
+ env[PATHNAME_SLUGS_KEY] = pathname_slugs || []
98
139
  end
99
140
  end
100
141
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RackJwtAegis
4
- VERSION = '0.0.0'
4
+ VERSION = '1.0.1'
5
5
  end