jwt_auth_cognito 0.1.0

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.
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JwtAuthCognito
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "jwt_auth_cognito/version"
4
+ require_relative "jwt_auth_cognito/configuration"
5
+ require_relative "jwt_auth_cognito/jwks_service"
6
+ require_relative "jwt_auth_cognito/redis_service"
7
+ require_relative "jwt_auth_cognito/token_blacklist_service"
8
+ require_relative "jwt_auth_cognito/jwt_validator"
9
+
10
+ module JwtAuthCognito
11
+ class Error < StandardError; end
12
+ class ValidationError < Error; end
13
+ class BlacklistError < Error; end
14
+ class ConfigurationError < Error; end
15
+
16
+ # Specific JWT error types (matching Node.js implementation)
17
+ class TokenExpiredError < ValidationError; end
18
+ class TokenNotActiveError < ValidationError; end
19
+ class TokenFormatError < ValidationError; end
20
+ class TokenRevokedError < ValidationError; end
21
+ class JWKSError < ValidationError; end
22
+ class RedisConnectionError < BlacklistError; end
23
+
24
+ # Configure the gem
25
+ def self.configure
26
+ yield(configuration)
27
+ end
28
+
29
+ def self.configuration
30
+ @configuration ||= Configuration.new
31
+ end
32
+
33
+ def self.reset_configuration!
34
+ @configuration = Configuration.new
35
+ end
36
+ end
37
+
38
+ # Cargar tareas Rake si estamos en Rails
39
+ if defined?(Rails::Railtie)
40
+ require_relative "jwt_auth_cognito/railtie"
41
+ end
@@ -0,0 +1,290 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :jwt_auth_cognito do
4
+ desc "Genera archivo de configuración para jwt_auth_cognito"
5
+ task :install do
6
+ puts "🚀 Instalando jwt_auth_cognito..."
7
+
8
+ # Verificar si estamos en una aplicación Rails
9
+ unless defined?(Rails)
10
+ puts "❌ Error: Este comando debe ejecutarse desde una aplicación Rails"
11
+ exit 1
12
+ end
13
+
14
+ config_file = Rails.root.join('config', 'initializers', 'jwt_auth_cognito.rb')
15
+ env_file = Rails.root.join('.env.example')
16
+
17
+ # Crear directorio si no existe
18
+ FileUtils.mkdir_p(File.dirname(config_file))
19
+
20
+ # Generar archivo de configuración
21
+ if File.exist?(config_file)
22
+ print "El archivo #{config_file} ya existe. ¿Sobrescribir? (y/N): "
23
+ response = STDIN.gets.chomp.downcase
24
+
25
+ unless %w[y yes sí si].include?(response)
26
+ puts "⏭️ Instalación cancelada"
27
+ exit 0
28
+ end
29
+ end
30
+
31
+ # Contenido del archivo de configuración
32
+ config_content = generate_config_content
33
+
34
+ File.write(config_file, config_content)
35
+ puts "✅ Archivo de configuración creado: #{config_file}"
36
+
37
+ # Generar/actualizar .env.example
38
+ env_content = generate_env_content
39
+
40
+ if File.exist?(env_file)
41
+ existing_content = File.read(env_file)
42
+ unless existing_content.include?('COGNITO_USER_POOL_ID')
43
+ File.write(env_file, existing_content + "\n" + env_content)
44
+ puts "✅ Variables agregadas a .env.example"
45
+ else
46
+ puts "ℹ️ Variables ya existen en .env.example"
47
+ end
48
+ else
49
+ File.write(env_file, env_content)
50
+ puts "✅ Archivo .env.example creado"
51
+ end
52
+
53
+ show_next_steps
54
+ end
55
+
56
+ desc "Muestra la configuración actual de jwt_auth_cognito"
57
+ task :config do
58
+ puts "📋 Configuración actual de jwt_auth_cognito:"
59
+ puts "=" * 50
60
+
61
+ config = JwtAuthCognito.configuration
62
+
63
+ puts "🏛️ AWS Cognito:"
64
+ puts " Region: #{config.cognito_region || '❌ NO CONFIGURADO'}"
65
+ puts " User Pool ID: #{config.cognito_user_pool_id || '❌ NO CONFIGURADO'}"
66
+ puts " Client ID: #{config.cognito_client_id || '❌ NO CONFIGURADO'}"
67
+ puts " Client Secret: #{config.has_client_secret? ? '✅ CONFIGURADO' : '⚠️ NO CONFIGURADO'}"
68
+
69
+ puts "\n🗄️ Redis:"
70
+ puts " Host: #{config.redis_host}"
71
+ puts " Puerto: #{config.redis_port}"
72
+ puts " Base de datos: #{config.redis_db}"
73
+ puts " TLS: #{config.redis_ssl ? '✅ HABILITADO' : '❌ DESHABILITADO'}"
74
+ puts " Password: #{config.redis_password ? '✅ CONFIGURADO' : '❌ NO CONFIGURADO'}"
75
+
76
+ puts "\n⚙️ Configuración:"
77
+ puts " Modo de validación: #{config.validation_mode}"
78
+ puts " Cache JWKS TTL: #{config.jwks_cache_ttl}s"
79
+ puts " Entorno: #{config.environment}"
80
+
81
+ puts "\n🔍 URLs:"
82
+ begin
83
+ puts " JWKS URL: #{config.jwks_url}"
84
+ puts " Cognito Issuer: #{config.cognito_issuer}"
85
+ rescue => e
86
+ puts " ❌ Error generando URLs: #{e.message}"
87
+ end
88
+ end
89
+
90
+ desc "Prueba la conexión a Redis"
91
+ task :test_redis do
92
+ puts "🔧 Probando conexión a Redis..."
93
+
94
+ begin
95
+ redis_service = JwtAuthCognito::RedisService.new
96
+ redis_service.send(:connect_redis)
97
+ puts "✅ Conexión a Redis exitosa"
98
+ rescue => e
99
+ puts "❌ Error conectando a Redis: #{e.message}"
100
+ puts "\n💡 Verifica tu configuración de Redis en las variables de entorno"
101
+ end
102
+ end
103
+
104
+ desc "Prueba la configuración de Cognito"
105
+ task :test_cognito do
106
+ puts "🔧 Probando configuración de Cognito..."
107
+
108
+ config = JwtAuthCognito.configuration
109
+
110
+ begin
111
+ config.validate!
112
+ puts "✅ Configuración básica de Cognito válida"
113
+
114
+ # Probar JWKS
115
+ jwks_service = JwtAuthCognito::JwksService.new
116
+ jwks_service.send(:fetch_jwks)
117
+ puts "✅ Conexión a JWKS exitosa"
118
+
119
+ rescue => e
120
+ puts "❌ Error en configuración de Cognito: #{e.message}"
121
+ puts "\n💡 Verifica tus variables de entorno de Cognito"
122
+ end
123
+ end
124
+
125
+ desc "Limpia todos los tokens de la blacklist"
126
+ task :clear_blacklist do
127
+ print "⚠️ ¿Estás seguro de que quieres limpiar toda la blacklist? (y/N): "
128
+ response = STDIN.gets.chomp.downcase
129
+
130
+ if %w[y yes sí si].include?(response)
131
+ begin
132
+ blacklist_service = JwtAuthCognito::TokenBlacklistService.new
133
+ count = blacklist_service.clear_all_blacklisted_tokens
134
+ puts "✅ #{count} tokens eliminados de la blacklist"
135
+ rescue => e
136
+ puts "❌ Error limpiando blacklist: #{e.message}"
137
+ end
138
+ else
139
+ puts "⏭️ Operación cancelada"
140
+ end
141
+ end
142
+
143
+ private
144
+
145
+ def generate_config_content
146
+ has_redis_config = defined?(Rails) && File.exist?(Rails.root.join('config', 'redis.yml'))
147
+
148
+ <<~CONFIG
149
+ # frozen_string_literal: true
150
+
151
+ # Configuración de JWT Auth Cognito
152
+ # Generado automáticamente el #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}
153
+
154
+ JwtAuthCognito.configure do |config|
155
+ # =============================================================================
156
+ # CONFIGURACIÓN DE AWS COGNITO
157
+ # =============================================================================
158
+
159
+ # User Pool ID de tu Cognito (requerido)
160
+ config.cognito_user_pool_id = ENV['COGNITO_USER_POOL_ID']
161
+
162
+ # Región de AWS donde está tu Cognito (requerido)
163
+ config.cognito_region = ENV['COGNITO_REGION'] || ENV['AWS_REGION'] || 'us-east-1'
164
+
165
+ # Client ID de tu aplicación en Cognito (requerido para validación de audiencia)
166
+ config.cognito_client_id = ENV['COGNITO_CLIENT_ID']
167
+
168
+ # Client Secret de tu aplicación en Cognito (opcional, para mayor seguridad)
169
+ # Si tu User Pool App Client está configurado con client secret, esto es requerido
170
+ config.cognito_client_secret = ENV['COGNITO_CLIENT_SECRET']
171
+
172
+ # =============================================================================
173
+ # CONFIGURACIÓN DE REDIS (para blacklist de tokens)
174
+ # =============================================================================
175
+
176
+ #{redis_config_section(has_redis_config)}
177
+
178
+ # Configuración de timeouts para Redis
179
+ config.redis_timeout = ENV['REDIS_TIMEOUT']&.to_i || 5
180
+ config.redis_connect_timeout = ENV['REDIS_CONNECT_TIMEOUT']&.to_i || 10
181
+ config.redis_read_timeout = ENV['REDIS_READ_TIMEOUT']&.to_i || 10
182
+
183
+ # =============================================================================
184
+ # CONFIGURACIÓN TLS PARA REDIS (PRODUCCIÓN)
185
+ # =============================================================================
186
+
187
+ # Configuración de certificados CA para Redis TLS
188
+ config.redis_ca_cert_path = ENV['REDIS_CA_CERT_PATH']
189
+ config.redis_ca_cert_name = ENV['REDIS_CA_CERT_NAME']
190
+
191
+ # Control de versiones TLS
192
+ config.redis_tls_min_version = ENV['REDIS_TLS_MIN_VERSION'] || 'TLSv1.2'
193
+ config.redis_tls_max_version = ENV['REDIS_TLS_MAX_VERSION'] || 'TLSv1.3'
194
+ config.redis_verify_mode = ENV['REDIS_VERIFY_MODE'] || 'peer'
195
+
196
+ # =============================================================================
197
+ # CONFIGURACIÓN DE VALIDACIÓN
198
+ # =============================================================================
199
+
200
+ # Modo de validación: :secure (producción) o :basic (desarrollo)
201
+ config.validation_mode = Rails.env.production? ? :secure : :basic
202
+
203
+ # Tiempo de cache para claves JWKS (en segundos)
204
+ config.jwks_cache_ttl = ENV['JWKS_CACHE_TTL']&.to_i || 3600 # 1 hora
205
+ end
206
+ CONFIG
207
+ end
208
+
209
+ def redis_config_section(has_redis_config)
210
+ if has_redis_config
211
+ <<~REDIS_CONFIG
212
+ # Integración con configuración existente de Redis
213
+ begin
214
+ redis_config = Rails.application.config_for(:redis)
215
+ config.redis_host = redis_config[:host] || ENV['REDIS_HOST'] || 'localhost'
216
+ config.redis_port = redis_config[:port] || ENV['REDIS_PORT']&.to_i || 6379
217
+ config.redis_password = redis_config[:password] || ENV['REDIS_PASSWORD']
218
+ config.redis_db = redis_config[:db] || ENV['REDIS_DB']&.to_i || 0
219
+ config.redis_ssl = redis_config[:ssl] || ENV['REDIS_TLS'] == 'true'
220
+ rescue StandardError
221
+ # Fallback si config/redis.yml no existe o tiene problemas
222
+ config.redis_host = ENV['REDIS_HOST'] || 'localhost'
223
+ config.redis_port = ENV['REDIS_PORT']&.to_i || 6379
224
+ config.redis_password = ENV['REDIS_PASSWORD']
225
+ config.redis_db = ENV['REDIS_DB']&.to_i || 0
226
+ config.redis_ssl = ENV['REDIS_TLS'] == 'true'
227
+ end
228
+ REDIS_CONFIG
229
+ else
230
+ <<~REDIS_CONFIG
231
+ config.redis_host = ENV['REDIS_HOST'] || 'localhost'
232
+ config.redis_port = ENV['REDIS_PORT']&.to_i || 6379
233
+ config.redis_password = ENV['REDIS_PASSWORD']
234
+ config.redis_db = ENV['REDIS_DB']&.to_i || 0
235
+ config.redis_ssl = ENV['REDIS_TLS'] == 'true'
236
+ REDIS_CONFIG
237
+ end
238
+ end
239
+
240
+ def generate_env_content
241
+ <<~ENV_CONTENT
242
+
243
+ # JWT Auth Cognito - Configuración
244
+ COGNITO_USER_POOL_ID=us-east-1_tu_user_pool_id
245
+ COGNITO_REGION=us-east-1
246
+ COGNITO_CLIENT_ID=tu_cognito_client_id
247
+ COGNITO_CLIENT_SECRET=tu_cognito_client_secret
248
+
249
+ # Redis para blacklist de tokens
250
+ REDIS_HOST=localhost
251
+ REDIS_PORT=6379
252
+ REDIS_PASSWORD=tu_redis_password
253
+ REDIS_DB=0
254
+ REDIS_TLS=false
255
+
256
+ # Redis TLS (para producción)
257
+ REDIS_CA_CERT_PATH=/ruta/a/certificados
258
+ REDIS_CA_CERT_NAME=redis-ca.crt
259
+ REDIS_TLS_MIN_VERSION=TLSv1.2
260
+ REDIS_TLS_MAX_VERSION=TLSv1.3
261
+
262
+ # Configuración adicional
263
+ JWKS_CACHE_TTL=3600
264
+ ENV_CONTENT
265
+ end
266
+
267
+ def show_next_steps
268
+ puts "\n" + "=" * 60
269
+ puts "🎉 ¡Instalación de jwt_auth_cognito completada!"
270
+ puts "=" * 60
271
+ puts "\n📋 PRÓXIMOS PASOS:"
272
+ puts "\n1. 🔧 Configura las variables de entorno:"
273
+ puts " - Edita .env (si usas dotenv) o configura variables del sistema"
274
+ puts " - Como mínimo configura: COGNITO_USER_POOL_ID, COGNITO_REGION, COGNITO_CLIENT_ID"
275
+
276
+ puts "\n2. 🧪 Prueba la configuración:"
277
+ puts " rake jwt_auth_cognito:config # Ver configuración actual"
278
+ puts " rake jwt_auth_cognito:test_cognito # Probar Cognito"
279
+ puts " rake jwt_auth_cognito:test_redis # Probar Redis"
280
+
281
+ puts "\n3. 🚀 Reinicia tu aplicación Rails"
282
+
283
+ puts "\n4. 📖 Usa la gema en tu código:"
284
+ puts " validator = JwtAuthCognito::JwtValidator.new"
285
+ puts " result = validator.validate_token(jwt_token)"
286
+
287
+ puts "\n💡 Para más ejemplos, revisa el README de la gema"
288
+ puts "=" * 60
289
+ end
290
+ end
metadata ADDED
@@ -0,0 +1,207 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jwt_auth_cognito
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - The Optimal
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-06-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jwt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: redis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 4.2.5
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '6.0'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 4.2.5
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '6.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: openssl
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.1.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 2.1.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: json
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.0'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: bundler
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '1.17'
96
+ - - "<"
97
+ - !ruby/object:Gem::Version
98
+ version: '3.0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '1.17'
106
+ - - "<"
107
+ - !ruby/object:Gem::Version
108
+ version: '3.0'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rake
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '13.0'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '13.0'
123
+ - !ruby/object:Gem::Dependency
124
+ name: rubocop
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '1.0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '1.0'
137
+ - !ruby/object:Gem::Dependency
138
+ name: webmock
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '3.0'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '3.0'
151
+ description: Gema Ruby para validar tokens JWT de AWS Cognito de forma offline con
152
+ funcionalidad de blacklist basada en Redis y soporte TLS completo
153
+ email:
154
+ - contact@theoptimal.com
155
+ executables: []
156
+ extensions: []
157
+ extra_rdoc_files: []
158
+ files:
159
+ - CHANGELOG.md
160
+ - CLAUDE.md
161
+ - Gemfile
162
+ - LICENSE.txt
163
+ - PUBLISH_GUIDE.md
164
+ - README.md
165
+ - Rakefile
166
+ - jwt_auth_cognito.gemspec
167
+ - lib/generators/jwt_auth_cognito/install_generator.rb
168
+ - lib/generators/jwt_auth_cognito/templates/jwt_auth_cognito.rb.erb
169
+ - lib/jwt_auth_cognito.rb
170
+ - lib/jwt_auth_cognito/configuration.rb
171
+ - lib/jwt_auth_cognito/jwks_service.rb
172
+ - lib/jwt_auth_cognito/jwt_validator.rb
173
+ - lib/jwt_auth_cognito/railtie.rb
174
+ - lib/jwt_auth_cognito/redis_service.rb
175
+ - lib/jwt_auth_cognito/token_blacklist_service.rb
176
+ - lib/jwt_auth_cognito/version.rb
177
+ - lib/tasks/jwt_auth_cognito.rake
178
+ homepage: https://github.com/theoptimal/jwt-auth-cognito
179
+ licenses:
180
+ - MIT
181
+ metadata:
182
+ allowed_push_host: https://rubygems.org
183
+ homepage_uri: https://github.com/theoptimal/jwt-auth-cognito
184
+ source_code_uri: https://github.com/theoptimal/jwt-auth-cognito
185
+ changelog_uri: https://github.com/theoptimal/jwt-auth-cognito/blob/main/CHANGELOG.md
186
+ documentation_uri: https://github.com/theoptimal/jwt-auth-cognito/blob/main/README.md
187
+ bug_tracker_uri: https://github.com/theoptimal/jwt-auth-cognito/issues
188
+ post_install_message:
189
+ rdoc_options: []
190
+ require_paths:
191
+ - lib
192
+ required_ruby_version: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: 2.7.0
197
+ required_rubygems_version: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ requirements: []
203
+ rubygems_version: 3.1.6
204
+ signing_key:
205
+ specification_version: 4
206
+ summary: Validación offline de JWT con AWS Cognito y blacklist Redis
207
+ test_files: []