jwt_auth_cognito 1.0.0.pre.beta.11 → 1.0.0.pre.beta.13
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/CLAUDE.md +1 -0
- data/README.md +25 -0
- data/jwt_auth_cognito.gemspec +1 -0
- data/lib/jwt_auth_cognito/authorization_concern.rb +28 -0
- data/lib/jwt_auth_cognito/cognito_identity_service.rb +81 -0
- data/lib/jwt_auth_cognito/configuration.rb +8 -1
- data/lib/jwt_auth_cognito/jwt_validator.rb +45 -0
- data/lib/jwt_auth_cognito/user_data_service.rb +29 -0
- data/lib/jwt_auth_cognito/version.rb +1 -1
- data/lib/jwt_auth_cognito.rb +4 -1
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 21369d98a11f9f2dc8a1539f4f4db6071822ae94901f15e0c4eb3496d4d74585
|
|
4
|
+
data.tar.gz: 7bcdd497bcb3ebb395a43ccb54c803efb525e739d1425670f488f675bb4d4d86
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2d68c23981b7efd4d919bda74cc2f67f15326b46d27a02103daf04bba9f76ed3de9c9b7b07de4d30d36a6a78660e9d07ac73d272767e76e765b2a8900a29d153
|
|
7
|
+
data.tar.gz: d50fc1f4f3fe447543cf0f7dfeff79de88082ec0d5aecf9cd602654349387a50100e6e7c4e8adcbfeb8af2f6962e060bac06d8a38a9b5362314e0e623351f241
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.0-beta.13] - 2026-06-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Cognito identity enrichment** (populate `payload['email']` on ACCESS tokens):
|
|
15
|
+
- Cognito **access tokens do not carry `email`** (only ID tokens do). New opt-in
|
|
16
|
+
enrichment fetches the user's standard identity attributes via Cognito `GetUser`
|
|
17
|
+
— authorized by the access token's own `aws.cognito.signin.user.admin` scope, so
|
|
18
|
+
**no AWS IAM credentials are required** — and merges them into the decoded payload.
|
|
19
|
+
- Enable with `config.enable_user_identity_enrichment = true` (env
|
|
20
|
+
`ENABLE_USER_IDENTITY_ENRICHMENT=true`), or pass
|
|
21
|
+
`enable_user_identity_enrichment: true` to `create_cognito_validator`.
|
|
22
|
+
- Runs only for `token_use == 'access'` tokens that don't already have `email`,
|
|
23
|
+
and only when `enrich_user_data` is requested (default in `validate`).
|
|
24
|
+
- Results are cached per `sub` (default 300s, `IDENTITY_CACHE_TIMEOUT`). Any failure
|
|
25
|
+
is non-fatal: the token still validates, just without identity enrichment.
|
|
26
|
+
- Default merged attributes: `email`, `email_verified`, `name`, `given_name`,
|
|
27
|
+
`family_name`, `phone_number`, `phone_number_verified`, `preferred_username`
|
|
28
|
+
(`*_verified` normalized to boolean). `custom:*` attributes are NOT merged.
|
|
29
|
+
- New `JwtAuthCognito::CognitoIdentityService` class.
|
|
30
|
+
- New dependency: `aws-sdk-cognitoidentityprovider`.
|
|
31
|
+
|
|
10
32
|
## [1.0.0-beta.11] - 2025-01-23
|
|
11
33
|
|
|
12
34
|
### Improved
|
data/CLAUDE.md
CHANGED
|
@@ -69,6 +69,7 @@ rake jwt_auth_cognito:test_cognito # Test Cognito connection
|
|
|
69
69
|
- **RedisService**: Low-level Redis operations with comprehensive TLS support and retry logic
|
|
70
70
|
- **TokenBlacklistService**: High-level token revocation and blacklist management
|
|
71
71
|
- **UserDataService**: User data retrieval from Redis with caching and auth-service compatibility
|
|
72
|
+
- **CognitoIdentityService**: Fetches identity attributes (email, name, ...) via Cognito `GetUser` to enrich ACCESS tokens, which don't carry `email`. `GetUser` is authorized by the access token's own `aws.cognito.signin.user.admin` scope — **no AWS IAM credentials required**. Opt-in via `enable_user_identity_enrichment`; merges into `payload` in `validate` only for `token_use == 'access'` tokens missing `email` when `enrich_user_data` is on; per-`sub` cache (default 300s); failures are non-fatal; `custom:*` excluded; `*_verified` normalized to boolean. Dependency: `aws-sdk-cognitoidentityprovider`.
|
|
72
73
|
- **ApiKeyValidator**: API key validation with system and app-level access control
|
|
73
74
|
- **ErrorUtils**: Centralized error handling and categorization system
|
|
74
75
|
- **SSMService**: AWS Parameter Store integration for secure certificate management (auth-service compatible)
|
data/README.md
CHANGED
|
@@ -102,6 +102,8 @@ AWS_SSM_ENDPOINT=https://ssm.us-east-1.amazonaws.com # Opcional, para VPC endpo
|
|
|
102
102
|
# Habilitar funcionalidades específicas
|
|
103
103
|
ENABLE_API_KEY_VALIDATION=true # Validación de API keys
|
|
104
104
|
ENABLE_USER_DATA_RETRIEVAL=true # Enriquecimiento de datos de usuario
|
|
105
|
+
ENABLE_USER_IDENTITY_ENRICHMENT=true # Enriquecimiento de identidad (email en access tokens)
|
|
106
|
+
IDENTITY_CACHE_TIMEOUT=300 # TTL de caché de identidad por sub (segundos)
|
|
105
107
|
```
|
|
106
108
|
|
|
107
109
|
### Opciones de Configuración Boolean
|
|
@@ -110,9 +112,32 @@ La gema soporta las siguientes opciones boolean para habilitar funcionalidades e
|
|
|
110
112
|
|
|
111
113
|
- **`enable_api_key_validation`** - Habilita la validación de API keys para control de acceso a nivel de sistema y aplicación (default: false)
|
|
112
114
|
- **`enable_user_data_retrieval`** - Habilita el enriquecimiento de datos de usuario con permisos, organizaciones y aplicaciones (default: false)
|
|
115
|
+
- **`enable_user_identity_enrichment`** - Habilita el enriquecimiento de identidad: pobla `payload['email']` (y otros atributos estándar) en **access tokens** vía Cognito `GetUser` (default: false)
|
|
113
116
|
|
|
114
117
|
Estas opciones permiten control granular sobre qué características están activas, optimizando el rendimiento habilitando solo la funcionalidad necesaria.
|
|
115
118
|
|
|
119
|
+
### Enriquecimiento de Identidad — `email` en Access Tokens
|
|
120
|
+
|
|
121
|
+
Los **access tokens de Cognito NO incluyen `email`** (solo los ID tokens lo traen). Si tu backend valida el access token y necesita el email (p. ej. para trazabilidad/logging), habilita `enable_user_identity_enrichment`. La gema obtiene los atributos del usuario con `GetUser` —autorizado por el propio scope `aws.cognito.signin.user.admin` del access token, **sin credenciales AWS IAM**— y los fusiona en el `payload`.
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
JwtAuthCognito.configure do |config|
|
|
125
|
+
config.cognito_region = 'us-east-1'
|
|
126
|
+
config.enable_user_identity_enrichment = true
|
|
127
|
+
config.identity_cache_timeout = 300 # TTL de caché por sub (segundos)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
result = validator.validate(access_token, api_key: api_key, enrich_user_data: true)
|
|
131
|
+
result[:payload]['email'] # ✅ ahora disponible
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Comportamiento:**
|
|
135
|
+
- Solo actúa sobre tokens `token_use == 'access'` que aún no traen `email`. Los ID tokens se omiten (ya lo traen).
|
|
136
|
+
- Solo se ejecuta cuando `enrich_user_data` está activo (default en `validate`).
|
|
137
|
+
- Resultados cacheados por `sub` (default 300s) para no llamar a Cognito en cada request.
|
|
138
|
+
- Tolerante a fallos: si `GetUser` falla, el token sigue siendo válido (solo no se enriquece).
|
|
139
|
+
- Los `*_verified` se normalizan a boolean. Los atributos `custom:*` **no** se fusionan.
|
|
140
|
+
|
|
116
141
|
## Configuración AWS para Development
|
|
117
142
|
|
|
118
143
|
### Desarrollo Local
|
data/jwt_auth_cognito.gemspec
CHANGED
|
@@ -42,6 +42,7 @@ Gem::Specification.new do |spec|
|
|
|
42
42
|
spec.extra_rdoc_files = ['README.md', 'CHANGELOG.md', 'LICENSE.txt']
|
|
43
43
|
|
|
44
44
|
# Dependencies - compatible with llegando-neo (Ruby 2.7.5, Rails 5.2.6)
|
|
45
|
+
spec.add_dependency 'aws-sdk-cognitoidentityprovider', '~> 1.0' # For GetUser identity enrichment
|
|
45
46
|
spec.add_dependency 'aws-sdk-ssm', '~> 1.0' # For AWS Parameter Store support
|
|
46
47
|
spec.add_dependency 'json', '~> 2.0'
|
|
47
48
|
spec.add_dependency 'jwt', '~> 2.0'
|
|
@@ -59,6 +59,24 @@ module JwtAuthCognito
|
|
|
59
59
|
@current_user_permissions ||= fetch_current_user_permissions
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
# Raises ForbiddenError unless the user has the given permission over a specific resource.
|
|
63
|
+
# By convention reads the resource ID from params[:id]; override with resource_id: keyword arg.
|
|
64
|
+
#
|
|
65
|
+
# before_action -> { authorize_resource_permission!('fleet:vehicles:write') }, only: [:update]
|
|
66
|
+
# before_action -> { authorize_resource_permission!('fleet:vehicles:write', resource_id: params[:vehicle_id]) }
|
|
67
|
+
def authorize_resource_permission!(permission, resource_id: params[:id])
|
|
68
|
+
uid = jwt_user_id
|
|
69
|
+
aid = jwt_app_id
|
|
70
|
+
oid = jwt_org_id
|
|
71
|
+
|
|
72
|
+
raise JwtAuthCognito::ForbiddenError, 'Access denied' unless uid && aid && oid && resource_id
|
|
73
|
+
|
|
74
|
+
return if jwt_validator.check_resource_permission?(uid, aid, oid, resource_id.to_s, permission)
|
|
75
|
+
|
|
76
|
+
log_resource_permission_denied(permission, resource_id)
|
|
77
|
+
raise JwtAuthCognito::ForbiddenError, 'Access denied'
|
|
78
|
+
end
|
|
79
|
+
|
|
62
80
|
private
|
|
63
81
|
|
|
64
82
|
def fetch_current_user_permissions
|
|
@@ -114,5 +132,15 @@ module JwtAuthCognito
|
|
|
114
132
|
"app_id=#{jwt_app_id} org_id=#{jwt_org_id}"
|
|
115
133
|
)
|
|
116
134
|
end
|
|
135
|
+
|
|
136
|
+
def log_resource_permission_denied(permission, resource_id)
|
|
137
|
+
return unless defined?(Rails)
|
|
138
|
+
|
|
139
|
+
Rails.logger.warn(
|
|
140
|
+
"[RESOURCE_PERMISSION_DENIED] user_id=#{jwt_user_id} " \
|
|
141
|
+
"permission=#{permission} resource_id=#{resource_id} " \
|
|
142
|
+
"app_id=#{jwt_app_id} org_id=#{jwt_org_id}"
|
|
143
|
+
)
|
|
144
|
+
end
|
|
117
145
|
end
|
|
118
146
|
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'aws-sdk-cognitoidentityprovider'
|
|
4
|
+
|
|
5
|
+
module JwtAuthCognito
|
|
6
|
+
# Fetches a user's Cognito identity attributes (email, name, ...) using the
|
|
7
|
+
# caller's OWN access token. Cognito access tokens do not carry `email`; only
|
|
8
|
+
# ID tokens do. The access token scope `aws.cognito.signin.user.admin`
|
|
9
|
+
# authorizes the GetUser operation, so NO AWS IAM credentials are required —
|
|
10
|
+
# the token itself is the authorization.
|
|
11
|
+
#
|
|
12
|
+
# Results are cached per-user (sub) so we don't hit Cognito on every single
|
|
13
|
+
# validation. Any failure returns nil (never raises) so token validation is
|
|
14
|
+
# never blocked by an identity-enrichment problem.
|
|
15
|
+
class CognitoIdentityService
|
|
16
|
+
# Curated STANDARD identity attributes merged into the decoded token.
|
|
17
|
+
# Intentionally excludes custom:* attributes to avoid leaking arbitrary data.
|
|
18
|
+
DEFAULT_IDENTITY_ATTRIBUTES = %w[
|
|
19
|
+
email email_verified name given_name family_name
|
|
20
|
+
phone_number phone_number_verified preferred_username
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
def initialize(config = JwtAuthCognito.configuration)
|
|
24
|
+
@region = config.cognito_region
|
|
25
|
+
@cache_ttl = config.identity_cache_timeout || 300
|
|
26
|
+
configured = config.identity_attributes
|
|
27
|
+
@attributes = configured && !configured.empty? ? configured : DEFAULT_IDENTITY_ATTRIBUTES
|
|
28
|
+
@cache = {}
|
|
29
|
+
@mutex = Mutex.new
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns a hash of identity attribute name => value for the user owning the
|
|
33
|
+
# access token, or nil on any failure (never raises).
|
|
34
|
+
def get_identity_attributes(access_token, sub = nil)
|
|
35
|
+
cache_key = sub || "token:#{access_token[-24..] || access_token}"
|
|
36
|
+
|
|
37
|
+
cached = read_cache(cache_key)
|
|
38
|
+
return cached if cached
|
|
39
|
+
|
|
40
|
+
response = client.get_user(access_token: access_token)
|
|
41
|
+
|
|
42
|
+
all = {}
|
|
43
|
+
response.user_attributes.each { |attr| all[attr.name] = attr.value }
|
|
44
|
+
|
|
45
|
+
filtered = {}
|
|
46
|
+
@attributes.each { |name| filtered[name] = all[name] if all.key?(name) }
|
|
47
|
+
|
|
48
|
+
write_cache(cache_key, filtered)
|
|
49
|
+
filtered
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
ErrorUtils.log_error(e, 'CognitoIdentityService.get_identity_attributes failed')
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def clear_cache
|
|
56
|
+
@mutex.synchronize { @cache = {} }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def client
|
|
62
|
+
@client ||= Aws::CognitoIdentityProvider::Client.new(region: @region)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def read_cache(key)
|
|
66
|
+
@mutex.synchronize do
|
|
67
|
+
entry = @cache[key]
|
|
68
|
+
next nil unless entry
|
|
69
|
+
next nil if entry[:expires_at] < Time.now.to_i
|
|
70
|
+
|
|
71
|
+
entry[:value]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def write_cache(key, value)
|
|
76
|
+
@mutex.synchronize do
|
|
77
|
+
@cache[key] = { value: value, expires_at: Time.now.to_i + @cache_ttl }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -7,7 +7,8 @@ module JwtAuthCognito
|
|
|
7
7
|
:redis_ssl, :redis_timeout, :redis_connect_timeout, :redis_read_timeout,
|
|
8
8
|
:redis_ca_cert_path, :redis_ca_cert_name, :redis_verify_mode,
|
|
9
9
|
:jwks_cache_ttl, :validation_mode, :environment,
|
|
10
|
-
:enable_api_key_validation, :enable_user_data_retrieval
|
|
10
|
+
:enable_api_key_validation, :enable_user_data_retrieval,
|
|
11
|
+
:enable_user_identity_enrichment, :identity_cache_timeout, :identity_attributes
|
|
11
12
|
|
|
12
13
|
def initialize
|
|
13
14
|
@cognito_region = ENV['COGNITO_REGION'] || ENV['AWS_REGION'] || 'us-east-1'
|
|
@@ -35,6 +36,12 @@ module JwtAuthCognito
|
|
|
35
36
|
@validation_mode = production? ? :secure : :basic
|
|
36
37
|
@enable_api_key_validation = ENV['ENABLE_API_KEY_VALIDATION'] == 'true'
|
|
37
38
|
@enable_user_data_retrieval = ENV['ENABLE_USER_DATA_RETRIEVAL'] == 'true'
|
|
39
|
+
|
|
40
|
+
# Cognito identity enrichment: populate payload['email'] (and other identity
|
|
41
|
+
# attributes) for ACCESS tokens via GetUser, since access tokens don't carry them.
|
|
42
|
+
@enable_user_identity_enrichment = ENV['ENABLE_USER_IDENTITY_ENRICHMENT'] == 'true'
|
|
43
|
+
@identity_cache_timeout = (ENV['IDENTITY_CACHE_TIMEOUT'] || 300).to_i
|
|
44
|
+
@identity_attributes = nil
|
|
38
45
|
end
|
|
39
46
|
|
|
40
47
|
def production?
|
|
@@ -10,6 +10,7 @@ module JwtAuthCognito
|
|
|
10
10
|
@blacklist_service = TokenBlacklistService.new(config)
|
|
11
11
|
@api_key_validator = config.enable_api_key_validation ? ApiKeyValidator.new(config) : nil
|
|
12
12
|
@user_data_service = config.enable_user_data_retrieval ? UserDataService.new(nil, config.user_data_config) : nil
|
|
13
|
+
@cognito_identity_service = config.enable_user_identity_enrichment ? CognitoIdentityService.new(config) : nil
|
|
13
14
|
@initialized = false
|
|
14
15
|
end
|
|
15
16
|
|
|
@@ -94,6 +95,18 @@ module JwtAuthCognito
|
|
|
94
95
|
end
|
|
95
96
|
end
|
|
96
97
|
|
|
98
|
+
# Step 6: Enrich token claims with Cognito identity attributes (email, name, ...)
|
|
99
|
+
# Cognito ACCESS tokens do NOT carry email (only ID tokens do). Fetch the user's
|
|
100
|
+
# attributes via GetUser (authorized by the access token's own scope) and merge
|
|
101
|
+
# them into the payload so consumers get payload['email'] transparently.
|
|
102
|
+
if enrich_user_data && @config.enable_user_identity_enrichment && @cognito_identity_service
|
|
103
|
+
payload = enriched_result[:payload]
|
|
104
|
+
if payload && payload['token_use'] == 'access' && payload['email'].nil?
|
|
105
|
+
attrs = @cognito_identity_service.get_identity_attributes(token, payload['sub'])
|
|
106
|
+
apply_identity_attributes(payload, attrs) if attrs
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
97
110
|
enriched_result
|
|
98
111
|
end
|
|
99
112
|
|
|
@@ -270,6 +283,28 @@ module JwtAuthCognito
|
|
|
270
283
|
@user_data_service.resolve_effective_permissions(user_id, app_id, org_id)
|
|
271
284
|
end
|
|
272
285
|
|
|
286
|
+
# Get the permissions the user has over a specific resource instance (ReBAC).
|
|
287
|
+
# Returns { resource_type:, resource_id:, permissions:, mode: } or nil.
|
|
288
|
+
def get_resource_permissions(user_id, app_id, org_id, resource_type, resource_id)
|
|
289
|
+
return nil unless @user_data_service
|
|
290
|
+
|
|
291
|
+
result = @user_data_service.resolve_resource_permissions(user_id, app_id, org_id, resource_id)
|
|
292
|
+
return nil unless result
|
|
293
|
+
|
|
294
|
+
{ resource_type: resource_type, resource_id: resource_id,
|
|
295
|
+
permissions: result[:permissions], mode: result[:mode] }
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Verify if the user has a specific permission over a concrete resource instance.
|
|
299
|
+
def check_resource_permission?(user_id, app_id, org_id, resource_id, permission)
|
|
300
|
+
return false unless @user_data_service
|
|
301
|
+
|
|
302
|
+
result = @user_data_service.resolve_resource_permissions(user_id, app_id, org_id, resource_id)
|
|
303
|
+
return false unless result
|
|
304
|
+
|
|
305
|
+
PermissionChecker.permission_in_list?(permission, result[:permissions])
|
|
306
|
+
end
|
|
307
|
+
|
|
273
308
|
def is_token_expired?(token)
|
|
274
309
|
payload = decode_token(token)
|
|
275
310
|
return true if payload.is_a?(Hash) && payload[:error]
|
|
@@ -423,5 +458,15 @@ module JwtAuthCognito
|
|
|
423
458
|
{ valid: true } # Continue with basic validation if user data service fails
|
|
424
459
|
end
|
|
425
460
|
end
|
|
461
|
+
|
|
462
|
+
# Merge fetched Cognito identity attributes into the decoded payload without
|
|
463
|
+
# overriding existing claims. `*_verified` attributes are normalized to booleans.
|
|
464
|
+
def apply_identity_attributes(payload, attrs)
|
|
465
|
+
attrs.each do |name, value|
|
|
466
|
+
next unless payload[name].nil?
|
|
467
|
+
|
|
468
|
+
payload[name] = name.end_with?('_verified') ? value == 'true' : value
|
|
469
|
+
end
|
|
470
|
+
end
|
|
426
471
|
end
|
|
427
472
|
end
|
|
@@ -372,6 +372,35 @@ module JwtAuthCognito
|
|
|
372
372
|
@cache_timestamps[key] = Time.now.to_i
|
|
373
373
|
end
|
|
374
374
|
|
|
375
|
+
# Resolve permissions the user has over a specific resource instance (ReBAC).
|
|
376
|
+
# Applies resourceRestrictions per-permission: open mode if none configured.
|
|
377
|
+
# Returns nil if the user has no active membership in that org.
|
|
378
|
+
def resolve_resource_permissions(user_id, app_id, organization_id, resource_id)
|
|
379
|
+
effective = resolve_effective_permissions(user_id, app_id, organization_id)
|
|
380
|
+
return nil unless effective
|
|
381
|
+
|
|
382
|
+
raw = @redis_service.get("user:permissions:#{user_id}")
|
|
383
|
+
return nil unless raw
|
|
384
|
+
|
|
385
|
+
data = JSON.parse(raw)
|
|
386
|
+
restrictions = data.dig('permissions', app_id, organization_id, 'resourceRestrictions')
|
|
387
|
+
has_any_restriction = restrictions.is_a?(Hash) && !restrictions.empty?
|
|
388
|
+
mode = has_any_restriction ? 'restricted' : 'open'
|
|
389
|
+
|
|
390
|
+
allowed = effective.select do |perm|
|
|
391
|
+
if !restrictions.is_a?(Hash) || !restrictions.key?(perm)
|
|
392
|
+
true
|
|
393
|
+
else
|
|
394
|
+
restrictions[perm].is_a?(Array) && restrictions[perm].include?(resource_id)
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
{ permissions: allowed, mode: mode }
|
|
399
|
+
rescue StandardError => e
|
|
400
|
+
puts "Error resolving resource permissions for #{user_id}:#{resource_id}: #{e.message}"
|
|
401
|
+
nil
|
|
402
|
+
end
|
|
403
|
+
|
|
375
404
|
def compute_permissions_from_roles(app_id, organization_id, role_names)
|
|
376
405
|
roles_data = get_app_roles(app_id, organization_id)
|
|
377
406
|
return [] unless roles_data.is_a?(Hash)
|
data/lib/jwt_auth_cognito.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative 'jwt_auth_cognito/redis_service'
|
|
|
8
8
|
require_relative 'jwt_auth_cognito/token_blacklist_service'
|
|
9
9
|
require_relative 'jwt_auth_cognito/api_key_validator'
|
|
10
10
|
require_relative 'jwt_auth_cognito/user_data_service'
|
|
11
|
+
require_relative 'jwt_auth_cognito/cognito_identity_service'
|
|
11
12
|
require_relative 'jwt_auth_cognito/error_utils'
|
|
12
13
|
require_relative 'jwt_auth_cognito/permission_checker'
|
|
13
14
|
require_relative 'jwt_auth_cognito/jwt_validator'
|
|
@@ -42,7 +43,8 @@ module JwtAuthCognito
|
|
|
42
43
|
|
|
43
44
|
# Convenience factory method to create a Cognito validator
|
|
44
45
|
def self.create_cognito_validator(region:, user_pool_id:, client_id: nil, client_secret: nil, redis_config: {},
|
|
45
|
-
enable_api_key_validation: false, enable_user_data_retrieval: false
|
|
46
|
+
enable_api_key_validation: false, enable_user_data_retrieval: false,
|
|
47
|
+
enable_user_identity_enrichment: false)
|
|
46
48
|
old_config = configuration.dup
|
|
47
49
|
|
|
48
50
|
configure do |config|
|
|
@@ -52,6 +54,7 @@ module JwtAuthCognito
|
|
|
52
54
|
config.cognito_client_secret = client_secret if client_secret
|
|
53
55
|
config.enable_api_key_validation = enable_api_key_validation
|
|
54
56
|
config.enable_user_data_retrieval = enable_user_data_retrieval
|
|
57
|
+
config.enable_user_identity_enrichment = enable_user_identity_enrichment
|
|
55
58
|
|
|
56
59
|
# Apply Redis configuration
|
|
57
60
|
config.redis_host = redis_config[:host] if redis_config[:host]
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jwt_auth_cognito
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.0.pre.beta.
|
|
4
|
+
version: 1.0.0.pre.beta.13
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- The Optimal
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: aws-sdk-cognitoidentityprovider
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.0'
|
|
13
27
|
- !ruby/object:Gem::Dependency
|
|
14
28
|
name: aws-sdk-ssm
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -190,6 +204,7 @@ files:
|
|
|
190
204
|
- lib/jwt_auth_cognito.rb
|
|
191
205
|
- lib/jwt_auth_cognito/api_key_validator.rb
|
|
192
206
|
- lib/jwt_auth_cognito/authorization_concern.rb
|
|
207
|
+
- lib/jwt_auth_cognito/cognito_identity_service.rb
|
|
193
208
|
- lib/jwt_auth_cognito/configuration.rb
|
|
194
209
|
- lib/jwt_auth_cognito/error_utils.rb
|
|
195
210
|
- lib/jwt_auth_cognito/jwks_service.rb
|