api_authorization 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +51 -0
- data/Rakefile +31 -0
- data/bin/api_auth +4 -0
- data/lib/api_authorization.rb +5 -0
- data/lib/api_authorization/railtie.rb +75 -0
- data/lib/api_authorization/version.rb +3 -0
- data/lib/app_routes/application_routes.rb +48 -0
- data/lib/tasks/initialize.rake +49 -0
- data/lib/tasks/user_tasks.rake +97 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 94acc2d7dd25207a51d40cfb954a679042f15a0b9d9b68c4fd36f75cfea3fbd9
|
4
|
+
data.tar.gz: cdef5a4d61e6f6d83f8787016281ff959bd2e0e820fd45d9eb4c7030239dac98
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ecf08b501bf862dcef4b1bb603c2255aee2c5db3d724a3aeafc171829d1cf303582cca2568aae82a85519e682a0809c8345880a2e6a62729663fea2ed06b8be4
|
7
|
+
data.tar.gz: 46fd8d2142abd9038bbffd6c232a9a68df34c1beca042f3c0adfd07de2587f6b7675a71dc11957c1500621d9fcc289f9ebb4f2096ebac804f38c1b9f294ba368
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2020 Azdren Ymeri
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Api Authorization (The gem is in development)
|
2
|
+
A multiple role-based authorization, based on controller actions.
|
3
|
+
|
4
|
+

|
5
|
+

