jwt_auth_cognito 0.3.0 → 1.0.0.pre.beta.2
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 +7 -0
- data/CLAUDE.md +45 -1
- data/README.md +25 -5
- data/bitbucket-pipelines.yml +12 -5
- data/lib/jwt_auth_cognito/jwt_validator.rb +168 -19
- data/lib/jwt_auth_cognito/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9296db47172be874a7d6204b54c3e5fc8de7f77a77a7e02f4b1d8d4b70bc9b8d
|
4
|
+
data.tar.gz: 55a4df3b1c9077b9803508ac925715510af9974ef79c40ed097cc0a86eb5b7a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19b0aa21809ac6d94c74e358d48d30b4246836610eff67121f41368552a6c385696952aec47a5bb8291c9141e6e0c1de398a028679f1fb05c8a3c71904d58446
|
7
|
+
data.tar.gz: 4cff441b707184fab34cc16f8368ae67334b8aad174f28b2c1649292a7d2b0b99ad66d60920ef9d503c95a162cd01e2ae621081e0129f38f3dc11c95f40c810c
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
### Improved
|
11
|
+
|
12
|
+
- **Documentation Enhancement**: Added Redis configuration documentation to main usage patterns
|
13
|
+
- Updated README.md with complete Redis connection setup in factory method
|
14
|
+
- Enhanced CLAUDE.md with Redis configuration in the main usage pattern
|
15
|
+
- Improved clarity on how to connect Redis for token blacklisting and user data enrichment
|
16
|
+
|
10
17
|
## [0.3.0] - 2024-01-15
|
11
18
|
|
12
19
|
### Added
|
data/CLAUDE.md
CHANGED
@@ -145,6 +145,50 @@ ENV['REDIS_CA_CERT'] = "-----BEGIN CERTIFICATE-----..."
|
|
145
145
|
- **Backward Compatibility**: All functionality works without client secret configuration
|
146
146
|
- **Security Integration**: Secret hash automatically included in blacklist operations when configured
|
147
147
|
|
148
|
+
## 🚀 Main Usage Pattern with Redis Connection
|
149
|
+
|
150
|
+
### ✨ Complete Setup with Redis Connection
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
# Create validator with Redis connection for blacklist and user data
|
154
|
+
validator = JwtAuthCognito.create_cognito_validator(
|
155
|
+
region: 'us-east-1',
|
156
|
+
user_pool_id: 'us-east-1_ExamplePool',
|
157
|
+
client_id: 'your-client-id',
|
158
|
+
client_secret: 'your-client-secret', # Optional
|
159
|
+
redis_config: {
|
160
|
+
# Redis configuration for token blacklisting and user data enrichment
|
161
|
+
host: ENV['REDIS_HOST'] || 'localhost',
|
162
|
+
port: ENV['REDIS_PORT']&.to_i || 6379,
|
163
|
+
password: ENV['REDIS_PASSWORD'],
|
164
|
+
db: ENV['REDIS_DB']&.to_i || 0,
|
165
|
+
|
166
|
+
# TLS configuration for secure connections
|
167
|
+
tls: ENV['REDIS_TLS'] == 'true',
|
168
|
+
ca_cert_path: ENV['REDIS_CA_CERT_PATH'],
|
169
|
+
ca_cert_name: ENV['REDIS_CA_CERT_NAME'],
|
170
|
+
verify_mode: ENV['REDIS_VERIFY_MODE'] || 'peer'
|
171
|
+
},
|
172
|
+
enable_user_data_retrieval: true
|
173
|
+
)
|
174
|
+
|
175
|
+
# Initialize Redis connection and services
|
176
|
+
validator.initialize!
|
177
|
+
|
178
|
+
# 🌟 Main validation method with complete functionality
|
179
|
+
result = validator.validate_token_enriched(token)
|
180
|
+
|
181
|
+
if result[:valid]
|
182
|
+
puts "✅ Valid token:"
|
183
|
+
puts "User: #{result[:sub]}"
|
184
|
+
puts "Permissions: #{result[:user_permissions]}"
|
185
|
+
puts "Organizations: #{result[:user_organizations]}"
|
186
|
+
puts "Applications: #{result[:applications]}"
|
187
|
+
else
|
188
|
+
puts "❌ Invalid token: #{result[:error]}"
|
189
|
+
end
|
190
|
+
```
|
191
|
+
|
148
192
|
## Environment Configuration
|
149
193
|
|
150
194
|
The gem supports extensive environment variable configuration for deployment flexibility:
|
@@ -152,7 +196,7 @@ The gem supports extensive environment variable configuration for deployment fle
|
|
152
196
|
### AWS Cognito Configuration
|
153
197
|
```bash
|
154
198
|
COGNITO_REGION=us-east-1
|
155
|
-
COGNITO_USER_POOL_ID=us-east-1_AbCdEfGhI
|
199
|
+
COGNITO_USER_POOL_ID=us-east-1_AbCdEfGhI
|
156
200
|
COGNITO_CLIENT_ID=your-client-id
|
157
201
|
COGNITO_CLIENT_SECRET=your-client-secret # Optional for enhanced security
|
158
202
|
```
|
data/README.md
CHANGED
@@ -162,21 +162,41 @@ end
|
|
162
162
|
### Factory Method para Configuración Simplificada (Nuevo v0.3.0)
|
163
163
|
|
164
164
|
```ruby
|
165
|
-
# Crear validador con
|
165
|
+
# Crear validador con conexión Redis completa
|
166
166
|
validator = JwtAuthCognito.create_cognito_validator(
|
167
167
|
region: 'us-east-1',
|
168
168
|
user_pool_id: 'us-east-1_ExamplePool',
|
169
169
|
client_id: 'your-client-id',
|
170
170
|
redis_config: {
|
171
|
-
|
172
|
-
|
173
|
-
|
171
|
+
# Configuración básica de Redis
|
172
|
+
host: ENV['REDIS_HOST'] || 'localhost',
|
173
|
+
port: ENV['REDIS_PORT']&.to_i || 6379,
|
174
|
+
password: ENV['REDIS_PASSWORD'],
|
175
|
+
db: ENV['REDIS_DB']&.to_i || 0,
|
176
|
+
|
177
|
+
# Configuración TLS para conexiones seguras
|
178
|
+
tls: ENV['REDIS_TLS'] == 'true',
|
179
|
+
ca_cert_path: ENV['REDIS_CA_CERT_PATH'],
|
180
|
+
ca_cert_name: ENV['REDIS_CA_CERT_NAME']
|
174
181
|
},
|
175
182
|
enable_user_data_retrieval: true
|
176
183
|
)
|
177
184
|
|
178
|
-
#
|
185
|
+
# Inicializar conexiones (incluye Redis)
|
186
|
+
validator.initialize!
|
187
|
+
|
188
|
+
# Usar inmediatamente con validación enriquecida
|
179
189
|
result = validator.validate_token_enriched(token)
|
190
|
+
|
191
|
+
if result[:valid]
|
192
|
+
puts "✅ Token válido con datos enriquecidos:"
|
193
|
+
puts "Usuario: #{result[:sub]}"
|
194
|
+
puts "Permisos: #{result[:user_permissions]}"
|
195
|
+
puts "Organizaciones: #{result[:user_organizations]}"
|
196
|
+
puts "Aplicaciones: #{result[:applications]}"
|
197
|
+
else
|
198
|
+
puts "❌ Token inválido: #{result[:error]}"
|
199
|
+
end
|
180
200
|
```
|
181
201
|
|
182
202
|
### Manejo Mejorado de Errores (Nuevo v0.3.0)
|
data/bitbucket-pipelines.yml
CHANGED
@@ -125,12 +125,11 @@ pipelines:
|
|
125
125
|
# Tags stable (X.Y.Z)
|
126
126
|
"v[0-9]*.[0-9]*.[0-9]*":
|
127
127
|
- step:
|
128
|
-
name: Deploy Estable
|
129
|
-
trigger: manual # Requiere confirmación manual
|
128
|
+
name: Tests y Build para Deploy Estable
|
130
129
|
caches:
|
131
130
|
- bundler
|
132
131
|
script:
|
133
|
-
- echo "🚨
|
132
|
+
- echo "🚨 Preparando versión estable para deploy"
|
134
133
|
- bundle install
|
135
134
|
- echo "Tests completos y exhaustivos..."
|
136
135
|
- bundle exec rspec
|
@@ -140,6 +139,16 @@ pipelines:
|
|
140
139
|
- bundle audit check --update || echo "Bundle audit no disponible, continuando..."
|
141
140
|
- echo "Building gem final..."
|
142
141
|
- gem build jwt_auth_cognito.gemspec
|
142
|
+
- echo "Build completado - Listo para deploy manual"
|
143
|
+
artifacts:
|
144
|
+
- "*.gem"
|
145
|
+
- step:
|
146
|
+
name: Deploy Estable a RubyGems
|
147
|
+
trigger: manual # Requiere confirmación manual para el deploy
|
148
|
+
caches:
|
149
|
+
- bundler
|
150
|
+
script:
|
151
|
+
- echo "🚨 DEPLOY DE PRODUCCIÓN - Versión estable"
|
143
152
|
- echo "Configurando credenciales RubyGems..."
|
144
153
|
- mkdir -p ~/.gem
|
145
154
|
- 'echo ":rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials'
|
@@ -147,8 +156,6 @@ pipelines:
|
|
147
156
|
- echo "Publicando version ESTABLE a RubyGems..."
|
148
157
|
- gem push *.gem
|
149
158
|
- echo "VERSION ESTABLE PUBLICADA EXITOSAMENTE"
|
150
|
-
artifacts:
|
151
|
-
- "*.gem"
|
152
159
|
|
153
160
|
# Tags alpha (X.Y.Z-alpha.N) - Solo para testing
|
154
161
|
"v*-alpha.*":
|
@@ -27,14 +27,24 @@ module JwtAuthCognito
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
# ========== 🚀 MAIN VALIDATION METHOD ==========
|
31
|
+
|
32
|
+
# Main validation method - use this for most cases
|
33
|
+
# Intelligently validates tokens with all features:
|
34
|
+
# - JWT validation (basic or secure)
|
35
|
+
# - API key validation (if provided)
|
36
|
+
# - Blacklist checking
|
37
|
+
# - Automatic appId verification
|
38
|
+
# - User data enrichment (if enabled)
|
39
|
+
def validate(token, options = {})
|
35
40
|
@config.validate!
|
36
41
|
|
37
|
-
|
42
|
+
api_key = options[:api_key]
|
43
|
+
force_secure = options[:force_secure] || false
|
44
|
+
enrich_user_data = options.fetch(:enrich_user_data, true)
|
45
|
+
require_app_access = options[:require_app_access] || false
|
46
|
+
|
47
|
+
# Step 1: Validate API key if provided
|
38
48
|
api_key_data = nil
|
39
49
|
if api_key && @config.enable_api_key_validation && @api_key_validator
|
40
50
|
api_key_result = @api_key_validator.validate_api_key(api_key)
|
@@ -43,26 +53,129 @@ module JwtAuthCognito
|
|
43
53
|
api_key_data = api_key_result[:key_data]
|
44
54
|
end
|
45
55
|
|
46
|
-
# Check blacklist first
|
56
|
+
# Step 2: Check blacklist first
|
47
57
|
return { valid: false, error: 'Token has been revoked' } if @blacklist_service.is_blacklisted?(token)
|
48
58
|
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
59
|
+
# Step 3: Validate JWT token
|
60
|
+
validation_mode = force_secure ? :secure : @config.validation_mode
|
61
|
+
token_result = case validation_mode
|
62
|
+
when :secure
|
63
|
+
validate_token_secure(token, options)
|
64
|
+
when :basic
|
65
|
+
validate_token_basic(token, options)
|
66
|
+
else
|
67
|
+
raise ConfigurationError, "Invalid validation_mode: #{validation_mode}"
|
68
|
+
end
|
69
|
+
|
70
|
+
return token_result unless token_result[:valid] && token_result[:payload]
|
71
|
+
|
72
|
+
# Step 4: Verify appId access if API key has one
|
73
|
+
if api_key_data
|
74
|
+
app_validation = verify_app_access(api_key_data, token_result[:payload], require_app_access)
|
75
|
+
return app_validation unless app_validation[:valid]
|
76
|
+
end
|
58
77
|
|
59
|
-
#
|
60
|
-
|
78
|
+
# Step 5: Enrich with user data if requested
|
79
|
+
enriched_result = token_result.dup
|
80
|
+
enriched_result[:api_key] = api_key_data if api_key_data
|
81
|
+
|
82
|
+
if enrich_user_data && @config.enable_user_data_retrieval && @user_data_service
|
83
|
+
user_id = token_result[:payload]['sub']
|
84
|
+
if user_id
|
85
|
+
begin
|
86
|
+
user_data = @user_data_service.get_comprehensive_user_data(user_id)
|
87
|
+
enriched_result[:user_permissions] = user_data['permissions']
|
88
|
+
enriched_result[:user_organizations] = user_data['organizations']
|
89
|
+
enriched_result[:applications] = user_data['applications']
|
90
|
+
rescue StandardError => e
|
91
|
+
ErrorUtils.log_error(e, 'User data retrieval failed')
|
92
|
+
# Continue with basic validation if user data service fails
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
61
96
|
|
62
|
-
|
97
|
+
enriched_result
|
98
|
+
end
|
99
|
+
|
100
|
+
# ========== SIMPLIFIED PUBLIC API ==========
|
101
|
+
|
102
|
+
# Quick validation for simple use cases
|
103
|
+
# Just validates the JWT token (includes blacklist check)
|
104
|
+
def validate_token(token, options = {})
|
105
|
+
result = validate(token, options.merge(enrich_user_data: false))
|
106
|
+
{
|
107
|
+
valid: result[:valid],
|
108
|
+
payload: result[:payload],
|
109
|
+
sub: result[:sub],
|
110
|
+
username: result[:username],
|
111
|
+
token_use: result[:token_use],
|
112
|
+
error: result[:error]
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
# Validate with API key (automatic appId verification)
|
117
|
+
# Use this when you have an API key and want automatic security
|
118
|
+
def validate_with_api_key(token, api_key, options = {})
|
119
|
+
validate(token, options.merge(api_key: api_key))
|
120
|
+
end
|
121
|
+
|
122
|
+
# Validate with strict appId requirement
|
123
|
+
# Use this when you MUST ensure user has access to a specific app
|
124
|
+
def validate_with_app_access(token, api_key, options = {})
|
125
|
+
validate(token, options.merge(api_key: api_key, require_app_access: true))
|
126
|
+
end
|
127
|
+
|
128
|
+
# Get enriched validation (user data included)
|
129
|
+
# Use this when you need user permissions, organizations, apps
|
130
|
+
def validate_enriched(token, api_key = nil, options = {})
|
131
|
+
validate(token, options.merge(api_key: api_key, enrich_user_data: true))
|
132
|
+
end
|
133
|
+
|
134
|
+
# ========== LEGACY METHODS (DEPRECATED) ==========
|
135
|
+
|
136
|
+
# @deprecated Use validate() or validate_with_api_key() instead
|
137
|
+
def validate_token_with_api_key(token, api_key = nil, options = {})
|
138
|
+
puts 'WARNING: validate_token_with_api_key is deprecated. Use validate() or validate_with_api_key() instead.'
|
139
|
+
result = validate(token, options.merge(api_key: api_key, enrich_user_data: false))
|
140
|
+
{
|
141
|
+
valid: result[:valid],
|
142
|
+
payload: result[:payload],
|
143
|
+
sub: result[:sub],
|
144
|
+
username: result[:username],
|
145
|
+
token_use: result[:token_use],
|
146
|
+
api_key: result[:api_key],
|
147
|
+
error: result[:error]
|
148
|
+
}
|
63
149
|
end
|
64
150
|
|
151
|
+
# @deprecated Use validate_with_app_access() instead
|
152
|
+
def validate_token_with_app_id(token, api_key, options = {})
|
153
|
+
puts 'WARNING: validate_token_with_app_id is deprecated. Use validate_with_app_access() instead.'
|
154
|
+
validate_with_app_access(token, api_key, options.merge(enrich_user_data: false))
|
155
|
+
end
|
156
|
+
|
157
|
+
# @deprecated Use validate() instead
|
158
|
+
def validate_token_enhanced(token, api_key = nil, options = {})
|
159
|
+
puts 'WARNING: validate_token_enhanced is deprecated. Use validate() instead.'
|
160
|
+
result = validate(token, options.merge(api_key: api_key, enrich_user_data: false))
|
161
|
+
{
|
162
|
+
valid: result[:valid],
|
163
|
+
payload: result[:payload],
|
164
|
+
sub: result[:sub],
|
165
|
+
username: result[:username],
|
166
|
+
token_use: result[:token_use],
|
167
|
+
api_key: result[:api_key],
|
168
|
+
error: result[:error]
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
# @deprecated Use validate_enriched() instead
|
65
173
|
def validate_token_enriched(token, api_key = nil, options = {})
|
174
|
+
puts 'WARNING: validate_token_enriched is deprecated. Use validate_enriched() instead.'
|
175
|
+
validate_enriched(token, api_key, options)
|
176
|
+
end
|
177
|
+
|
178
|
+
def old_validate_token_enriched(token, api_key = nil, options = {})
|
66
179
|
# First, perform standard token validation
|
67
180
|
basic_result = validate_token_with_api_key(token, api_key, options)
|
68
181
|
|
@@ -299,5 +412,41 @@ module JwtAuthCognito
|
|
299
412
|
|
300
413
|
raise ValidationError, "Token missing required scopes: #{missing_scopes.join(', ')}"
|
301
414
|
end
|
415
|
+
|
416
|
+
def verify_app_access(api_key_data, payload, require_app_access)
|
417
|
+
app_id = api_key_data['appId'] || api_key_data['metadata']&.[]('appId')
|
418
|
+
|
419
|
+
return { valid: false, error: 'API key is not associated with an application' } if !app_id && require_app_access
|
420
|
+
|
421
|
+
return { valid: true } unless app_id
|
422
|
+
|
423
|
+
user_id = payload['sub']
|
424
|
+
return { valid: false, error: 'Token missing user ID (sub claim)' } unless user_id
|
425
|
+
|
426
|
+
verify_user_app_access(user_id, app_id, require_app_access)
|
427
|
+
end
|
428
|
+
|
429
|
+
def verify_user_app_access(user_id, app_id, require_app_access)
|
430
|
+
if require_app_access && (!@config.enable_user_data_retrieval || !@user_data_service)
|
431
|
+
return { valid: false,
|
432
|
+
error: 'User data service not available for application access verification' }
|
433
|
+
end
|
434
|
+
|
435
|
+
return { valid: true } unless @config.enable_user_data_retrieval && @user_data_service
|
436
|
+
|
437
|
+
begin
|
438
|
+
user_applications = @user_data_service.get_user_applications(user_id)
|
439
|
+
has_access = user_applications.any? { |app| app['appId'] == app_id }
|
440
|
+
|
441
|
+
return { valid: false, error: "User does not have access to application #{app_id}" } unless has_access
|
442
|
+
|
443
|
+
{ valid: true }
|
444
|
+
rescue StandardError => e
|
445
|
+
return { valid: false, error: 'Could not verify application access' } if require_app_access
|
446
|
+
|
447
|
+
ErrorUtils.log_error(e, 'User application access verification failed')
|
448
|
+
{ valid: true } # Continue with basic validation if user data service fails
|
449
|
+
end
|
450
|
+
end
|
302
451
|
end
|
303
452
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jwt_auth_cognito
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre.beta.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The Optimal
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-09-
|
11
|
+
date: 2025-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-ssm
|
@@ -237,9 +237,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
237
237
|
version: 2.7.0
|
238
238
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
239
239
|
requirements:
|
240
|
-
- - "
|
240
|
+
- - ">"
|
241
241
|
- !ruby/object:Gem::Version
|
242
|
-
version:
|
242
|
+
version: 1.3.1
|
243
243
|
requirements: []
|
244
244
|
rubygems_version: 3.3.27
|
245
245
|
signing_key:
|