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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f93334f493089fe07b825a71ccbe4c8eb2b3ae9b924e2e7cab16f4818d0bb4a
|
4
|
+
data.tar.gz: 47e73ee83002a71737e3d7e16c31fe428652ddb9a6d4104eb2d622b9bc9dc666
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3108d25afcf5df41d3f7578b12fdb496402deb3ba7ce9e8485ed90e96e3d71dd7d4297c67dd49911d73ffd2a31100845e792e5e1670d3a35cbe877bad8066ba6
|
7
|
+
data.tar.gz: 1c403ba8a424348b2ac80c0a46c7cc71e9e720bff838a735caac6d263884c3eab06480917d3bff8c8f7a7ed295bc4ecac1e5cf53caf609c361aa2a5159533e0e
|
data/.yardopts
ADDED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Securial
|
1
|
+
# Securial Gem
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/securial)
|
4
4
|
[](https://rubygems.org/gems/securial)
|
@@ -8,19 +8,22 @@
|
|
8
8
|
[
|
9
9
|
](https://coveralls.io/github/AlyBadawy/Securial?branch=main)
|
10
10
|
|
11
|
+
[](https://alybadawy.github.io/Securial/_index.html)
|
12
|
+
|
11
13
|
---
|
12
14
|
|
15
|
+
## Overview
|
16
|
+
|
13
17
|
### ๐ก๏ธ What is Securial?
|
14
18
|
|
15
19
|
**Securial** is a mountable Rails engine that provides robust, extensible authentication and access control for Rails applications. It supports:
|
16
20
|
|
17
|
-
-
|
18
|
-
-
|
19
|
-
-
|
20
|
-
-
|
21
|
-
-
|
22
|
-
-
|
23
|
-
- ๐ฆ Database-agnostic support
|
21
|
+
- ๐ JWT-based authentication
|
22
|
+
- โช๏ธ API session tokens, with refresh tokens
|
23
|
+
- ๐คณ Simple integration with web and mobile apps
|
24
|
+
- ๐งน Clean, JSON-based API responses
|
25
|
+
- ๐ง User management with roles
|
26
|
+
- ๐ซ Database-agnostic support
|
24
27
|
|
25
28
|
### ๐ Why Securial?
|
26
29
|
|
@@ -34,12 +37,13 @@ Securial can be installed on an existing Rails application or use the `securial
|
|
34
37
|
|
35
38
|
### Installation on an existing Rails app:
|
36
39
|
|
37
|
-
|
40
|
+
Add Securial to an existing Rails app is as simple as 1..2..3:
|
38
41
|
|
39
42
|
- Add `gem "securial"` to your GemFile
|
40
43
|
- Run `bundle install`
|
41
44
|
- Run `rails generate securial:install`
|
42
45
|
- Mount the Securial engine in your Rails application `config/routes.rb` file:
|
46
|
+
|
43
47
|
```ruby
|
44
48
|
Rails.application.routes.draw do
|
45
49
|
mount Securial::Engine => "/securial"
|
@@ -47,6 +51,7 @@ To add Securial to an existing Rails app:
|
|
47
51
|
# The rest of your routes
|
48
52
|
end
|
49
53
|
```
|
54
|
+
|
50
55
|
- Run the migrations by running the command: `rails db:migrate`
|
51
56
|
|
52
57
|
๐ก Full installation steps are available in the [Wiki โบ Installation](https://github.com/AlyBadawy/Securial/wiki/Installation).
|
@@ -1,4 +1,10 @@
|
|
1
1
|
module Securial
|
2
|
+
# Identity Concern
|
3
|
+
#
|
4
|
+
# Provides authentication and user identification functionality for controllers.
|
5
|
+
# This concern adds before_action hooks for user identification and authentication,
|
6
|
+
# and provides helper methods for accessing the current user and enforcing authentication.
|
7
|
+
#
|
2
8
|
module Identity
|
3
9
|
extend ActiveSupport::Concern
|
4
10
|
|
@@ -8,6 +14,41 @@ module Securial
|
|
8
14
|
helper_method :current_user if respond_to?(:helper_method)
|
9
15
|
end
|
10
16
|
|
17
|
+
# @!method skip_authentication!(options = {})
|
18
|
+
# Skips authentication for specified controller actions, making them publicly accessible.
|
19
|
+
#
|
20
|
+
# This class method allows you to bypass the `authenticate_user!` before_action
|
21
|
+
# that is applied by default to all controller actions when including the Identity concern.
|
22
|
+
# It's useful for endpoints that should be publicly accessible, such as landing pages,
|
23
|
+
# password reset, login, or registration.
|
24
|
+
#
|
25
|
+
# @param [Hash] options Options to pass to skip_before_action
|
26
|
+
# @option options [Symbol, Array<Symbol>] :only Specific action(s) to skip authentication for
|
27
|
+
# @option options [Symbol, Array<Symbol>] :except Action(s) to exclude from skipping
|
28
|
+
#
|
29
|
+
# @example Skip authentication for login and registration actions
|
30
|
+
# class SessionsController < ApplicationController
|
31
|
+
# include Securial::Identity
|
32
|
+
#
|
33
|
+
# skip_authentication! only: [:new, :create]
|
34
|
+
#
|
35
|
+
# def new
|
36
|
+
# # Login form action
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# def create
|
40
|
+
# # Authentication logic
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @example Skip authentication for all actions except protected ones
|
45
|
+
# class PublicController < ApplicationController
|
46
|
+
# include Securial::Identity
|
47
|
+
#
|
48
|
+
# skip_authentication! except: [:dashboard, :account]
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# @return [void]
|
11
52
|
class_methods do
|
12
53
|
def skip_authentication!(**options)
|
13
54
|
skip_before_action :authenticate_user!, **options
|
@@ -15,15 +56,34 @@ module Securial
|
|
15
56
|
end
|
16
57
|
|
17
58
|
|
59
|
+
# Returns the currently authenticated user or nil if no user is authenticated.
|
60
|
+
#
|
61
|
+
# This method provides access to the current user object from the session
|
62
|
+
# tracked in Current.session.
|
63
|
+
#
|
64
|
+
# @return [Securial::User, nil] The current authenticated user or nil
|
65
|
+
#
|
18
66
|
def current_user
|
19
67
|
Current.session&.user
|
20
68
|
end
|
21
69
|
|
70
|
+
# Ensures the current user has admin privileges.
|
71
|
+
#
|
72
|
+
# This method checks if a user is authenticated and has admin privileges.
|
73
|
+
# If the user is not an admin, it renders a forbidden response.
|
74
|
+
# If no user is authenticated, it calls authenticate_user! to handle the unauthorized case.
|
75
|
+
#
|
76
|
+
# @return [void]
|
77
|
+
#
|
22
78
|
def authenticate_admin!
|
23
79
|
if current_user
|
24
80
|
return if current_user.is_admin?
|
25
81
|
|
26
|
-
render status: :forbidden,
|
82
|
+
render status: :forbidden,
|
83
|
+
json: {
|
84
|
+
errors: ["You are not authorized to perform this action"],
|
85
|
+
instructions: "Please contact an administrator if you believe this is an error.",
|
86
|
+
}
|
27
87
|
else
|
28
88
|
authenticate_user!
|
29
89
|
end
|
@@ -31,6 +91,18 @@ module Securial
|
|
31
91
|
|
32
92
|
private
|
33
93
|
|
94
|
+
# Identifies the current user from the Authorization header.
|
95
|
+
#
|
96
|
+
# This method attempts to identify the user by:
|
97
|
+
# 1. Checking for a valid Bearer token in the Authorization header
|
98
|
+
# 2. Decoding the token to extract the session ID
|
99
|
+
# 3. Finding and validating the corresponding session
|
100
|
+
# 4. Ensuring IP address and user agent match for security
|
101
|
+
#
|
102
|
+
# If identification succeeds, the session is stored in Current.session
|
103
|
+
#
|
104
|
+
# @return [void]
|
105
|
+
#
|
34
106
|
def identify_user
|
35
107
|
return if internal_rails_request?
|
36
108
|
|
@@ -53,13 +125,30 @@ module Securial
|
|
53
125
|
end
|
54
126
|
end
|
55
127
|
|
128
|
+
# Ensures a user is authenticated before proceeding.
|
129
|
+
#
|
130
|
+
# This method checks if a user has been successfully identified.
|
131
|
+
# If not, it renders an unauthorized response and halts the request.
|
132
|
+
# Internal Rails requests are exempt from authentication requirements.
|
133
|
+
#
|
134
|
+
# @return [void]
|
56
135
|
def authenticate_user!
|
57
136
|
return if internal_rails_request?
|
58
137
|
return if Current.session&.user
|
59
138
|
|
60
|
-
render status: :unauthorized,
|
139
|
+
render status: :unauthorized,
|
140
|
+
json: {
|
141
|
+
errors: ["You are not signed in"],
|
142
|
+
instructions: "Please sign in to access this resource.",
|
143
|
+
} and return
|
61
144
|
end
|
62
145
|
|
146
|
+
# Determines if the current request is from internal Rails controllers.
|
147
|
+
#
|
148
|
+
# This method checks if the current controller is one of Rails' internal
|
149
|
+
# controllers (Info, Mailers, Welcome) which should bypass authentication.
|
150
|
+
#
|
151
|
+
# @return [Boolean] true if the request is from internal Rails controllers, false otherwise
|
63
152
|
def internal_rails_request?
|
64
153
|
defined?(Rails::InfoController) && is_a?(Rails::InfoController) ||
|
65
154
|
defined?(Rails::MailersController) && is_a?(Rails::MailersController) ||
|
@@ -1,59 +1,122 @@
|
|
1
1
|
module Securial
|
2
|
+
#
|
3
|
+
# AccountsController
|
4
|
+
#
|
5
|
+
# This controller handles user account-related operations including:
|
6
|
+
# - User registration
|
7
|
+
# - Profile viewing and management
|
8
|
+
# - Account updates
|
9
|
+
# - Account deletion
|
10
|
+
#
|
11
|
+
# Routes typically mounted at Securial/accounts/* in the host application.
|
12
|
+
#
|
2
13
|
class AccountsController < ApplicationController
|
14
|
+
# Retrieves the current user's profile.
|
15
|
+
#
|
16
|
+
# Provides the authenticated user's complete profile information.
|
17
|
+
# Requires authentication via the Identity concern.
|
18
|
+
#
|
19
|
+
# @return [void] Renders user profile with 200 OK status
|
3
20
|
def me
|
4
21
|
@securial_user = Current.user
|
5
22
|
|
6
23
|
render :show, status: :ok, location: @securial_user
|
7
24
|
end
|
8
25
|
|
26
|
+
# Shows a specific user's profile by username.
|
27
|
+
#
|
28
|
+
# Retrieves and displays public profile information for the requested user.
|
29
|
+
#
|
30
|
+
# @param [String] params[:username] The username of the requested user profile
|
31
|
+
# @return [void] Renders user profile with 200 OK status or 404 if not found
|
9
32
|
def show
|
10
33
|
@securial_user = Securial::User.find_by(username: params.expect(:username))
|
11
34
|
render_user_profile
|
12
35
|
end
|
13
36
|
|
37
|
+
# Registers a new user account.
|
38
|
+
#
|
39
|
+
# Creates a new user in the system with the provided registration information.
|
40
|
+
#
|
41
|
+
# @param [Hash] params[:securial_user] User attributes including email_address, password, etc.
|
42
|
+
# @return [void] Renders new user with 201 Created status or errors with 422
|
14
43
|
def register
|
15
44
|
@securial_user = Securial::User.new(user_params)
|
16
45
|
if @securial_user.save
|
17
46
|
render :show, status: :created, location: @securial_user
|
18
47
|
else
|
19
|
-
render json: {
|
48
|
+
render json: {
|
49
|
+
errors: @securial_user.errors.full_messages }, status: :unprocessable_entity
|
20
50
|
end
|
21
51
|
end
|
22
52
|
|
53
|
+
# Updates the current user's profile information.
|
54
|
+
#
|
55
|
+
# Allows users to modify their profile after authenticating with their current password.
|
56
|
+
#
|
57
|
+
# @param [String] current_password User's current password for verification
|
58
|
+
# @param [Hash] params[:securial_user] Updated user attributes
|
59
|
+
# @return [void] Renders updated user with 200 OK status or errors with 422
|
23
60
|
def update_profile
|
24
61
|
@securial_user = Current.user
|
25
62
|
if @securial_user.authenticate(params[:securial_user][:current_password])
|
26
63
|
if @securial_user.update(user_params)
|
27
64
|
render :show, status: :ok, location: @securial_user
|
28
65
|
else
|
29
|
-
render json: {
|
66
|
+
render json: {
|
67
|
+
errors: @securial_user.errors.full_messages,
|
68
|
+
instructions: "Please ensure all required fields are filled out correctly.",
|
69
|
+
}, status: :unprocessable_entity
|
30
70
|
end
|
31
71
|
else
|
32
|
-
render json: {
|
72
|
+
render json: {
|
73
|
+
errors: ["Current password is incorrect"],
|
74
|
+
instructions: "Please verify your current password and try again.",
|
75
|
+
}, status: :unprocessable_entity
|
33
76
|
end
|
34
77
|
end
|
35
78
|
|
79
|
+
# Permanently deletes the current user's account.
|
80
|
+
#
|
81
|
+
# Removes the user account and all associated data after password verification.
|
82
|
+
#
|
83
|
+
# @param [String] params[:current_password] User's current password for verification
|
84
|
+
# @return [void] Renders success message with 200 OK status or error with 422
|
36
85
|
def delete_account
|
37
86
|
@securial_user = Current.user
|
38
87
|
if @securial_user.authenticate(params.expect(securial_user: [:current_password]).dig(:current_password))
|
39
88
|
@securial_user.destroy
|
40
89
|
render json: { message: "Account deleted successfully" }, status: :ok
|
41
90
|
else
|
42
|
-
render json: {
|
91
|
+
render json: {
|
92
|
+
errors: ["Current password is incorrect"],
|
93
|
+
instructions: "Please verify your current password and try again.",
|
94
|
+
}, status: :unprocessable_entity
|
43
95
|
end
|
44
96
|
end
|
45
97
|
|
46
98
|
private
|
47
99
|
|
100
|
+
# Permits and extracts user parameters from the request.
|
101
|
+
#
|
102
|
+
# @return [ActionController::Parameters] Permitted user parameters
|
103
|
+
#
|
48
104
|
def user_params
|
49
105
|
params.expect(securial_user: [:email_address, :password, :password_confirmation, :first_name, :last_name, :phone, :username, :bio])
|
50
106
|
end
|
51
107
|
|
108
|
+
# Renders the user profile or a not found response.
|
109
|
+
#
|
110
|
+
# @return [void] Renders user profile or not found error
|
111
|
+
#
|
52
112
|
def render_user_profile
|
53
113
|
if @securial_user
|
54
114
|
render :show, status: :ok, location: @securial_user
|
55
115
|
else
|
56
|
-
render json: {
|
116
|
+
render json: {
|
117
|
+
errors: ["User not found"],
|
118
|
+
instructions: "Please check the username and try again.",
|
119
|
+
}, status: :not_found
|
57
120
|
end
|
58
121
|
end
|
59
122
|
end
|
@@ -1,4 +1,16 @@
|
|
1
1
|
module Securial
|
2
|
+
#
|
3
|
+
# ApplicationController
|
4
|
+
#
|
5
|
+
# This is the base controller for the Securial engine, inheriting from ActionController::API.
|
6
|
+
# and provides common functionality for all Securial controllers, including:
|
7
|
+
# - Custom view path configuration
|
8
|
+
# - Common exception handling for API responses
|
9
|
+
# - Standardized error rendering
|
10
|
+
#
|
11
|
+
# All other controllers in the Securial engine inherit from this controller
|
12
|
+
# to ensure consistent behavior across the API.
|
13
|
+
#
|
2
14
|
class ApplicationController < ActionController::API
|
3
15
|
prepend_view_path Securial::Engine.root.join("app", "views")
|
4
16
|
|
@@ -7,12 +19,32 @@ module Securial
|
|
7
19
|
|
8
20
|
private
|
9
21
|
|
22
|
+
# Renders a standardized 404 Not Found JSON response.
|
23
|
+
#
|
24
|
+
# Called automatically when an ActiveRecord::RecordNotFound exception is raised,
|
25
|
+
# ensuring consistent error responses across the API.
|
26
|
+
#
|
27
|
+
# @param [ActiveRecord::RecordNotFound] exception The exception raised when a record is not found
|
28
|
+
# @return [void]
|
10
29
|
def render_404
|
11
|
-
render status: :not_found, json: {
|
30
|
+
render status: :not_found, json: {
|
31
|
+
errors: ["Record not found"],
|
32
|
+
instructions: "Please check the requested resource and try again.",
|
33
|
+
}
|
12
34
|
end
|
13
35
|
|
36
|
+
# Renders a standardized 400 Bad Request JSON response.
|
37
|
+
#
|
38
|
+
# Called automatically when an ActionController::ParameterMissing exception is raised,
|
39
|
+
# providing the client with information about the missing parameter.
|
40
|
+
#
|
41
|
+
# @param [ActionController::ParameterMissing] exception The exception raised for missing parameters
|
42
|
+
# @return [void]
|
14
43
|
def render_400(exception)
|
15
|
-
render status: :bad_request, json: {
|
44
|
+
render status: :bad_request, json: {
|
45
|
+
errors: [exception.message],
|
46
|
+
instructions: "Please ensure all required parameters are provided and formatted correctly.",
|
47
|
+
}
|
16
48
|
end
|
17
49
|
end
|
18
50
|
end
|
@@ -1,8 +1,30 @@
|
|
1
1
|
module Securial
|
2
|
+
#
|
3
|
+
# PasswordsController
|
4
|
+
#
|
5
|
+
# Controller for managing user password operations in the Securial authentication system.
|
6
|
+
#
|
7
|
+
# This controller handles password-related operations including:
|
8
|
+
# - Forgot password functionality
|
9
|
+
# - Password reset with secure tokens
|
10
|
+
#
|
11
|
+
# All actions in this controller skip standard authentication requirements to allow
|
12
|
+
# unauthenticated users to recover their accounts.
|
13
|
+
#
|
14
|
+
# Routes typically mounted at Securial/password/* in the host application.
|
15
|
+
#
|
2
16
|
class PasswordsController < ApplicationController
|
3
17
|
skip_authentication!
|
4
18
|
before_action :set_user_by_password_token, only: %i[ reset_password ]
|
5
19
|
|
20
|
+
# Initiates the password reset process for a user.
|
21
|
+
#
|
22
|
+
# Looks up a user by email address and, if found, generates a secure reset token
|
23
|
+
# and sends password reset instructions via email. To prevent user enumeration attacks,
|
24
|
+
# returns the same success response regardless of whether the email exists.
|
25
|
+
#
|
26
|
+
# @param [String] params[:email_address] The email address of the user requesting password reset
|
27
|
+
# @return [void] Renders success message with 200 OK status
|
6
28
|
def forgot_password
|
7
29
|
if user = User.find_by(email_address: params.require(:email_address))
|
8
30
|
user.generate_reset_password_token!
|
@@ -12,6 +34,15 @@ module Securial
|
|
12
34
|
render status: :ok, json: { message: "Password reset instructions sent (if user with that email address exists)." }
|
13
35
|
end
|
14
36
|
|
37
|
+
# Resets a user's password using a valid reset token.
|
38
|
+
#
|
39
|
+
# Validates the provided token, clears it to prevent reuse, and updates
|
40
|
+
# the user's password if the new password is valid.
|
41
|
+
#
|
42
|
+
# @param [String] params[:token] The password reset token from the email
|
43
|
+
# @param [String] params[:password] The new password
|
44
|
+
# @param [String] params[:password_confirmation] Confirmation of the new password
|
45
|
+
# @return [void] Renders success message with 200 OK status or errors with 422
|
15
46
|
def reset_password
|
16
47
|
@user.clear_reset_password_token!
|
17
48
|
if @user.update(params.permit(:password, :password_confirmation))
|
@@ -23,13 +54,22 @@ module Securial
|
|
23
54
|
|
24
55
|
private
|
25
56
|
|
57
|
+
# Locates and validates a user by their password reset token.
|
58
|
+
#
|
59
|
+
# Sets @user instance variable if the token is valid and not expired.
|
60
|
+
# Renders an error response if the token is invalid or expired.
|
61
|
+
#
|
62
|
+
# @param [String] params[:token] The password reset token to validate
|
63
|
+
# @return [void]
|
26
64
|
def set_user_by_password_token
|
27
|
-
|
28
|
-
|
65
|
+
begin
|
66
|
+
@user = User.find_by_reset_password_token!(params[:token]) # rubocop:disable Rails/DynamicFindBy
|
67
|
+
unless @user.reset_password_token_valid?
|
68
|
+
render status: :unprocessable_entity, json: { errors: { token: "is invalid or has expired" } } and return
|
69
|
+
end
|
70
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveRecord::RecordNotFound
|
29
71
|
render status: :unprocessable_entity, json: { errors: { token: "is invalid or has expired" } } and return
|
30
72
|
end
|
31
|
-
rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveRecord::RecordNotFound
|
32
|
-
render status: :unprocessable_entity, json: { errors: { token: "is invalid or has expired" } } and return
|
33
73
|
end
|
34
74
|
end
|
35
75
|
end
|
@@ -1,10 +1,35 @@
|
|
1
1
|
module Securial
|
2
|
+
#
|
3
|
+
# RoleAssignmentsController
|
4
|
+
#
|
5
|
+
# Controller for managing role assignments in the Securial authorization system.
|
6
|
+
#
|
7
|
+
# This controller handles role management operations including:
|
8
|
+
# - Assigning roles to users
|
9
|
+
# - Removing roles from users
|
10
|
+
#
|
11
|
+
# All operations require admin authentication and are typically used for
|
12
|
+
# user permission management within the application.
|
13
|
+
#
|
14
|
+
# Routes typically mounted at Securial/admins/role_assignments/* in the host application.
|
15
|
+
#
|
2
16
|
class RoleAssignmentsController < ApplicationController
|
17
|
+
# Assigns a role to a user.
|
18
|
+
#
|
19
|
+
# Creates a new role assignment between the specified user and role.
|
20
|
+
# Validates that the assignment doesn't already exist.
|
21
|
+
#
|
22
|
+
# @param [Integer] params[:user_id] The ID of the user to assign the role to
|
23
|
+
# @param [Integer] params[:role_id] The ID of the role to be assigned
|
24
|
+
# @return [void] Renders the created assignment with 201 Created status or errors with 422
|
3
25
|
def create
|
4
26
|
return unless define_user_and_role
|
5
27
|
|
6
28
|
if @securial_user.roles.exists?(@securial_role.id)
|
7
|
-
render json: {
|
29
|
+
render json: {
|
30
|
+
errors: ["Role already assigned to user"],
|
31
|
+
instructions: "Please check the user's current roles before assigning a new one.",
|
32
|
+
}, status: :unprocessable_entity
|
8
33
|
return
|
9
34
|
end
|
10
35
|
@securial_role_assignment = RoleAssignment.new(securial_role_assignment_params)
|
@@ -12,6 +37,14 @@ module Securial
|
|
12
37
|
render :show, status: :created
|
13
38
|
end
|
14
39
|
|
40
|
+
# Removes a role from a user.
|
41
|
+
#
|
42
|
+
# Deletes an existing role assignment between the specified user and role.
|
43
|
+
# Validates that the assignment exists before attempting deletion.
|
44
|
+
#
|
45
|
+
# @param [Integer] params[:user_id] The ID of the user to remove the role from
|
46
|
+
# @param [Integer] params[:role_id] The ID of the role to be removed
|
47
|
+
# @return [void] Renders the deleted assignment with 200 OK status or errors with 422
|
15
48
|
def destroy
|
16
49
|
return unless define_user_and_role
|
17
50
|
@role_assignment = RoleAssignment.find_by(securial_role_assignment_params)
|
@@ -19,27 +52,45 @@ module Securial
|
|
19
52
|
@role_assignment.destroy!
|
20
53
|
render :show, status: :ok
|
21
54
|
else
|
22
|
-
render json: {
|
55
|
+
render json: {
|
56
|
+
errors: ["Role is not assigned to user"],
|
57
|
+
instructions: "Please check the user's current roles before attempting to remove a role.",
|
58
|
+
}, status: :unprocessable_entity
|
23
59
|
end
|
24
60
|
end
|
25
61
|
|
26
62
|
private
|
27
63
|
|
64
|
+
# Looks up and validates the existence of both the user and role.
|
65
|
+
#
|
66
|
+
# Sets @securial_user and @securial_role instance variables if both exist.
|
67
|
+
# Renders error responses if either cannot be found.
|
68
|
+
#
|
69
|
+
# @return [Boolean] true if both user and role were found, false otherwise
|
28
70
|
def define_user_and_role
|
29
71
|
@securial_user = User.find_by(id: params.expect(securial_role_assignment: [:user_id]).dig(:user_id))
|
30
72
|
@securial_role = Role.find_by(id: params.expect(securial_role_assignment: [:role_id]).dig(:role_id))
|
31
73
|
if @securial_user.nil?
|
32
|
-
render json: {
|
74
|
+
render json: {
|
75
|
+
errors: ["User not found"],
|
76
|
+
instructions: "Please check the user ID and try again.",
|
77
|
+
}, status: :unprocessable_entity
|
33
78
|
return false
|
34
79
|
end
|
35
80
|
if @securial_role.nil?
|
36
|
-
render json: {
|
81
|
+
render json: {
|
82
|
+
errors: ["Role not found"],
|
83
|
+
instructions: "Please check the role ID and try again.",
|
84
|
+
}, status: :unprocessable_entity
|
37
85
|
return false
|
38
86
|
end
|
39
87
|
|
40
88
|
true
|
41
89
|
end
|
42
90
|
|
91
|
+
# Permits and extracts role assignment parameters from the request.
|
92
|
+
#
|
93
|
+
# @return [ActionController::Parameters] Permitted role assignment parameters
|
43
94
|
def securial_role_assignment_params
|
44
95
|
params.expect(securial_role_assignment: [:user_id, :role_id])
|
45
96
|
end
|
@@ -1,14 +1,47 @@
|
|
1
1
|
module Securial
|
2
|
+
#
|
3
|
+
# RolesController
|
4
|
+
#
|
5
|
+
# Controller for managing roles in the Securial authorization system.
|
6
|
+
#
|
7
|
+
# This controller handles role management operations including:
|
8
|
+
# - Creating new roles
|
9
|
+
# - Listing available roles
|
10
|
+
# - Updating role properties
|
11
|
+
# - Deleting roles
|
12
|
+
#
|
13
|
+
# All operations require admin authentication and are typically used for
|
14
|
+
# setting up and managing the application's permission structure.
|
15
|
+
#
|
16
|
+
# Routes typically mounted at Securial/admins/roles/* in the host application.
|
17
|
+
#
|
2
18
|
class RolesController < ApplicationController
|
3
19
|
before_action :set_securial_role, only: [:show, :update, :destroy]
|
4
20
|
|
21
|
+
# Lists all roles in the system.
|
22
|
+
#
|
23
|
+
# Retrieves all roles for administrative display and management.
|
24
|
+
#
|
25
|
+
# @return [void] Renders index view with all roles
|
5
26
|
def index
|
6
27
|
@securial_roles = Role.all
|
7
28
|
end
|
8
29
|
|
30
|
+
# Shows details for a specific role.
|
31
|
+
#
|
32
|
+
# Retrieves and displays information for a single role.
|
33
|
+
#
|
34
|
+
# @param [Integer] params[:id] The ID of the role to display
|
35
|
+
# @return [void] Renders show view with the specified role
|
9
36
|
def show
|
10
37
|
end
|
11
38
|
|
39
|
+
# Creates a new role in the system.
|
40
|
+
#
|
41
|
+
# Adds a new role with the provided attributes.
|
42
|
+
#
|
43
|
+
# @param [Hash] params[:securial_role] Role attributes including role_name and hide_from_profile
|
44
|
+
# @return [void] Renders the created role with 201 Created status or errors with 422
|
12
45
|
def create
|
13
46
|
@securial_role = Role.new(securial_role_params)
|
14
47
|
|
@@ -19,6 +52,13 @@ module Securial
|
|
19
52
|
end
|
20
53
|
end
|
21
54
|
|
55
|
+
# Updates an existing role.
|
56
|
+
#
|
57
|
+
# Modifies the attributes of an existing role.
|
58
|
+
#
|
59
|
+
# @param [Integer] params[:id] The ID of the role to update
|
60
|
+
# @param [Hash] params[:securial_role] Updated role attributes
|
61
|
+
# @return [void] Renders the updated role or errors with 422 status
|
22
62
|
def update
|
23
63
|
if @securial_role.update(securial_role_params)
|
24
64
|
render :show
|
@@ -27,6 +67,12 @@ module Securial
|
|
27
67
|
end
|
28
68
|
end
|
29
69
|
|
70
|
+
# Deletes an existing role.
|
71
|
+
#
|
72
|
+
# Permanently removes a role from the system.
|
73
|
+
#
|
74
|
+
# @param [Integer] params[:id] The ID of the role to delete
|
75
|
+
# @return [void] Returns 204 No Content status
|
30
76
|
def destroy
|
31
77
|
@securial_role.destroy
|
32
78
|
head :no_content
|
@@ -34,10 +80,18 @@ module Securial
|
|
34
80
|
|
35
81
|
private
|
36
82
|
|
83
|
+
# Finds and sets a specific role for show, update and destroy actions.
|
84
|
+
#
|
85
|
+
# @param [Integer] params[:id] The ID of the role to find
|
86
|
+
# @return [void]
|
37
87
|
def set_securial_role
|
38
88
|
@securial_role = Role.find(params[:id])
|
39
89
|
end
|
40
90
|
|
91
|
+
# Permits and extracts role parameters from the request.
|
92
|
+
#
|
93
|
+
# @return [ActionController::Parameters] Permitted role parameters
|
94
|
+
#
|
41
95
|
def securial_role_params
|
42
96
|
params.expect(securial_role: [:role_name, :hide_from_profile])
|
43
97
|
end
|