|
6
|
+
[](https://opensource.org/licenses/MIT)
|
7
|
+
|
8
|
+
##### Database Model
|
9
|
+

|
10
|
+
## Installation
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'api_authorization'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
```bash
|
19
|
+
$ bundle
|
20
|
+
```
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
```bash
|
24
|
+
$ gem install api_authorization
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
1. After you have created your users_table(through devise or manually) next run
|
29
|
+
```bash
|
30
|
+
$ rails api_auth:initialize
|
31
|
+
```
|
32
|
+
2. Next populate permissions table with your controllers and actions run:
|
33
|
+
```bash
|
34
|
+
$ rails api_auth:create_permissions
|
35
|
+
```
|
36
|
+
3. Include the Authorization module on your `ApplicationController` :
|
37
|
+
```ruby
|
38
|
+
include ActionController::Helpers
|
39
|
+
include ApiAuthorization
|
40
|
+
enable_role_authorization
|
41
|
+
```
|
42
|
+
4. DONE
|
43
|
+
|
44
|
+
##### More CLI commands will be published soon
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
Feel free to suggest a feature or report a bug.
|
48
|
+
#### [Code Of Conduct](CODE_OF_CONDUCT.md)
|
49
|
+
|
50
|
+
## License
|
51
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rdoc/task'
|
10
|
+
|
11
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
12
|
+
rdoc.rdoc_dir = 'rdoc'
|
13
|
+
rdoc.title = 'ApiAuthorization'
|
14
|
+
rdoc.options << '--line-numbers'
|
15
|
+
rdoc.rdoc_files.include('README.md')
|
16
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'bundler/gem_tasks'
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
|
23
|
+
Rake::TestTask.new(:test) do |_t|
|
24
|
+
# t.libs << 'spec'
|
25
|
+
# t.pattern = 'test/**/*_test.rb'
|
26
|
+
# t.verbose = true
|
27
|
+
sh 'rspec --format documentation'
|
28
|
+
end
|
29
|
+
|
30
|
+
task default: :test
|
31
|
+
Rake.add_rakelib 'lib/tasks'
|
data/bin/api_auth
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApiAuthorization
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do |_mod|
|
7
|
+
helper_method :check_role
|
8
|
+
|
9
|
+
def self.enable_role_authorization
|
10
|
+
before_action :check_role
|
11
|
+
end
|
12
|
+
|
13
|
+
# Filter the request with by controller and action to know if a user
|
14
|
+
# can execute that action in that controller
|
15
|
+
#
|
16
|
+
# @return when the user is allowed
|
17
|
+
def check_role
|
18
|
+
puts 'AUTHORIZATION: Checking user roles' if Rails.env == 'development'
|
19
|
+
roles = current_user.try(:roles)
|
20
|
+
return if roles.find { |role| role.try(:name).try(:downcase) == 'superadmin' }
|
21
|
+
|
22
|
+
return render json: { error: 'You are not authorized' }, status: 403 if current_user.roles.empty?
|
23
|
+
|
24
|
+
current_user.roles.each do |role|
|
25
|
+
return if role.permissions.where(controller: params['controller'], action: params['action']).count.positive?
|
26
|
+
end
|
27
|
+
|
28
|
+
render json: { error: 'You are not authorized' }, status: 403
|
29
|
+
rescue StandardError => e
|
30
|
+
render json: { error: 'You are not authorized' }, status: 403
|
31
|
+
end
|
32
|
+
|
33
|
+
# Filter the request params to know wether or not a user has
|
34
|
+
# the right to push a certain value as a parameter.
|
35
|
+
#
|
36
|
+
# example:
|
37
|
+
#
|
38
|
+
# allowed_params = { anno: [2019] }
|
39
|
+
# will remove from the params if the params hash contain a key :anno
|
40
|
+
# with a value which is not 2019
|
41
|
+
#
|
42
|
+
# @params [Action::Parameters]
|
43
|
+
# @return [Action::Parameters] without the disallowed key/values.
|
44
|
+
def check_allowed_params(params, controller, action)
|
45
|
+
puts 'AUTHORIZATION: Checking the request params' if Rails.env == 'development'
|
46
|
+
|
47
|
+
roles = current_user.try(:permissions)
|
48
|
+
return params if roles.find { |role| role.try(:name).try(:downcase) == 'superadmin' }
|
49
|
+
|
50
|
+
rules = roles.where('controller = ? AND action = ? AND allowed_params IS NOT NULL', controller, action)
|
51
|
+
|
52
|
+
return params if rules.nil? || rules.empty?
|
53
|
+
|
54
|
+
rules.each do |rule|
|
55
|
+
next if rule.allowed_params.nil?
|
56
|
+
|
57
|
+
# puts "####### ruleS => #{rule.allowed_params.inspect}"
|
58
|
+
rule.allowed_params.each do |k, v|
|
59
|
+
puts " key: #{k}, value: #{v}"
|
60
|
+
params.delete(k) unless Array(v).include?(params[k]) || v == params[k]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
params
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Railtie < ::Rails::Railtie
|
69
|
+
# exportin rake tasks
|
70
|
+
rake_tasks do
|
71
|
+
load 'tasks/initialize.rake'
|
72
|
+
load 'tasks/user_tasks.rake'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppRoutes
|
4
|
+
class ApplicationRoutes
|
5
|
+
def initialize
|
6
|
+
@routes = []
|
7
|
+
|
8
|
+
Rails.application.routes.routes.map do |r|
|
9
|
+
route = {
|
10
|
+
url: r.defaults[:controller],
|
11
|
+
controller: r.defaults[:controller],
|
12
|
+
action: r.defaults[:action],
|
13
|
+
method: r.verb
|
14
|
+
}
|
15
|
+
# rotta_finale = {
|
16
|
+
# controller: r.defaults[:controller],
|
17
|
+
# action: r.defaults[:action]
|
18
|
+
# }
|
19
|
+
# check = rotta[:controller]
|
20
|
+
# verb = rotta[:method]
|
21
|
+
# action = rotta[:action]
|
22
|
+
# if check && verb != 'PATCH' && action != 'new' && action != 'edit'
|
23
|
+
# @routes.push(rotta_finale) if check.include? 'api/v1'
|
24
|
+
# end
|
25
|
+
|
26
|
+
@routes.push(route)
|
27
|
+
end
|
28
|
+
generate_routes
|
29
|
+
end
|
30
|
+
|
31
|
+
def call
|
32
|
+
@routes.group_by { |n| n[:controller] }.each { |_k, v| v.uniq! }
|
33
|
+
end
|
34
|
+
|
35
|
+
def generate_routes
|
36
|
+
puts 'Populating permissions_table with routes of the application' if Rails.env == 'development'
|
37
|
+
Permission.destroy_all
|
38
|
+
@routes.each do |k|
|
39
|
+
Permission.create!(controller: k[:controller], action: k[:action])
|
40
|
+
end
|
41
|
+
puts 'Done!' if Rails.env == 'development'
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
attr_accessor :routes
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './../app_routes/application_routes.rb'
|
4
|
+
|
5
|
+
namespace :api_auth do
|
6
|
+
desc 'Create the initial tables and populate the permissions table'
|
7
|
+
task :init, %i[tenant single_role] => [:environment] do |_t, args|
|
8
|
+
Apartment::Tenant.switch! args[:tenant] if args[:tenant]
|
9
|
+
|
10
|
+
puts 'Initializing'
|
11
|
+
# TODO: before creating the migration make sure to check that there is
|
12
|
+
# no roles tables or permissions tables
|
13
|
+
if ActiveRecord::Base.connection.table_exists? 'users'
|
14
|
+
|
15
|
+
if args[:single_role].nil?
|
16
|
+
# creating roles table
|
17
|
+
sh 'rails g model role name:string description:text'
|
18
|
+
Rake::Task['db:migrate'].invoke
|
19
|
+
|
20
|
+
# creating a join table between users and roles
|
21
|
+
sh 'rails g migration CreateJoinTableUserRole user role'
|
22
|
+
sh 'rails db:migrate'
|
23
|
+
|
24
|
+
else
|
25
|
+
sh 'rails g model role name:string description:text user:references'
|
26
|
+
sh 'rails db:migrate'
|
27
|
+
end
|
28
|
+
|
29
|
+
# creating permissions table
|
30
|
+
sh 'rails g model permission controller:string action:string allowed_params:json'
|
31
|
+
sh 'rails db:migrate'
|
32
|
+
|
33
|
+
# creating a join table between roles and permissions
|
34
|
+
sh 'rails g migration CreateJoinTableRolePermission role permission'
|
35
|
+
sh 'rails db:migrate'
|
36
|
+
|
37
|
+
else
|
38
|
+
puts 'users table does not exist !'
|
39
|
+
next
|
40
|
+
end
|
41
|
+
puts 'Done !'
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'Populate the permissions table with all the controllers and actions of the application'
|
45
|
+
task :create_permissions, %i[tenant] => [:environment] do |_t, args|
|
46
|
+
Apartment::Tenant.switch! args[:tenant] if args[:tenant]
|
47
|
+
AppRoutes::ApplicationRoutes.new
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :api_auth do
|
4
|
+
desc 'Create a default user and make it superadmin'
|
5
|
+
task :create_superadmin, [:tenant] => [:environment] do |_t, args|
|
6
|
+
Apartment::Tenant.switch args[:tenant] do
|
7
|
+
user = User.find_by_email('giovanni@montedelgallo.com')
|
8
|
+
role = Role.find_by_name('superadmin')
|
9
|
+
if user
|
10
|
+
puts 'User giovanni@montedelgallo.com already exists'
|
11
|
+
else
|
12
|
+
user = User.create!(email: 'giovanni@montedelgallo.com', password: '123456')
|
13
|
+
puts "User created with email: 'giovanni@montedelgallo.com', password: '123456'"
|
14
|
+
end
|
15
|
+
role ||= Role.create!(name: 'superadmin')
|
16
|
+
user.roles << role
|
17
|
+
end
|
18
|
+
puts '###################################################'
|
19
|
+
puts '##'
|
20
|
+
puts '## USER CREATED:'
|
21
|
+
puts '##'
|
22
|
+
puts '## email: giovanni@montedelgallo.com'
|
23
|
+
puts '## password: 123456'
|
24
|
+
puts "## tenant: #{args[:tenant]}"
|
25
|
+
puts '##'
|
26
|
+
puts '###################################################'
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'create custom user'
|
30
|
+
task :create_user, %i[tenant email password] => [:environment] do |_t, args|
|
31
|
+
Apartment::Tenant.switch args[:tenant] do
|
32
|
+
User.create!(email: args[:email], password: args[:password])
|
33
|
+
puts '###################################################'
|
34
|
+
puts '##'
|
35
|
+
puts '## USER CREATED:'
|
36
|
+
puts '##'
|
37
|
+
puts "## email: #{args[:email]}"
|
38
|
+
puts "## password: #{args[:password]}"
|
39
|
+
puts "## tenant: #{args[:tenant]}"
|
40
|
+
puts '##'
|
41
|
+
puts '###################################################'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Reset user password'
|
46
|
+
task :reset_password, %i[tenant email new_password] => [:environment] do |_t, args|
|
47
|
+
# rails "auth:reset_password[uno, giovanni@montedelgallo.com, password]"
|
48
|
+
Apartment::Tenant.switch args[:tenant] do
|
49
|
+
user = User.find_by_email(args[:email])
|
50
|
+
user.password = args[:new_password]
|
51
|
+
user.save
|
52
|
+
end
|
53
|
+
|
54
|
+
puts '###################################################'
|
55
|
+
puts '##'
|
56
|
+
puts '## USER PASSWORD RESET:'
|
57
|
+
puts '##'
|
58
|
+
puts "## email: #{args[:email]}"
|
59
|
+
puts "## password: #{args[:new_password]}"
|
60
|
+
puts "## tenant: #{args[:tenant]}"
|
61
|
+
puts '##'
|
62
|
+
puts '###################################################'
|
63
|
+
end
|
64
|
+
|
65
|
+
desc 'Make a user superadmin'
|
66
|
+
task :promote_superadmin, %i[tenant email] => [:environment] do |_t, args|
|
67
|
+
# rails "auth:reset_password[uno, giovanni@montedelgallo.com, password]"
|
68
|
+
Apartment::Tenant.switch args[:tenant] do
|
69
|
+
user = User.find_by_email(args[:email])
|
70
|
+
role = Role.find_by_name('superadmin')
|
71
|
+
role ||= Role.create!(name: 'superadmin')
|
72
|
+
user.roles << role
|
73
|
+
end
|
74
|
+
|
75
|
+
puts '###################################################'
|
76
|
+
puts '##'
|
77
|
+
puts '## USER PROMOTED TO SUPERADMIN:'
|
78
|
+
puts '##'
|
79
|
+
puts "## email: #{args[:email]}"
|
80
|
+
puts "## tenant: #{args[:tenant]}"
|
81
|
+
puts '##'
|
82
|
+
puts '###################################################'
|
83
|
+
end
|
84
|
+
|
85
|
+
desc 'create admin'
|
86
|
+
task :create_admin, %i[email password] => [:environment] do |_t, args|
|
87
|
+
Admin.create!(email: args[:email], password: args[:password])
|
88
|
+
puts '###################################################'
|
89
|
+
puts '##'
|
90
|
+
puts '## ADMIN CREATED:'
|
91
|
+
puts '##'
|
92
|
+
puts "## email: #{args[:email]}"
|
93
|
+
puts "## password: #{args[:password]}"
|
94
|
+
puts '##'
|
95
|
+
puts '###################################################'
|
96
|
+
end
|
97
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: api_authorization
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Giovanni Panasiti
|
8
|
+
- Azdren Ymeri
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2020-08-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 6.0.3
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 6.0.3.2
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 6.0.3
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 6.0.3.2
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: sqlite3
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
type: :development
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: byebug
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Highly flexible authorization where a user can have more than 1 role
|
63
|
+
with differen permissions.
|
64
|
+
email:
|
65
|
+
- giovanni@montedelgallo.com
|
66
|
+
- azdren.ymeri@montedelgallo.com
|
67
|
+
executables:
|
68
|
+
- api_auth
|
69
|
+
extensions: []
|
70
|
+
extra_rdoc_files: []
|
71
|
+
files:
|
72
|
+
- MIT-LICENSE
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- bin/api_auth
|
76
|
+
- lib/api_authorization.rb
|
77
|
+
- lib/api_authorization/railtie.rb
|
78
|
+
- lib/api_authorization/version.rb
|
79
|
+
- lib/app_routes/application_routes.rb
|
80
|
+
- lib/tasks/initialize.rake
|
81
|
+
- lib/tasks/user_tasks.rake
|
82
|
+
homepage: https://montedelgallo.com/
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata:
|
86
|
+
allowed_push_host: https://rubygems.org/
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubygems_version: 3.0.3
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: A multi role bassed authorization
|
106
|
+
test_files: []
|