beskar 0.0.2 → 0.2.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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +274 -0
  3. data/README.md +412 -204
  4. data/app/channels/concerns/beskar/channels/session_security.rb +46 -0
  5. data/app/controllers/beskar/administrative_actions_controller.rb +16 -0
  6. data/app/controllers/beskar/application_controller.rb +214 -0
  7. data/app/controllers/beskar/banned_ips_controller.rb +255 -0
  8. data/app/controllers/beskar/dashboard_controller.rb +62 -0
  9. data/app/controllers/beskar/security_events_controller.rb +164 -0
  10. data/app/controllers/concerns/beskar/controllers/audit_export.rb +54 -0
  11. data/app/controllers/concerns/beskar/controllers/security_tracking.rb +76 -48
  12. data/app/controllers/concerns/beskar/controllers/session_security.rb +29 -0
  13. data/app/jobs/beskar/notification_job.rb +33 -0
  14. data/app/mailers/beskar/security_mailer.rb +59 -0
  15. data/app/models/beskar/administrative_action.rb +41 -0
  16. data/app/models/beskar/banned_ip.rb +105 -105
  17. data/app/models/beskar/security_event.rb +51 -4
  18. data/app/models/beskar/security_state.rb +58 -0
  19. data/app/services/beskar/banned_ip_manager.rb +88 -0
  20. data/app/views/beskar/administrative_actions/index.html.erb +33 -0
  21. data/app/views/beskar/administrative_actions/show.html.erb +21 -0
  22. data/app/views/beskar/banned_ips/edit.html.erb +195 -0
  23. data/app/views/beskar/banned_ips/index.html.erb +319 -0
  24. data/app/views/beskar/banned_ips/new.html.erb +190 -0
  25. data/app/views/beskar/banned_ips/review.html.erb +24 -0
  26. data/app/views/beskar/banned_ips/show.html.erb +304 -0
  27. data/app/views/beskar/dashboard/index.html.erb +280 -0
  28. data/app/views/beskar/security_events/index.html.erb +302 -0
  29. data/app/views/beskar/security_events/show.html.erb +293 -0
  30. data/app/views/beskar/shared/_export_form.html.erb +10 -0
  31. data/app/views/layouts/beskar/_behavior.html.erb +121 -0
  32. data/app/views/layouts/beskar/application.html.erb +581 -6
  33. data/config/routes.rb +30 -0
  34. data/db/migrate/20251016000001_create_beskar_security_events.rb +3 -3
  35. data/db/migrate/20260910000001_create_beskar_security_states.rb +14 -0
  36. data/db/migrate/20260911000001_create_beskar_administrative_actions.rb +22 -0
  37. data/db/migrate/20260911000002_expand_administrative_action_targets.rb +6 -0
  38. data/docs/README.md +73 -0
  39. data/docs/archive/project-documentation.md +659 -0
  40. data/docs/audits/project-review.md +437 -0
  41. data/docs/audits/repair-status.md +216 -0
  42. data/docs/guides/audit-and-waf.md +175 -0
  43. data/docs/guides/audit-lifecycle.md +172 -0
  44. data/docs/guides/authentication.md +213 -0
  45. data/docs/guides/configuration.md +182 -0
  46. data/docs/guides/dashboard-and-search.md +251 -0
  47. data/docs/guides/notifications-and-recovery.md +157 -0
  48. data/docs/guides/risk-scoring.md +116 -0
  49. data/docs/operations/monitor-only-mode.md +85 -0
  50. data/docs/operations/security-hardening.md +167 -0
  51. data/docs/operations/state-storage.md +144 -0
  52. data/docs/research/rust-performance-assessment.md +69 -0
  53. data/lib/beskar/configuration.rb +105 -20
  54. data/lib/beskar/configuration_validator.rb +188 -0
  55. data/lib/beskar/devise_authentication.rb +24 -0
  56. data/lib/beskar/engine.rb +21 -88
  57. data/lib/beskar/logger.rb +288 -0
  58. data/lib/beskar/middleware/request_analyzer.rb +133 -99
  59. data/lib/beskar/models/security_trackable_authenticable.rb +76 -97
  60. data/lib/beskar/models/security_trackable_devise.rb +34 -25
  61. data/lib/beskar/models/security_trackable_generic.rb +171 -214
  62. data/lib/beskar/risk_level.rb +22 -0
  63. data/lib/beskar/services/account_locker.rb +90 -81
  64. data/lib/beskar/services/administrative_audit.rb +36 -0
  65. data/lib/beskar/services/administrative_bans.rb +104 -0
  66. data/lib/beskar/services/audit_data.rb +72 -0
  67. data/lib/beskar/services/authentication.rb +31 -0
  68. data/lib/beskar/services/authentication_attempt.rb +141 -0
  69. data/lib/beskar/services/ban_expiry.rb +28 -0
  70. data/lib/beskar/services/device_detector.rb +32 -41
  71. data/lib/beskar/services/event_search.rb +58 -0
  72. data/lib/beskar/services/geolocation_service.rb +83 -114
  73. data/lib/beskar/services/ip_whitelist.rb +31 -40
  74. data/lib/beskar/services/location_assessment.rb +109 -0
  75. data/lib/beskar/services/native_account_lock.rb +82 -0
  76. data/lib/beskar/services/notifications.rb +46 -0
  77. data/lib/beskar/services/rate_limiter.rb +99 -125
  78. data/lib/beskar/services/request_context.rb +64 -0
  79. data/lib/beskar/services/risk_assessment.rb +58 -0
  80. data/lib/beskar/services/session_revocation.rb +62 -0
  81. data/lib/beskar/services/waf.rb +311 -198
  82. data/lib/beskar/services/waf_request.rb +60 -0
  83. data/lib/beskar/version.rb +1 -1
  84. data/lib/beskar/warden_authentication.rb +53 -0
  85. data/lib/beskar.rb +54 -4
  86. data/lib/generators/beskar/install/install_generator.rb +158 -0
  87. data/lib/generators/beskar/install/templates/initializer.rb.tt +261 -0
  88. data/lib/tasks/beskar_tasks.rake +25 -20
  89. metadata +93 -12
  90. data/lib/beskar/templates/beskar_initializer.rb +0 -107
