securial 1.0.1 → 1.0.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/.yardopts +4 -0
- data/README.md +14 -9
- data/app/controllers/concerns/securial/identity.rb +91 -2
- data/app/controllers/securial/accounts_controller.rb +68 -5
- data/app/controllers/securial/application_controller.rb +34 -2
- data/app/controllers/securial/passwords_controller.rb +44 -4
- data/app/controllers/securial/role_assignments_controller.rb +55 -4
- data/app/controllers/securial/roles_controller.rb +54 -0
- data/app/controllers/securial/sessions_controller.rb +77 -3
- data/app/controllers/securial/status_controller.rb +24 -0
- data/app/controllers/securial/users_controller.rb +54 -0
- data/app/jobs/securial/application_job.rb +9 -0
- data/app/mailers/securial/application_mailer.rb +12 -0
- data/app/mailers/securial/securial_mailer.rb +30 -0
- data/app/models/concerns/securial/password_resettable.rb +70 -0
- data/app/models/securial/application_record.rb +19 -0
- data/app/models/securial/current.rb +13 -0
- data/app/models/securial/role.rb +17 -0
- data/app/models/securial/role_assignment.rb +16 -0
- data/app/models/securial/session.rb +79 -1
- data/app/models/securial/user.rb +34 -0
- data/lib/generators/factory_bot/model/model_generator.rb +1 -0
- data/lib/securial/auth.rb +44 -6
- data/lib/securial/cli.rb +124 -0
- data/lib/securial/config.rb +49 -2
- data/lib/securial/engine.rb +41 -0
- data/lib/securial/error/auth.rb +52 -0
- data/lib/securial/error/base_securial_error.rb +51 -0
- data/lib/securial/error/config.rb +33 -0
- data/lib/securial/error.rb +33 -3
- data/lib/securial/helpers.rb +48 -4
- data/lib/securial/logger/broadcaster.rb +89 -1
- data/lib/securial/logger/builder.rb +54 -1
- data/lib/securial/logger/formatter.rb +73 -0
- data/lib/securial/logger.rb +42 -1
- data/lib/securial/middleware.rb +40 -9
- data/lib/securial/security/request_rate_limiter.rb +47 -1
- data/lib/securial/security.rb +37 -6
- data/lib/securial/version.rb +8 -1
- data/lib/securial.rb +36 -0
- metadata +4 -3
data/lib/securial/helpers.rb
CHANGED
@@ -1,11 +1,55 @@
|
|
1
|
+
# @title Securial Helper Utilities
|
2
|
+
#
|
3
|
+
# Centralized collection of helper modules for the Securial framework.
|
4
|
+
#
|
5
|
+
# This file serves as the entry point for all helper functionality in Securial,
|
6
|
+
# loading specialized utility modules that provide common functions used
|
7
|
+
# throughout the framework. These helpers handle tasks such as normalization,
|
8
|
+
# pattern matching, role management, and data transformation, making common
|
9
|
+
# operations consistent across the codebase.
|
10
|
+
#
|
11
|
+
# @example Normalizing user input
|
12
|
+
# # For normalizing email addresses (converts to lowercase)
|
13
|
+
# email = Securial::Helpers::NormalizingHelper.normalize_email("USER@EXAMPLE.COM")
|
14
|
+
# # => "user@example.com"
|
15
|
+
#
|
16
|
+
# @example Validating input format
|
17
|
+
# # For validating email format
|
18
|
+
# valid = Securial::Helpers::RegexHelper.valid_email?("user@example.com")
|
19
|
+
# # => true
|
20
|
+
#
|
21
|
+
# invalid = Securial::Helpers::RegexHelper.valid_email?("not-an-email")
|
22
|
+
# # => false
|
23
|
+
#
|
24
|
+
# @example Transforming data structure keys
|
25
|
+
# # For transforming keys in response data (snake_case to camelCase)
|
26
|
+
# data = { user_id: 1, first_name: "John", last_name: "Doe" }
|
27
|
+
# json = Securial::Helpers::KeyTransformer.transform(data, :lower_camel_case)
|
28
|
+
# # => { userId: 1, firstName: "John", lastName: "Doe" }
|
29
|
+
#
|
1
30
|
require "securial/helpers/normalizing_helper"
|
2
31
|
require "securial/helpers/regex_helper"
|
3
32
|
require "securial/helpers/roles_helper"
|
4
33
|
require "securial/helpers/key_transformer"
|
5
34
|
|
6
35
|
module Securial
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
36
|
+
# Namespace containing utility modules for common operations.
|
37
|
+
#
|
38
|
+
# The Helpers module serves as a container for specialized utility modules
|
39
|
+
# that provide reusable functionality across the Securial framework:
|
40
|
+
#
|
41
|
+
# - {NormalizingHelper} - Methods for normalizing user input (emails, usernames, etc.)
|
42
|
+
# - {RegexHelper} - Regular expressions and validation methods for input validation
|
43
|
+
# - {RolesHelper} - Functions for working with user roles and permissions management
|
44
|
+
# - {KeyTransformer} - Tools for transforming data structure keys between formats (snake_case, camelCase)
|
45
|
+
#
|
46
|
+
# These helpers ensure consistent behavior across the application and reduce
|
47
|
+
# code duplication by centralizing common operations.
|
48
|
+
#
|
49
|
+
# @see Securial::Helpers::NormalizingHelper
|
50
|
+
# @see Securial::Helpers::RegexHelper
|
51
|
+
# @see Securial::Helpers::RolesHelper
|
52
|
+
# @see Securial::Helpers::KeyTransformer
|
53
|
+
#
|
54
|
+
module Helpers; end
|
11
55
|
end
|
@@ -1,36 +1,109 @@
|
|
1
|
+
# @title Securial Logger Broadcaster
|
2
|
+
#
|
3
|
+
# Logger broadcasting utility for the Securial framework.
|
4
|
+
#
|
5
|
+
# This file defines a broadcaster class that sends logging messages to multiple
|
6
|
+
# destination loggers simultaneously. This enables unified logging across different
|
7
|
+
# outputs (like console and file) while maintaining appropriate formatting for each.
|
8
|
+
#
|
9
|
+
# @example Creating a broadcaster with multiple loggers
|
10
|
+
# # Create individual loggers
|
11
|
+
# file_logger = Logger.new('application.log')
|
12
|
+
# stdout_logger = Logger.new(STDOUT)
|
13
|
+
#
|
14
|
+
# # Combine them into a broadcaster
|
15
|
+
# broadcaster = Securial::Logger::Broadcaster.new([file_logger, stdout_logger])
|
16
|
+
#
|
17
|
+
# # Log messages go to both destinations
|
18
|
+
# broadcaster.info("Processing authentication request")
|
19
|
+
#
|
1
20
|
module Securial
|
2
21
|
module Logger
|
22
|
+
# Broadcasts log messages to multiple logger instances simultaneously.
|
23
|
+
#
|
24
|
+
# This class implements the Logger interface and forwards all logging calls
|
25
|
+
# to a collection of underlying loggers. This allows unified logging to
|
26
|
+
# multiple destinations (e.g., file and stdout) while maintaining specific
|
27
|
+
# formatting for each destination.
|
28
|
+
#
|
29
|
+
# @example Using a broadcaster with two loggers
|
30
|
+
# file_logger = Logger.new('app.log')
|
31
|
+
# console_logger = Logger.new(STDOUT)
|
32
|
+
# broadcaster = Broadcaster.new([file_logger, console_logger])
|
33
|
+
#
|
34
|
+
# # This logs to both destinations
|
35
|
+
# broadcaster.info("User logged in")
|
36
|
+
#
|
3
37
|
class Broadcaster
|
38
|
+
# Initializes a new broadcaster with the provided loggers.
|
39
|
+
#
|
40
|
+
# @param loggers [Array<Logger>] Collection of logger instances
|
41
|
+
# @return [Broadcaster] New broadcaster instance
|
4
42
|
def initialize(loggers)
|
5
43
|
@loggers = loggers
|
6
44
|
end
|
7
45
|
|
46
|
+
# Dynamically define logging methods for each severity level
|
47
|
+
# (debug, info, warn, error, fatal, unknown)
|
8
48
|
::Logger::Severity.constants.each do |severity|
|
9
49
|
define_method(severity.downcase) do |*args, &block|
|
10
50
|
@loggers.each { |logger| logger.public_send(severity.downcase, *args, &block) }
|
11
51
|
end
|
12
52
|
end
|
13
53
|
|
54
|
+
# Writes a message to each underlying logger.
|
55
|
+
#
|
56
|
+
# @param msg [String] Message to be written
|
57
|
+
# @return [Array] Results from each logger's << method
|
14
58
|
def <<(msg)
|
15
59
|
@loggers.each { |logger| logger << msg }
|
16
60
|
end
|
17
61
|
|
62
|
+
# Closes all underlying loggers.
|
63
|
+
#
|
64
|
+
# @return [void]
|
18
65
|
def close
|
19
66
|
@loggers.each(&:close)
|
20
67
|
end
|
21
68
|
|
69
|
+
# No-op method to satisfy the Logger interface.
|
70
|
+
#
|
71
|
+
# Since each underlying logger has its own formatter, setting a
|
72
|
+
# formatter on the broadcaster is not supported.
|
73
|
+
#
|
74
|
+
# @param _formatter [Object] Ignored formatter object
|
75
|
+
# @return [void]
|
22
76
|
def formatter=(_formatter)
|
23
|
-
# Do nothing
|
77
|
+
# Do nothing - each logger maintains its own formatter
|
24
78
|
end
|
25
79
|
|
80
|
+
# Returns nil to satisfy the Logger interface.
|
81
|
+
#
|
82
|
+
# Since each underlying logger has its own formatter, there is
|
83
|
+
# no single formatter for the broadcaster.
|
84
|
+
#
|
85
|
+
# @return [nil] Always returns nil
|
26
86
|
def formatter
|
27
87
|
nil
|
28
88
|
end
|
29
89
|
|
90
|
+
# Returns the collection of managed loggers.
|
91
|
+
#
|
92
|
+
# @return [Array<Logger>] All loggers managed by this broadcaster
|
93
|
+
#
|
30
94
|
def loggers
|
31
95
|
@loggers
|
32
96
|
end
|
33
97
|
|
98
|
+
# Executes a block with the specified tags added to the log.
|
99
|
+
#
|
100
|
+
# Supports ActiveSupport::TaggedLogging by forwarding tagged blocks
|
101
|
+
# to all underlying loggers that support tagging.
|
102
|
+
#
|
103
|
+
# @param tags [Array<String>] Tags to apply to log messages
|
104
|
+
# @yield Block to be executed with the tags applied
|
105
|
+
# @return [Object] Result of the block
|
106
|
+
#
|
34
107
|
def tagged(*tags, &block)
|
35
108
|
# If all loggers support tagged, nest the calls, otherwise just yield.
|
36
109
|
taggable_loggers = @loggers.select { |logger| logger.respond_to?(:tagged) }
|
@@ -44,10 +117,25 @@ module Securial
|
|
44
117
|
end
|
45
118
|
end
|
46
119
|
|
120
|
+
# Checks if the broadcaster responds to the given method.
|
121
|
+
#
|
122
|
+
# @param method [Symbol] Method name to check
|
123
|
+
# @param include_private [Boolean] Whether to include private methods
|
124
|
+
# @return [Boolean] True if any of the underlying loggers respond to the method
|
47
125
|
def respond_to_missing?(method, include_private = false)
|
48
126
|
@loggers.any? { |logger| logger.respond_to?(method, include_private) } || super
|
49
127
|
end
|
50
128
|
|
129
|
+
# Delegates missing methods to all underlying loggers.
|
130
|
+
#
|
131
|
+
# If all loggers respond to the method, it will be called on each logger.
|
132
|
+
# Otherwise, raises a NoMethodError.
|
133
|
+
#
|
134
|
+
# @param method [Symbol] Method name to call
|
135
|
+
# @param args [Array] Arguments to pass to the method
|
136
|
+
# @param block [Proc] Block to pass to the method
|
137
|
+
# @return [Array] Results from each logger's method call
|
138
|
+
# @raise [NoMethodError] If any logger doesn't respond to the method
|
51
139
|
def method_missing(method, *args, &block)
|
52
140
|
if @loggers.all? { |logger| logger.respond_to?(method) }
|
53
141
|
@loggers.map { |logger| logger.send(method, *args, &block) }
|
@@ -1,3 +1,19 @@
|
|
1
|
+
# @title Securial Logger Builder
|
2
|
+
#
|
3
|
+
# Logger construction utilities for the Securial framework.
|
4
|
+
#
|
5
|
+
# This file defines a builder class that constructs and configures loggers for the Securial
|
6
|
+
# framework based on application configuration. It supports multiple logging destinations
|
7
|
+
# (stdout and file) with appropriate formatters for each, and combines them using a
|
8
|
+
# broadcaster pattern for unified logging.
|
9
|
+
#
|
10
|
+
# @example Building a logger with defaults from configuration
|
11
|
+
# # Securial.configuration has been set up elsewhere
|
12
|
+
# logger = Securial::Logger::Builder.build
|
13
|
+
#
|
14
|
+
# # Log messages go to both configured destinations
|
15
|
+
# logger.info("User authentication successful")
|
16
|
+
#
|
1
17
|
require "logger"
|
2
18
|
require "active_support/logger"
|
3
19
|
require "active_support/tagged_logging"
|
@@ -7,7 +23,22 @@ require "securial/logger/formatter"
|
|
7
23
|
|
8
24
|
module Securial
|
9
25
|
module Logger
|
26
|
+
# Builder for constructing Securial's logging system.
|
27
|
+
#
|
28
|
+
# This class provides factory methods to create properly configured logger instances
|
29
|
+
# based on the application's configuration settings. It supports multiple logging
|
30
|
+
# destinations and handles the setup of formatters, log levels, and tagging.
|
31
|
+
#
|
10
32
|
class Builder
|
33
|
+
# Builds a complete logger system based on configuration settings.
|
34
|
+
#
|
35
|
+
# Creates file and/or stdout loggers as specified in configuration and
|
36
|
+
# combines them using a Broadcaster to provide unified logging to multiple
|
37
|
+
# destinations with appropriate formatting for each.
|
38
|
+
#
|
39
|
+
# @return [Securial::Logger::Broadcaster] A broadcaster containing all configured loggers
|
40
|
+
# @see Securial::Logger::Broadcaster
|
41
|
+
#
|
11
42
|
def self.build
|
12
43
|
loggers = []
|
13
44
|
progname = "Securial"
|
@@ -23,6 +54,17 @@ module Securial
|
|
23
54
|
Broadcaster.new(loggers)
|
24
55
|
end
|
25
56
|
|
57
|
+
# Creates and configures a file logger.
|
58
|
+
#
|
59
|
+
# Sets up a logger that writes to a Rails environment-specific log file
|
60
|
+
# with plain text formatting and adds it to the provided loggers array.
|
61
|
+
#
|
62
|
+
# @param progname [String] The program name to include in log entries
|
63
|
+
# @param level [Integer, Symbol] The log level (e.g., :info, :debug)
|
64
|
+
# @param loggers [Array<Logger>] Array to which the new logger will be added
|
65
|
+
# @return [ActiveSupport::TaggedLogging] The configured file logger
|
66
|
+
# @see Securial::Logger::Formatter::PlainFormatter
|
67
|
+
#
|
26
68
|
def self.create_file_logger(progname, level, loggers)
|
27
69
|
file_logger = ::Logger.new(Rails.root.join("log", "securial-#{Rails.env}.log"))
|
28
70
|
file_logger.level = level
|
@@ -32,12 +74,23 @@ module Securial
|
|
32
74
|
loggers << tagged_file_logger
|
33
75
|
end
|
34
76
|
|
77
|
+
# Creates and configures a stdout logger.
|
78
|
+
#
|
79
|
+
# Sets up a logger that writes to standard output with colorful formatting
|
80
|
+
# and adds it to the provided loggers array.
|
81
|
+
#
|
82
|
+
# @param progname [String] The program name to include in log entries
|
83
|
+
# @param level [Integer, Symbol] The log level (e.g., :info, :debug)
|
84
|
+
# @param loggers [Array<Logger>] Array to which the new logger will be added
|
85
|
+
# @return [ActiveSupport::TaggedLogging] The configured stdout logger
|
86
|
+
# @see Securial::Logger::Formatter::ColorfulFormatter
|
87
|
+
#
|
35
88
|
def self.create_stdout_logger(progname, level, loggers)
|
36
89
|
stdout_logger = ::Logger.new($stdout)
|
37
90
|
stdout_logger.level = level
|
38
91
|
stdout_logger.progname = progname
|
39
92
|
stdout_logger.formatter = Formatter::ColorfulFormatter.new
|
40
|
-
tagged_stdout_logger =
|
93
|
+
tagged_stdout_logger = ActiveSupport::TaggedLogging.new(stdout_logger)
|
41
94
|
loggers << tagged_stdout_logger
|
42
95
|
end
|
43
96
|
end
|
@@ -1,6 +1,33 @@
|
|
1
|
+
# @title Securial Logger Formatters
|
2
|
+
#
|
3
|
+
# Log formatting utilities for the Securial framework's logging system.
|
4
|
+
#
|
5
|
+
# This file defines formatter classes that determine how log messages are displayed,
|
6
|
+
# providing both colorful terminal-friendly output and plain text output options.
|
7
|
+
# These formatters are used by the Securial::Logger system to ensure consistent
|
8
|
+
# and readable log formats across different environments.
|
9
|
+
#
|
10
|
+
# @example Using a formatter with a standard Ruby logger
|
11
|
+
# require 'logger'
|
12
|
+
# logger = Logger.new(STDOUT)
|
13
|
+
# logger.formatter = Securial::Logger::Formatter::ColorfulFormatter.new
|
14
|
+
#
|
15
|
+
# logger.info("Application started")
|
16
|
+
# # Output: [2023-11-15 14:30:22] INFO -- Application started (in green color)
|
17
|
+
#
|
1
18
|
module Securial
|
2
19
|
module Logger
|
20
|
+
# Formatting utilities for Securial's logging system.
|
21
|
+
#
|
22
|
+
# This module contains formatter classes and constants that determine
|
23
|
+
# how log messages are presented. It provides both colored output for
|
24
|
+
# terminal environments and plain text output for file logging.
|
25
|
+
#
|
3
26
|
module Formatter
|
27
|
+
# Terminal color codes for different log severity levels.
|
28
|
+
#
|
29
|
+
# @return [Hash{String => String}] Mapping of severity names to ANSI color codes
|
30
|
+
#
|
4
31
|
COLORS = {
|
5
32
|
"DEBUG" => "\e[36m", # cyan
|
6
33
|
"INFO" => "\e[32m", # green
|
@@ -9,10 +36,38 @@ module Securial
|
|
9
36
|
"FATAL" => "\e[35m", # magenta
|
10
37
|
"UNKNOWN" => "\e[37m", # white
|
11
38
|
}.freeze
|
39
|
+
|
40
|
+
# ANSI code to reset terminal colors.
|
41
|
+
#
|
42
|
+
# @return [String] Terminal color reset sequence
|
43
|
+
#
|
12
44
|
CLEAR = "\e[0m"
|
45
|
+
|
46
|
+
# Width used for severity level padding in log output.
|
47
|
+
#
|
48
|
+
# @return [Integer] Number of characters to use for severity field
|
49
|
+
#
|
13
50
|
SEVERITY_WIDTH = 5
|
14
51
|
|
52
|
+
# Formatter that adds color to log output for terminal display.
|
53
|
+
#
|
54
|
+
# This formatter colorizes log messages based on their severity level,
|
55
|
+
# making them easier to distinguish in terminal output. It follows the
|
56
|
+
# standard Ruby Logger formatter interface.
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# logger = Logger.new(STDOUT)
|
60
|
+
# logger.formatter = Securial::Logger::Formatter::ColorfulFormatter.new
|
61
|
+
#
|
15
62
|
class ColorfulFormatter
|
63
|
+
# Formats a log message with color based on severity.
|
64
|
+
#
|
65
|
+
# @param severity [String] Log severity level (DEBUG, INFO, etc.)
|
66
|
+
# @param timestamp [Time] Time when the log event occurred
|
67
|
+
# @param progname [String] Program name or context for the log message
|
68
|
+
# @param msg [String] The log message itself
|
69
|
+
# @return [String] Formatted log message with appropriate ANSI color codes
|
70
|
+
#
|
16
71
|
def call(severity, timestamp, progname, msg)
|
17
72
|
color = COLORS[severity] || CLEAR
|
18
73
|
padded_severity = severity.ljust(SEVERITY_WIDTH)
|
@@ -22,7 +77,25 @@ module Securial
|
|
22
77
|
end
|
23
78
|
end
|
24
79
|
|
80
|
+
# Formatter that produces plain text log output without colors.
|
81
|
+
#
|
82
|
+
# This formatter is suitable for file logging or environments where
|
83
|
+
# terminal colors are not supported. It follows the standard Ruby
|
84
|
+
# Logger formatter interface.
|
85
|
+
#
|
86
|
+
# @example
|
87
|
+
# logger = Logger.new('application.log')
|
88
|
+
# logger.formatter = Securial::Logger::Formatter::PlainFormatter.new
|
89
|
+
#
|
25
90
|
class PlainFormatter
|
91
|
+
# Formats a log message in plain text without color codes.
|
92
|
+
#
|
93
|
+
# @param severity [String] Log severity level (DEBUG, INFO, etc.)
|
94
|
+
# @param timestamp [Time] Time when the log event occurred
|
95
|
+
# @param progname [String] Program name or context for the log message
|
96
|
+
# @param msg [String] The log message itself
|
97
|
+
# @return [String] Formatted log message as plain text
|
98
|
+
#
|
26
99
|
def call(severity, timestamp, progname, msg)
|
27
100
|
padded_severity = severity.ljust(SEVERITY_WIDTH)
|
28
101
|
formatted = "[#{timestamp.strftime("%Y-%m-%d %H:%M:%S")}] #{padded_severity} -- #{msg}\n"
|
data/lib/securial/logger.rb
CHANGED
@@ -1,13 +1,54 @@
|
|
1
|
+
# @title Securial Logger Configuration
|
2
|
+
#
|
3
|
+
# Defines the logging interface for the Securial framework.
|
4
|
+
#
|
5
|
+
# This file establishes the logging system for Securial, providing methods
|
6
|
+
# to access and configure the application's logger instance. By default,
|
7
|
+
# it initializes a logger using the Securial::Logger::Builder class, which
|
8
|
+
# configures appropriate log levels and formatters based on the current environment.
|
9
|
+
#
|
10
|
+
# @example Basic logging usage
|
11
|
+
# # Log messages at different levels
|
12
|
+
# Securial.logger.debug("Detailed debugging information")
|
13
|
+
# Securial.logger.info("General information about system operation")
|
14
|
+
# Securial.logger.warn("Warning about potential issue")
|
15
|
+
# Securial.logger.error("Error condition")
|
16
|
+
#
|
17
|
+
# @example Setting a custom logger
|
18
|
+
# # Configure a custom logger
|
19
|
+
# custom_logger = Logger.new(STDOUT)
|
20
|
+
# custom_logger.level = :info
|
21
|
+
# Securial.logger = custom_logger
|
22
|
+
#
|
1
23
|
require_relative "logger/builder"
|
2
24
|
|
3
25
|
module Securial
|
4
26
|
extend self
|
5
27
|
attr_accessor :logger
|
6
28
|
|
29
|
+
# Returns the logger instance used by Securial.
|
30
|
+
#
|
31
|
+
# If no logger has been set, initializes a new logger instance using
|
32
|
+
# the Securial::Logger::Builder class, which configures the logger
|
33
|
+
# based on the current environment settings.
|
34
|
+
#
|
35
|
+
# @return [Securial::Logger::Builder] the configured logger instance
|
36
|
+
# @see Securial::Logger::Builder
|
7
37
|
def logger
|
8
|
-
@logger ||= Logger::Builder.build
|
38
|
+
@logger ||= Securial::Logger::Builder.build
|
9
39
|
end
|
10
40
|
|
41
|
+
# Sets the logger instance for Securial.
|
42
|
+
#
|
43
|
+
# This allows applications to provide their own custom logger
|
44
|
+
# implementation that may have specialized formatting or output
|
45
|
+
# destinations.
|
46
|
+
#
|
47
|
+
# @param logger [Logger] a Logger-compatible object that responds to standard
|
48
|
+
# logging methods (debug, info, warn, error, fatal)
|
49
|
+
# @return [Logger] the newly set logger instance
|
50
|
+
# @example
|
51
|
+
# Securial.logger = Rails.logger
|
11
52
|
def logger=(logger)
|
12
53
|
@logger = logger
|
13
54
|
end
|
data/lib/securial/middleware.rb
CHANGED
@@ -1,16 +1,47 @@
|
|
1
|
+
# @title Securial Middleware Components
|
2
|
+
#
|
3
|
+
# Rack middleware components for the Securial framework.
|
4
|
+
#
|
5
|
+
# This file serves as the entry point for middleware-related functionality in Securial,
|
6
|
+
# loading specialized middleware classes that provide features like request/response
|
7
|
+
# processing, logging enhancements, and security header management.
|
8
|
+
#
|
1
9
|
require "securial/middleware/request_tag_logger"
|
2
10
|
require "securial/middleware/transform_request_keys"
|
3
11
|
require "securial/middleware/transform_response_keys"
|
4
12
|
require "securial/middleware/response_headers"
|
5
13
|
|
6
14
|
module Securial
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
# Namespace for Rack middleware components in the Securial framework.
|
16
|
+
#
|
17
|
+
# This module contains several middleware components that enhance Rails applications:
|
18
|
+
#
|
19
|
+
# - {RequestTagLogger} - Tags logs with request IDs for better traceability
|
20
|
+
# - {TransformRequestKeys} - Transforms incoming request parameter keys to a consistent format
|
21
|
+
# - {TransformResponseKeys} - Transforms outgoing response JSON keys to match client conventions
|
22
|
+
# - {ResponseHeaders} - Adds security headers to responses based on configuration
|
23
|
+
#
|
24
|
+
# @example Using middleware in a Rails application (config/application.rb)
|
25
|
+
# module YourApp
|
26
|
+
# class Application < Rails::Application
|
27
|
+
# # Add request logging with unique IDs
|
28
|
+
# config.middleware.use Securial::Middleware::RequestTagLogger
|
29
|
+
#
|
30
|
+
# # Transform request keys from camelCase to snake_case
|
31
|
+
# config.middleware.use Securial::Middleware::TransformRequestKeys
|
32
|
+
#
|
33
|
+
# # Transform response keys from snake_case to camelCase
|
34
|
+
# config.middleware.use Securial::Middleware::TransformResponseKeys
|
35
|
+
#
|
36
|
+
# # Add security headers to all responses
|
37
|
+
# config.middleware.use Securial::Middleware::ResponseHeaders
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# @see Securial::Middleware::RequestTagLogger
|
42
|
+
# @see Securial::Middleware::TransformRequestKeys
|
43
|
+
# @see Securial::Middleware::TransformResponseKeys
|
44
|
+
# @see Securial::Middleware::ResponseHeaders
|
45
|
+
#
|
46
|
+
module Middleware; end
|
16
47
|
end
|
@@ -1,11 +1,57 @@
|
|
1
|
+
# @title Securial Request Rate Limiter
|
2
|
+
#
|
3
|
+
# Rate limiting middleware for protecting authentication endpoints in the Securial framework.
|
4
|
+
#
|
5
|
+
# This file implements rate limiting for sensitive endpoints like login and password reset,
|
6
|
+
# protecting them from brute force attacks, credential stuffing, and denial of service attempts.
|
7
|
+
# It uses the Rack::Attack middleware to track and limit request rates based on IP address
|
8
|
+
# and provided credentials.
|
9
|
+
#
|
10
|
+
# @example Basic configuration in a Rails initializer
|
11
|
+
# # In config/initializers/securial.rb
|
12
|
+
# Securial.configure do |config|
|
13
|
+
# config.rate_limit_requests_per_minute = 5
|
14
|
+
# config.rate_limit_response_status = 429
|
15
|
+
# config.rate_limit_response_message = "Too many requests. Please try again later."
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # Apply rate limiting
|
19
|
+
# Securial::Security::RequestRateLimiter.apply!
|
20
|
+
#
|
1
21
|
require "rack/attack"
|
2
22
|
require "securial/config"
|
3
23
|
|
4
24
|
module Securial
|
5
25
|
module Security
|
26
|
+
# Protects authentication endpoints with configurable rate limiting.
|
27
|
+
#
|
28
|
+
# This module provides Rack::Attack-based rate limiting for sensitive Securial
|
29
|
+
# endpoints, preventing brute force attacks and abuse. It limits requests based
|
30
|
+
# on both IP address and credential values (like email address), providing
|
31
|
+
# multi-dimensional protection against different attack vectors.
|
32
|
+
#
|
33
|
+
# Protected endpoints include:
|
34
|
+
# - Login attempts (/sessions/login)
|
35
|
+
# - Password reset requests (/password/forgot)
|
36
|
+
#
|
6
37
|
module RequestRateLimiter
|
7
38
|
extend self
|
8
39
|
|
40
|
+
# Applies rate limiting rules to the Rack::Attack middleware.
|
41
|
+
#
|
42
|
+
# This method configures Rack::Attack with throttling rules for sensitive endpoints
|
43
|
+
# and sets up a custom JSON response format for throttled requests. It should be
|
44
|
+
# called during application initialization, typically in a Rails initializer.
|
45
|
+
#
|
46
|
+
# Rate limits are defined using settings from the Securial configuration:
|
47
|
+
# - rate_limit_requests_per_minute: Maximum requests allowed per minute
|
48
|
+
# - rate_limit_response_status: HTTP status code to return (typically 429)
|
49
|
+
# - rate_limit_response_message: Message to include in throttled responses
|
50
|
+
#
|
51
|
+
# @return [void]
|
52
|
+
# @see Securial::Config::Configuration
|
53
|
+
# @see Rack::Attack
|
54
|
+
#
|
9
55
|
def apply! # rubocop:disable Metrics/MethodLength
|
10
56
|
resp_status = Securial.configuration.rate_limit_response_status
|
11
57
|
resp_message = Securial.configuration.rate_limit_response_message
|
@@ -36,7 +82,7 @@ module Securial
|
|
36
82
|
"Content-Type" => "application/json",
|
37
83
|
"Retry-After" => retry_after.to_s,
|
38
84
|
},
|
39
|
-
[{
|
85
|
+
[{ errors: [resp_message] }.to_json],
|
40
86
|
]
|
41
87
|
end
|
42
88
|
end
|
data/lib/securial/security.rb
CHANGED
@@ -1,8 +1,39 @@
|
|
1
|
+
# @title Securial Security Components
|
2
|
+
#
|
3
|
+
# Security components and protections for the Securial framework.
|
4
|
+
#
|
5
|
+
# This file serves as the entry point for security-related functionality in Securial,
|
6
|
+
# loading specialized security modules that provide protection mechanisms including
|
7
|
+
# rate limiting, CSRF protection, and other security measures to safeguard
|
8
|
+
# Securial-powered applications.
|
9
|
+
#
|
10
|
+
# @example Using the rate limiter
|
11
|
+
# # Set up a rate limiter for login attempts
|
12
|
+
# limiter = Securial::Security::RequestRateLimiter.new(
|
13
|
+
# max_requests: 5,
|
14
|
+
# period: 1.minute,
|
15
|
+
# block_duration: 15.minutes
|
16
|
+
# )
|
17
|
+
#
|
18
|
+
# # Check if a request is allowed
|
19
|
+
# if limiter.allowed?(request.ip)
|
20
|
+
# # Process login attempt
|
21
|
+
# else
|
22
|
+
# # Return rate limit exceeded response
|
23
|
+
# end
|
24
|
+
#
|
1
25
|
require "securial/security/request_rate_limiter"
|
2
26
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
27
|
+
module Securial
|
28
|
+
# Namespace for security-related functionality in the Securial framework.
|
29
|
+
#
|
30
|
+
# The Security module contains components that implement various security
|
31
|
+
# measures to protect applications from common attacks and threats:
|
32
|
+
#
|
33
|
+
# - {RequestRateLimiter} - Protection against brute force and DoS attacks
|
34
|
+
# - Additional security components may be added in future versions
|
35
|
+
#
|
36
|
+
# @see Securial::Security::RequestRateLimiter
|
37
|
+
#
|
38
|
+
module Security; end
|
39
|
+
end
|
data/lib/securial/version.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
1
|
module Securial
|
2
|
-
|
2
|
+
# Current version of the Securial gem.
|
3
|
+
#
|
4
|
+
# This constant is used by the gem specification to determine the version of the gem
|
5
|
+
# when it is built and published to RubyGems. It follows Semantic Versioning 2.0.0.
|
6
|
+
#
|
7
|
+
# @see https://semver.org/ Semantic Versioning 2.0.0
|
8
|
+
# @return [String] the current version in the format "major.minor.patch"
|
9
|
+
VERSION = "1.0.2".freeze
|
3
10
|
end
|
data/lib/securial.rb
CHANGED
@@ -1,11 +1,47 @@
|
|
1
|
+
# Main entry point for the Securial gem.
|
2
|
+
#
|
3
|
+
# This file serves as the primary entry point for the Securial gem,
|
4
|
+
# requiring necessary dependencies, setting up the module structure,
|
5
|
+
# and establishing method delegation.
|
6
|
+
#
|
7
|
+
# The Securial gem is a mountable Rails engine that provides authentication
|
8
|
+
# and authorization capabilities for Rails applications, supporting JWT,
|
9
|
+
# API tokens, and session-based authentication.
|
10
|
+
#
|
11
|
+
# @example Basic usage in a Rails application
|
12
|
+
# # In Gemfile
|
13
|
+
# gem 'securial'
|
14
|
+
#
|
15
|
+
# # In routes.rb
|
16
|
+
# Rails.application.routes.draw do
|
17
|
+
# mount Securial::Engine => '/securial'
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @see Securial::Engine
|
21
|
+
# @see Securial::VERSION
|
22
|
+
#
|
1
23
|
require "securial/version"
|
2
24
|
require "securial/engine"
|
3
25
|
|
4
26
|
require "jbuilder"
|
5
27
|
|
28
|
+
# Main namespace for the Securial authentication and authorization framework.
|
29
|
+
#
|
30
|
+
# This module provides access to core functionality of the Securial gem
|
31
|
+
# by exposing key helper methods and serving as the root namespace for
|
32
|
+
# all Securial components.
|
33
|
+
#
|
6
34
|
module Securial
|
7
35
|
extend self
|
8
36
|
|
37
|
+
# @!method protected_namespace
|
38
|
+
# Returns the namespace used for protected resources in the application.
|
39
|
+
# @return [String] the protected namespace designation
|
40
|
+
|
41
|
+
# @!method titleized_admin_role
|
42
|
+
# Returns the admin role name with proper title-case formatting.
|
43
|
+
# @return [String] the admin role title
|
44
|
+
|
9
45
|
delegate :protected_namespace, to: Securial::Helpers::RolesHelper
|
10
46
|
delegate :titleized_admin_role, to: Securial::Helpers::RolesHelper
|
11
47
|
end
|