@@ -0,0 +1,659 @@
1
+ # Archived Beskar project overview
2
+
3
+ This overview predates the September 2026 remediation. Its cache and enforcement
4
+ descriptions are historical. Consult [State storage](../operations/state-storage.md) for the
5
+ current coordination contract, [Authentication](../guides/authentication.md) for current
6
+ admission/session integration, [Risk scoring](../guides/risk-scoring.md) for scored evidence
7
+ and removal of implicit trust discounts, [Audit data and WAF](../guides/audit-and-waf.md) for current
8
+ capture/export and matching behavior, [Dashboard and search](../guides/dashboard-and-search.md)
9
+ for current reporting/search/routes and UTC/CSP/browser behavior, [Configuration](../guides/configuration.md) for validation
10
+ and supported capabilities, [Notifications and recovery](../guides/notifications-and-recovery.md)
11
+ for opt-in delivery/host recovery, [Audit lifecycle](../guides/audit-lifecycle.md) for retained
12
+ events and administrative history, and [Repair status](../audits/repair-status.md) for verified
13
+ fixes and open findings. Local verification uses mise default Ruby 4.0.6.
14
+
15
+ ## Quick Reference for Coding Agents
16
+
17
+ This document provides a comprehensive overview of the Beskar security engine project structure, architecture, and key implementation details for efficient coding sessions.
18
+
19
+ ## Project Overview
20
+
21
+ **Beskar** is a Rails-native security engine (Rails 8.0+) that provides multi-layered protection for web applications. It's built as a mountable Rails Engine with minimal external dependencies.
22
+
23
+ ### Core Information
24
+ - **Name**: Beskar
25
+ - **Version**: 0.1.0
26
+ - **Type**: Rails Engine (mountable)
27
+ - **Rails Version**: >= 8.0.0
28
+ - **Ruby Version**: Compatible with Ruby 3.x
29
+ - **License**: MIT
30
+ - **Author**: Maciej Litwiniuk
31
+
32
+ ### Latest Release (v0.1.0)
33
+ - **Release Date**: 2024-12-20
34
+ - **Major Change**: Monitor-only mode refactored to top-level configuration
35
+ - **Breaking Change**: `config.waf[:monitor_only]` → `config.monitor_only`
36
+ - **Key Feature**: Ban records now created even in monitor-only mode for verification
37
+ - **Migration Required**: See [Current upgrade guidance](../operations/security-hardening.md)
38
+ - **Full Changelog**: See [CHANGELOG.md](../../CHANGELOG.md)
39
+
40
+ ### Key Dependencies
41
+ - `rails` >= 8.0.0
42
+ - `maxminddb` ~> 0.1 (for GeoIP functionality)
43
+ - Development: `devise`, `debug`, `factory_bot_rails`, `mocha`
44
+ - Dashboard: No external CSS dependencies - uses embedded styles
45
+
46
+ ## Architecture Overview
47
+
48
+ ### Project Structure
49
+ ```
50
+ beskar/
51
+ ├── app/
52
+ │ ├── models/beskar/ # Active Record models
53
+ │ ├── controllers/beskar/ # Dashboard controllers
54
+ │ ├── jobs/ # Background jobs
55
+ │ └── views/beskar/ # Dashboard views with embedded styles
56
+ ├── lib/
57
+ │ ├── beskar/
58
+ │ │ ├── middleware/ # Rack middleware for request analysis
59
+ │ │ ├── models/ # Concerns and modules for user models
60
+ │ │ ├── services/ # Core service objects
61
+ │ │ ├── templates/ # Installation templates
62
+ │ │ ├── configuration.rb # Configuration class
63
+ │ │ ├── engine.rb # Rails engine definition
64
+ │ │ ├── logger.rb # Centralized logging system
65
+ │ │ └── version.rb # Version constant
66
+ │ └── tasks/ # Rake tasks
67
+ ├── db/migrate/ # Database migrations
68
+ ├── test/ # Test suite
69
+ └── config/ # Engine configuration
70
+ ```
71
+
72
+ ## Core Components
73
+
74
+ ### 0. Dashboard Authentication (`app/controllers/beskar/application_controller.rb`)
75
+
76
+ #### ApplicationController
77
+ - **Purpose**: Base controller for all dashboard endpoints with mandatory authentication
78
+ - **Security Model**: Authentication REQUIRED for all environments (no defaults)
79
+ - **Key Features**:
80
+ - Clean, maintainable authentication flow with single responsibility methods
81
+ - Helpful error messages with configuration examples when authentication not configured
82
+ - Support for any authentication strategy (Devise, token-based, HTTP Basic, custom)
83
+ - Consistent error handling for both HTML and JSON responses
84
+ - CSRF protection enabled
85
+ - Helper methods for formatting timestamps, risk levels, and geolocation data
86
+
87
+ - **Authentication Flow**:
88
+ ```ruby
89
+ authenticate_admin!
90
+
91
+ Configuration present? → No → show_helpful_error_with_examples (401)
92
+ ↓ Yes
93
+ handle_custom_authentication
94
+
95
+ Call config.authenticate_admin.call(request)
96
+
97
+ true → allow access | false → unauthorized (401) | exception → log + unauthorized (401)
98
+ ```
99
+
100
+ - **Configuration Required**:
101
+ ```ruby
102
+ # config/initializers/beskar.rb
103
+ Beskar.configuration.authenticate_admin = ->(request) do
104
+ # Return truthy to allow access, falsey to deny
105
+ # Examples in initializer template
106
+ end
107
+ ```
108
+
109
+ - **Design Principles**:
110
+ - No environment-based defaults (prevents production surprises)
111
+ - Authentication must be explicitly configured
112
+ - Clear separation between authentication logic and error handling
113
+ - All paths return explicit true/false values
114
+ - Comprehensive test coverage (42 tests, 122 assertions)
115
+
116
+ ### 1. Models (`app/models/beskar/`)
117
+
118
+ #### BannedIp
119
+ - **Purpose**: Tracks IP addresses that are banned from the application
120
+ - **Key Fields**:
121
+ - `ip_address`: The banned IP
122
+ - `reason`: Why it was banned (rate_limit_abuse, authentication_abuse, waf_violation)
123
+ - `expires_at`: When the ban expires (nil for permanent)
124
+ - `permanent`: Boolean flag
125
+ - `violation_count`: Number of violations
126
+ - `metadata`: JSON field for additional data
127
+ - **Key Methods**:
128
+ - `.ban!(ip_address, reason:, duration:, ...)`: Ban an IP
129
+ - `.banned?(ip_address)`: Check if IP is banned
130
+ - `.preload_cache!`: Load banned IPs into cache
131
+ - `#extend_ban!`: Extend existing ban (escalating durations)
132
+
133
+ #### SecurityEvent
134
+ - **Purpose**: Comprehensive audit log of security-related events
135
+ - **Key Fields**:
136
+ - `user`: Polymorphic association (optional)
137
+ - `event_type`: Type of event (login_success, login_failed, account_locked, etc.)
138
+ - `ip_address`: Source IP
139
+ - `user_agent`: Browser/client info
140
+ - `risk_score`: Calculated risk (0-100)
141
+ - `metadata`: JSON with event details
142
+ - **Event Types**:
143
+ - Authentication: `login_success`, `login_failed`, `account_locked`
144
+ - WAF: `waf_violation`, `vulnerability_scan`
145
+ - Rate Limiting: `rate_limit_exceeded`
146
+ - Patterns: `brute_force_attempt`, `credential_stuffing`
147
+
148
+ ### 2. Services (`lib/beskar/services/`)
149
+
150
+ #### RateLimiter
151
+ - **Purpose**: Distributed rate limiting using Rails.cache
152
+ - **Key Methods**:
153
+ - `.check_ip_rate_limit(ip)`: Check IP-based limits
154
+ - `.check_account_rate_limit(user_id)`: Check account-based limits
155
+ - `.is_rate_limited?(request, user)`: Combined check
156
+ - **Configuration**: Three tiers (IP, account, global) with configurable limits and periods
157
+
158
+ #### WAF (Web Application Firewall)
159
+ - **Purpose**: Detect and block vulnerability scanning attempts
160
+ - **Categories**:
161
+ - `wordpress`: WordPress-specific paths
162
+ - `php_admin`: PHPMyAdmin and similar
163
+ - `config_files`: .env, .git, database.yml
164
+ - `path_traversal`: Directory traversal attempts
165
+ - `framework_debug`: Debug endpoints
166
+ - `cms_scan`: CMS detection attempts
167
+ - `common_exploits`: Known exploit files
168
+ - **Rails Exception Detection**:
169
+ - `ActionController::UnknownFormat`: Unusual format requests (Medium severity)
170
+ - `ActionDispatch::RemoteIp::IpSpoofAttackError`: IP spoofing attempts (Critical severity)
171
+ - `ActionDispatch::Http::MimeNegotiation::InvalidType`: Invalid MIME types (Medium severity)
172
+ - `ActiveRecord::RecordNotFound`: Record enumeration attempts (Low severity, configurable exclusions)
173
+ - **Key Methods**:
174
+ - `.analyze_request(request)`: Check for vulnerability patterns
175
+ - `.analyze_exception(exception, request)`: Analyze Rails exceptions as threats
176
+ - `.should_block?(ip)`: Determine if IP should be blocked
177
+ - `.record_violation(ip, analysis)`: Log violation and potentially ban
178
+
179
+ #### AccountLocker
180
+ - **Purpose**: Risk-based account locking with Devise integration
181
+ - **Risk Factors**:
182
+ - Geographic anomalies (impossible travel)
183
+ - Device fingerprints (bot detection)
184
+ - Login velocity patterns
185
+ - IP reputation
186
+ - **Adaptive Learning**: Reduces risk scores for established patterns after successful unlocks
187
+ - **Key Methods**:
188
+ - `#should_lock?`: Check if account should be locked based on risk
189
+ - `#lock!`: Lock the account (Devise or custom)
190
+ - `#unlock!`: Unlock the account
191
+
192
+ #### GeolocationService
193
+ - **Purpose**: IP geolocation using MaxMind databases
194
+ - **Providers**:
195
+ - `:maxmind`: Real MaxMind GeoLite2/GeoIP2 database
196
+ - `:mock`: Mock data for development/testing
197
+ - **Key Methods**:
198
+ - `.lookup(ip)`: Get location data
199
+ - `.calculate_distance(coord1, coord2)`: Haversine distance
200
+ - `.impossible_travel?(locations, time_diff)`: Detect impossible travel
201
+
202
+ #### IpWhitelist
203
+ - **Purpose**: Allow trusted IPs to bypass blocking
204
+ - **Features**:
205
+ - Support for single IPs and CIDR ranges
206
+ - IPv4 and IPv6 support
207
+ - Still logs all activity for audit
208
+ - **Key Methods**:
209
+ - `.whitelisted?(ip)`: Check if IP is whitelisted
210
+ - `.add(ip_or_range)`: Add to whitelist
211
+ - `.remove(ip_or_range)`: Remove from whitelist
212
+
213
+ #### DeviceDetector
214
+ - **Purpose**: Analyze user agents for risk assessment
215
+ - **Detection**:
216
+ - Known bot signatures
217
+ - Suspicious patterns
218
+ - Missing/malformed user agents
219
+ - **Key Methods**:
220
+ - `.detect(user_agent)`: Analyze and return device info
221
+ - `.is_bot?(user_agent)`: Check for bot signatures
222
+
223
+ ### 3. Logger (`lib/beskar/logger.rb`)
224
+
225
+ #### Beskar::Logger
226
+ - **Purpose**: Centralized logging system with consistent formatting
227
+ - **Features**:
228
+ - Automatic `[Beskar]` or `[Beskar::Component]` prefix formatting
229
+ - Component name aliasing for cleaner output
230
+ - Configurable log levels and output backends
231
+ - Include module for automatic component detection in classes
232
+ - **Key Methods**:
233
+ - `.debug/info/warn/error/fatal(message, component:)`: Log at specific levels
234
+ - `.logger=`: Set custom logger backend
235
+ - `.level=`: Set minimum log level
236
+ - `.component_aliases=`: Configure component name mappings
237
+ - **Usage**:
238
+ ```ruby
239
+ # Simple logging
240
+ Beskar::Logger.info("User authenticated")
241
+
242
+ # With component
243
+ Beskar::Logger.warn("Rate limit exceeded", component: :WAF)
244
+
245
+ # In classes
246
+ class MyService
247
+ include Beskar::Logger
248
+ def process
249
+ log_info("Processing...") # Auto-uses class name as component
250
+ end
251
+ end
252
+ ```
253
+
254
+ ### 4. Middleware (`lib/beskar/middleware/`)
255
+
256
+ #### RequestAnalyzer
257
+ - **Purpose**: Main entry point for request security analysis
258
+ - **Processing Order**:
259
+ 1. Check IP whitelist status
260
+ 2. Check if IP is banned
261
+ 3. Apply rate limiting
262
+ 4. Analyze WAF patterns
263
+ 5. Process request or block
264
+ - **Responses**:
265
+ - 403 Forbidden: Banned IP or WAF violation
266
+ - 429 Too Many Requests: Rate limited
267
+ - Normal processing: Allowed through
268
+
269
+ ### 5. User Model Concerns (`lib/beskar/models/`)
270
+
271
+ #### SecurityTrackable
272
+ - **Purpose**: Main module for Devise integration (backward compatibility)
273
+ - **Usage**: `include Beskar::SecurityTrackable` in User model
274
+ - **Delegates to**: SecurityTrackableDevise
275
+
276
+ #### SecurityTrackableDevise
277
+ - **Purpose**: Devise-specific authentication tracking
278
+ - **Features**:
279
+ - Automatic success/failure tracking
280
+ - Risk score calculation
281
+ - Account locking integration
282
+ - Warden callback hooks
283
+
284
+ #### SecurityTrackableAuthenticable
285
+ - **Purpose**: Rails 8 has_secure_password integration
286
+ - **Features**: Similar to Devise module but for native Rails auth
287
+
288
+ #### SecurityTrackableGeneric
289
+ - **Purpose**: Shared functionality across all auth systems
290
+ - **Core Methods**:
291
+ - `track_authentication_event(request, outcome)`: Main tracking method
292
+ - `calculate_authentication_risk(request)`: Risk score calculation
293
+ - `lock_if_high_risk!(security_event, request)`: Auto-lock logic
294
+
295
+ ## Database Schema
296
+
297
+ ### beskar_security_events
298
+ ```sql
299
+ - id: bigint (primary key)
300
+ - user_type: string (polymorphic)
301
+ - user_id: bigint (polymorphic)
302
+ - event_type: string (required)
303
+ - ip_address: string
304
+ - attempted_email: string
305
+ - user_agent: text
306
+ - metadata: json
307
+ - risk_score: integer (0-100)
308
+ - created_at: datetime
309
+ - updated_at: datetime
310
+
311
+ Indexes: ip_address, event_type, attempted_email, created_at, risk_score, composite
312
+ ```
313
+
314
+ ### beskar_banned_ips
315
+ ```sql
316
+ - id: bigint (primary key)
317
+ - ip_address: string (unique, required)
318
+ - reason: string (required)
319
+ - details: text
320
+ - banned_at: datetime (required)
321
+ - expires_at: datetime (null = permanent)
322
+ - permanent: boolean (default: false)
323
+ - violation_count: integer (default: 1)
324
+ - metadata: text (JSON)
325
+ - created_at: datetime
326
+ - updated_at: datetime
327
+
328
+ Indexes: ip_address (unique), banned_at, expires_at, composite
329
+ ```
330
+
331
+ ## Configuration Structure
332
+
333
+ Configuration is managed through `Beskar::Configuration` class, accessed via `Beskar.configuration`.
334
+
335
+ ### Main Configuration Blocks
336
+
337
+ ```ruby
338
+ Beskar.configure do |config|
339
+ # ============================================================================
340
+ # Dashboard Authentication (REQUIRED)
341
+ # ============================================================================
342
+ # Configure authentication for the Beskar dashboard.
343
+ # This is REQUIRED and must be set for all environments.
344
+ #
345
+ # The authenticate_admin callback receives the request object and is executed
346
+ # in the controller context, giving you access to all controller methods
347
+ # (cookies, session, authenticate_or_request_with_http_basic, etc.).
348
+ # The block should return truthy value to allow access, falsey to deny.
349
+ #
350
+ # Example 1: Devise with admin role (recommended for production)
351
+ config.authenticate_admin = ->(request) do
352
+ user = request.env['warden']&.authenticate(scope: :user)
353
+ user&.admin?
354
+ end
355
+ #
356
+ # Example 2: Simple token-based authentication
357
+ # config.authenticate_admin = ->(request) do
358
+ # token = ENV['BESKAR_ADMIN_TOKEN']
359
+ # token.present? && Beskar::Services::RequestContext.secure_match?(request.headers['Authorization'], "Bearer #{token}")
360
+ # end
361
+ #
362
+ # Example 3: For development/testing only (NOT for production!)
363
+ # config.authenticate_admin = ->(request) do
364
+ # Rails.env.development? || Rails.env.test?
365
+ # end
366
+ #
367
+ # Example 4: HTTP Basic Auth (uses controller method)
368
+ # config.authenticate_admin = ->(request) do
369
+ # authenticate_or_request_with_http_basic do |username, password|
370
+ # Beskar::Services::RequestContext.secure_match?(username, ENV['BESKAR_USERNAME']) &&
371
+ # Beskar::Services::RequestContext.secure_match?(password, ENV['BESKAR_PASSWORD'])
372
+ # end
373
+ # end
374
+ #
375
+ # Example 5: Cookie-based authentication (uses controller cookies)
376
+ # config.authenticate_admin = ->(request) do
377
+ # Beskar::Services::RequestContext.secure_match?(cookies.signed[:admin_token], ENV['BESKAR_ADMIN_TOKEN'])
378
+ # end
379
+
380
+ # ============================================================================
381
+ # Global Monitor-Only Mode (affects all blocking features)
382
+ # ============================================================================
383
+ config.monitor_only = true # Start with true in production, set to false when ready
384
+
385
+ # Security Tracking
386
+ config.security_tracking = {
387
+ enabled: true,
388
+ track_successful_logins: true,
389
+ track_failed_logins: true,
390
+ auto_analyze_patterns: true
391
+ }
392
+
393
+ # Rate Limiting
394
+ config.rate_limiting = {
395
+ ip_attempts: { limit: 10, period: 1.hour, exponential_backoff: true },
396
+ account_attempts: { limit: 5, period: 15.minutes, exponential_backoff: true },
397
+ global_attempts: { limit: 100, period: 1.minute, exponential_backoff: false }
398
+ }
399
+
400
+ # WAF Configuration
401
+ config.waf[:enabled] = true
402
+ config.waf[:auto_block] = true
403
+ config.waf[:block_threshold] = 3
404
+ config.waf[:violation_window] = 1.hour
405
+ config.waf[:block_durations] = [1.hour, 6.hours, 24.hours, 7.days]
406
+ config.waf[:permanent_block_after] = 5
407
+ config.waf[:create_security_events] = true
408
+
409
+ # Risk-Based Locking
410
+ config.risk_based_locking = {
411
+ enabled: false,
412
+ risk_threshold: 75,
413
+ lock_strategy: :devise_lockable,
414
+ auto_unlock_time: 1.hour,
415
+ notify_user: true,
416
+ log_lock_events: true,
417
+ immediate_signout: false
418
+ }
419
+
420
+ # IP Whitelist
421
+ config.ip_whitelist = [
422
+ "192.168.1.100",
423
+ "10.0.0.0/24"
424
+ ]
425
+
426
+ # Geolocation
427
+ config.geolocation = {
428
+ provider: :mock, # or :maxmind
429
+ maxmind_city_db_path: nil,
430
+ cache_ttl: 4.hours
431
+ }
432
+ end
433
+ ```
434
+
435
+ ## Key Features Implementation
436
+
437
+ ### ⚠️ BREAKING CHANGE in v0.1.0
438
+ **Monitor-only mode is now a top-level configuration setting.**
439
+ - Previous: `config.waf[:monitor_only]`
440
+ - Current: `config.monitor_only`
441
+ - See `BREAKING_CHANGES.md` for migration guide
442
+
443
+ ### 1. Monitor-Only Mode (Global)
444
+ - Set `config.monitor_only = true` (top-level setting affecting all blocking features)
445
+ - Creates ban records and security events normally
446
+ - Logs violations without actually blocking requests
447
+ - Ban records exist in database but are not enforced
448
+ - Useful for initial deployment, testing, and verification
449
+ - Allows you to query `Beskar::BannedIp` to see what would be blocked
450
+
451
+ ### 2. Adaptive Risk Learning
452
+ - After 2+ successful logins from an IP, location becomes "established"
453
+ - Risk scores reduced to 30% for established patterns (max 25)
454
+ - Prevents repeated locks after user validation
455
+ - Stored in SecurityEvent metadata
456
+
457
+ ### 3. Escalating Ban Durations
458
+ - Progressive bans: 1 hour → 6 hours → 24 hours → 7 days → permanent
459
+ - Applied to both rate limiting and WAF violations
460
+ - Violation count tracked in BannedIp model
461
+
462
+ ### 4. Hybrid Blocking System
463
+ - **Cache Layer**: Fast checks via Rails.cache
464
+ - **Database Layer**: Persistent storage, survives restarts
465
+ - **Preloading**: BannedIps loaded into cache on startup
466
+
467
+ ## Installation & Setup
468
+
469
+ ### Installation Task
470
+ ```bash
471
+ bin/rails beskar:install
472
+ ```
473
+ This task:
474
+ 1. Copies migrations to host app
475
+ 2. Creates initializer at `config/initializers/beskar.rb`
476
+ 3. Displays setup instructions
477
+
478
+ ### Manual Setup Steps
479
+ 1. Run migrations: `bin/rails db:migrate`
480
+ 2. Add to User model: `include Beskar::SecurityTrackable`
481
+ 3. Configure in initializer
482
+ 4. Monitor for 24-48 hours with monitor_only mode
483
+ 5. Review logs and adjust configuration
484
+ 6. Disable monitor_only when ready
485
+
486
+ ## Testing Structure
487
+
488
+ ### Test Organization
489
+ ```
490
+ test/
491
+ ├── dummy/ # Dummy Rails app for testing
492
+ ├── factories/ # FactoryBot factories
493
+ ├── integration/ # Integration tests
494
+ ├── models/ # Model tests
495
+ ├── services/ # Service tests
496
+ └── test_helper.rb # Test configuration
497
+ ```
498
+
499
+ ### Key Test Patterns
500
+ - Uses Minitest framework
501
+ - FactoryBot for fixtures
502
+ - Mocha for mocking
503
+ - Tests run against dummy Rails app
504
+
505
+ ## Development Workflow
506
+
507
+ ### Running Tests
508
+ ```bash
509
+ cd beskar
510
+ bundle exec rails test
511
+ ```
512
+
513
+ ### Console Access
514
+ ```bash
515
+ cd beskar/test/dummy
516
+ bin/rails console
517
+ ```
518
+
519
+ ### Key Development Files
520
+ - `beskar.gemspec`: Gem specification
521
+ - `lib/beskar/version.rb`: Version management
522
+ - `lib/beskar.rb`: Main module file
523
+ - `lib/beskar/engine.rb`: Engine configuration
524
+
525
+ ## Common Patterns & Conventions
526
+
527
+ ### Error Handling
528
+ - Services use safe error handling with logging
529
+ - Never break request flow for tracking failures
530
+ - Return nil or safe defaults on errors
531
+
532
+ ### Logging
533
+ - **Centralized System**: All logging through `Beskar::Logger`
534
+ - **Automatic Formatting**: Component prefixes added automatically
535
+ - **Component Aliases**: Clean names (e.g., `Beskar::Services::Waf` → `WAF`)
536
+ - **Levels**: DEBUG for details, INFO for events, WARN for issues, ERROR for failures, FATAL for critical
537
+ - **Monitor-only mode**: Uses emoji indicators (🔍, 🔒)
538
+ - **Usage Examples**:
539
+ ```ruby
540
+ # Direct usage
541
+ Beskar::Logger.info("Message")
542
+ Beskar::Logger.warn("Warning", component: :WAF)
543
+
544
+ # In classes
545
+ include Beskar::Logger
546
+ log_error("Error occurred")
547
+ ```
548
+
549
+ ### Cache Keys
550
+ - Namespaced: `beskar:feature:identifier`
551
+ - Examples:
552
+ - `beskar:banned_ip:192.168.1.1`
553
+ - `beskar:waf_violations:192.168.1.1`
554
+ - `beskar:rate_limit:ip:192.168.1.1`
555
+
556
+ ### Polymorphic Associations
557
+ - SecurityEvent uses polymorphic `user` association
558
+ - Supports multiple user types (User, Admin, etc.)
559
+ - Auto-detection via Devise mappings
560
+
561
+ ## API Quick Reference
562
+
563
+ ### Public Module Methods
564
+ ```ruby
565
+ Beskar.configure { |config| ... }
566
+ Beskar.configuration
567
+ Beskar.rate_limiter
568
+ Beskar.rate_limited?(request, user)
569
+ ```
570
+
571
+ ### Logger Methods
572
+ ```ruby
573
+ Beskar::Logger.debug(message, component: nil)
574
+ Beskar::Logger.info(message, component: nil)
575
+ Beskar::Logger.warn(message, component: nil)
576
+ Beskar::Logger.error(message, component: nil)
577
+ Beskar::Logger.fatal(message, component: nil)
578
+ Beskar::Logger.logger = custom_logger
579
+ Beskar::Logger.level = :warn
580
+ Beskar::Logger.component_aliases = { 'MyClass' => 'MC' }
581
+ ```
582
+
583
+ ### User Model Methods (with SecurityTrackable)
584
+ ```ruby
585
+ user.security_events
586
+ user.track_authentication_event(request, :success/:failed)
587
+ user.calculate_authentication_risk(request)
588
+ user.recent_failed_attempts(time_window)
589
+ ```
590
+
591
+ ### Service Class Methods
592
+ ```ruby
593
+ Beskar::BannedIp.ban!(ip, reason: ..., duration: ...)
594
+ Beskar::BannedIp.banned?(ip)
595
+ Beskar::Services::Waf.analyze_request(request)
596
+ Beskar::Services::RateLimiter.check_ip_rate_limit(ip)
597
+ Beskar::Services::IpWhitelist.whitelisted?(ip)
598
+ Beskar::Services::GeolocationService.lookup(ip)
599
+ ```
600
+
601
+ ## Important Considerations
602
+
603
+ ### Performance
604
+ - Uses Rails.cache extensively (configure appropriately)
605
+ - Database queries optimized with indexes
606
+ - Preloading of banned IPs on startup
607
+ - Async job processing for pattern analysis
608
+
609
+ ### Security
610
+ - No external service dependencies by default
611
+ - MaxMind database must be provided by user (licensing)
612
+ - All events logged for audit trail
613
+ - Whitelisted IPs still tracked but never blocked
614
+
615
+ ### Compatibility
616
+ - Rails 8.0+ required
617
+ - Works with Devise out of the box
618
+ - Supports Rails native authentication (has_secure_password)
619
+ - Database-agnostic (SQLite, PostgreSQL, MySQL)
620
+
621
+ ## Future Enhancements (Planned)
622
+ - Real-time security dashboard (mounted route)
623
+ - Email notifications for security events
624
+ - Advanced bot detection with JavaScript challenges
625
+ - Honeypot fields for form protection
626
+ - API rate limiting endpoints
627
+ - WebAuthn support for high-risk accounts
628
+
629
+ ## Debugging Tips
630
+
631
+ ### Check Security Events
632
+ ```ruby
633
+ Beskar::SecurityEvent.where(event_type: 'waf_violation').recent
634
+ Beskar::SecurityEvent.where(user: some_user).order(created_at: :desc)
635
+ ```
636
+
637
+ ### Monitor Banned IPs
638
+ ```ruby
639
+ Beskar::BannedIp.active
640
+ Beskar::BannedIp.by_reason('waf_violation')
641
+ ```
642
+
643
+ ### Test WAF Patterns
644
+ ```ruby
645
+ request = ActionDispatch::Request.new(env)
646
+ Beskar::Services::Waf.analyze_request(request)
647
+ ```
648
+
649
+ ### Check Rate Limiting
650
+ ```ruby
651
+ Beskar::Services::RateLimiter.check_ip_rate_limit('192.168.1.1')
652
+ ```
653
+
654
+ ## Support & Resources
655
+ - GitHub: https://github.com/humadroid-io/beskar
656
+ - Homepage: https://humadroid.io/beskar
657
+ - Changelog: [CHANGELOG.md](../../CHANGELOG.md)
658
+ - Breaking Changes: [Current upgrade guidance](../operations/security-hardening.md)
659
+ - Author: Maciej Litwiniuk (maciej@litwiniuk.net)