authegy 0.0.1
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/CHANGELOG.md +5 -0
- data/README.md +70 -0
- data/app/assets/config/authegy_manifest.js +2 -0
- data/app/assets/javascripts/authegy/application.js +15 -0
- data/app/assets/stylesheets/authegy/application.css +15 -0
- data/app/controllers/authegy/application_controller.rb +5 -0
- data/app/helpers/authegy/application_helper.rb +4 -0
- data/app/jobs/authegy/application_job.rb +4 -0
- data/app/mailers/authegy/application_mailer.rb +6 -0
- data/app/models/authegy/application_record.rb +5 -0
- data/app/views/layouts/authegy/application.html.erb +16 -0
- data/lib/authegy.rb +27 -0
- data/lib/authegy/authorizable.rb +57 -0
- data/lib/authegy/controller_helpers.rb +62 -0
- data/lib/authegy/engine.rb +5 -0
- data/lib/authegy/models/person.rb +24 -0
- data/lib/authegy/models/role.rb +18 -0
- data/lib/authegy/models/role_assignment.rb +16 -0
- data/lib/authegy/models/user.rb +24 -0
- data/lib/authegy/version.rb +3 -0
- data/lib/devise/models/database_authenticatable_with_person_email.rb +30 -0
- data/lib/devise/models/validatable_with_person_email.rb +41 -0
- data/lib/generators/authegy/USAGE +8 -0
- data/lib/generators/authegy/install_generator.rb +29 -0
- data/lib/generators/authegy/models_generator.rb +46 -0
- data/lib/generators/authegy/orm_helpers.rb +39 -0
- data/lib/generators/authegy/templates/models_migration.erb +83 -0
- data/lib/generators/authegy/templates/person_model.rb +9 -0
- data/lib/generators/authegy/templates/role_assignment_model.rb +6 -0
- data/lib/generators/authegy/templates/role_model.rb +6 -0
- data/lib/generators/authegy/templates/user_model.rb +15 -0
- data/lib/tasks/authegy_tasks.rake +4 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d07d7606ab2766ec64bdec8b4755b033c697bc5d6eccda20f39d8fc308c2489d
|
4
|
+
data.tar.gz: 51685f9e90d411e8514d14c795ef5a6a2b57a0e9234f339ebf591c0ebe03718e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 05a858a671eab9e43fc0c7bf49d77e8abe1ddf81f92c7f60ee71041d0c33e3e4ac0b12abb34ee6282192f16717b196858139583519f4ed1be06abd30dc129403
|
7
|
+
data.tar.gz: cc880a11cbaff90d3e037f6058e215f5cfbdf9880df258df0d0db6d0c1ffc1703bf86207e0a42fbdfc2f278e9aeab52ade142d0966b0c6d4d72575ea8f76fdc0
|
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Authegy
|
2
|
+
|
3
|
+
The Authegy gem is a library that combines several useful ruby libraries to
|
4
|
+
provide an opinionated authentication and role-based authorization models for
|
5
|
+
your rails apps.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'authegy'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install authegy
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### Basic Use Case: The User & Role models
|
26
|
+
|
27
|
+
- Use only a single "User" class, with several roles associated to it - instead
|
28
|
+
of having multiple "user" classes, which tend to have duplicated code &
|
29
|
+
functionality between them.
|
30
|
+
- Roles can also be optionally associated to different "Resource" models, so we
|
31
|
+
can limit the authorization to certain objects. Examples:
|
32
|
+
- "User 2" is an "Administrator" of "Website 2" (so he/she can change the
|
33
|
+
Website 2's URL)
|
34
|
+
- "User 3" is a "Procurement Manager" of "Company 4" (so he/she can place
|
35
|
+
orders on behalf of the Company 4)
|
36
|
+
|
37
|
+

|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
## Development
|
43
|
+
|
44
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
45
|
+
`rake spec` to run the tests. You can also run `bin/console` for an interactive
|
46
|
+
prompt that will allow you to experiment.
|
47
|
+
|
48
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
49
|
+
release a new version, update the version number in `version.rb`, and then run
|
50
|
+
`bundle exec rake release`, which will create a git tag for the version, push
|
51
|
+
git commits and tags, and push the `.gem` file to
|
52
|
+
[rubygems.org](https://rubygems.org).
|
53
|
+
|
54
|
+
## Contributing
|
55
|
+
|
56
|
+
Bug reports and pull requests are welcome on GitHub at
|
57
|
+
https://github.com/vovimayhem/authegy. This project is intended to be a safe,
|
58
|
+
welcoming space for collaboration, and contributors are expected to adhere to
|
59
|
+
the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
60
|
+
|
61
|
+
## License
|
62
|
+
|
63
|
+
The gem is available as open source under the terms of the
|
64
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
65
|
+
|
66
|
+
## Code of Conduct
|
67
|
+
|
68
|
+
Everyone interacting in the A2 project’s codebases, issue trackers, chat rooms
|
69
|
+
and mailing lists is expected to follow the
|
70
|
+
[Code of Conduct](https://github.com/vovimayhem/authegy/blob/master/CODE_OF_CONDUCT.md).
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require rails-ujs
|
14
|
+
//= require activestorage
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Authegy</title>
|
5
|
+
<%= csrf_meta_tags %>
|
6
|
+
<%= csp_meta_tag %>
|
7
|
+
|
8
|
+
<%= stylesheet_link_tag "authegy/application", media: "all" %>
|
9
|
+
<%= javascript_include_tag "authegy/application" %>
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
|
13
|
+
<%= yield %>
|
14
|
+
|
15
|
+
</body>
|
16
|
+
</html>
|
data/lib/authegy.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_support/dependencies'
|
2
|
+
require 'devise'
|
3
|
+
require 'authegy/engine'
|
4
|
+
|
5
|
+
module Authegy
|
6
|
+
autoload :Authorizable, 'authegy/authorizable'
|
7
|
+
|
8
|
+
autoload :Person, 'authegy/models/person'
|
9
|
+
autoload :RoleAssignment, 'authegy/models/role_assignment'
|
10
|
+
autoload :Role, 'authegy/models/role'
|
11
|
+
autoload :User, 'authegy/models/user'
|
12
|
+
|
13
|
+
autoload :ControllerHelpers, 'authegy/controller_helpers'
|
14
|
+
|
15
|
+
def self.extract_resource_attributes(resource_type_or_instance)
|
16
|
+
return { resource_type: resource_type_or_instance } \
|
17
|
+
if resource_type_or_instance.is_a? String
|
18
|
+
|
19
|
+
return { resource_type: resource_type_or_instance.name } \
|
20
|
+
if resource_type_or_instance.is_a? Class
|
21
|
+
|
22
|
+
return {
|
23
|
+
resource_type: resource_type_or_instance.class.name,
|
24
|
+
resource_id: resource_type_or_instance.id
|
25
|
+
} if resource_type_or_instance.respond_to? :id
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Authegy
|
4
|
+
module Authorizable
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
has_many :role_assignments,
|
9
|
+
class_name: '::RoleAssignment',
|
10
|
+
inverse_of: :actor,
|
11
|
+
foreign_key: :actor_id
|
12
|
+
|
13
|
+
has_many :assigned_roles,
|
14
|
+
-> { distinct },
|
15
|
+
through: :role_assignments,
|
16
|
+
source: :role
|
17
|
+
end
|
18
|
+
|
19
|
+
def assign_role(role_name, resource_type_or_instance = nil)
|
20
|
+
assignment_attributes = {
|
21
|
+
role: ::Role.find_or_create_by(name: role_name)
|
22
|
+
}
|
23
|
+
|
24
|
+
if resource_type_or_instance.present?
|
25
|
+
assignment_attributes.merge! Authegy
|
26
|
+
.extract_resource_attributes(resource_type_or_instance)
|
27
|
+
end
|
28
|
+
|
29
|
+
role_assignments.find_or_create_by assignment_attributes
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_role?(role_name, resource_type_or_instance = nil)
|
33
|
+
matching_attributes = { role: role_name.to_s }
|
34
|
+
|
35
|
+
return role_assignment_list.select do |assignment|
|
36
|
+
assignment[:role] == matching_attributes[:role]
|
37
|
+
end.any? if resource_type_or_instance.blank?
|
38
|
+
|
39
|
+
matching_attributes.merge! Authegy
|
40
|
+
.extract_resource_attributes(resource_type_or_instance)
|
41
|
+
|
42
|
+
role_assignment_list.select do |assignment|
|
43
|
+
assignment == matching_attributes
|
44
|
+
end.any?
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def role_assignment_list
|
50
|
+
@role_assignment_list ||= role_assignments.includes(:role).map do |assgn|
|
51
|
+
assgn.attributes.slice('resource_type', 'resource_id').merge!(
|
52
|
+
role: assgn.role.name
|
53
|
+
).symbolize_keys!
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Authegy
|
4
|
+
# = AuthorizationHelper
|
5
|
+
#
|
6
|
+
# Methods that deal with defining access to resources by user roles
|
7
|
+
module ControllerHelpers
|
8
|
+
# authorize_action!
|
9
|
+
# Usage:
|
10
|
+
# ```
|
11
|
+
# class ThingsController < ApplicationController
|
12
|
+
# before_action do
|
13
|
+
# authorize_action! to: 'thing.owner'
|
14
|
+
# authorize_action! :administrator, :manager, of: 'thing.other_thing'
|
15
|
+
# authorize_action! :anyone, from: 'thing.company'
|
16
|
+
# end, only: [:index, :show]
|
17
|
+
# end
|
18
|
+
# ```
|
19
|
+
def authorize_action!(*given_roles)
|
20
|
+
given_roles, options = AuthorizationHelper.parse_given_roles(given_roles)
|
21
|
+
auth_request_env['match_roles_on'] = options[:match_roles_on] if options.key?(:match_roles_on)
|
22
|
+
|
23
|
+
return auth_request_env['authorized_roles'] = Role.all if super_admin_user?
|
24
|
+
auth_request_env['authorized_roles'] = current_user_roles.where(name: given_roles)
|
25
|
+
|
26
|
+
# error if only general manager, plant managers can create
|
27
|
+
|
28
|
+
raise ActionErrors::Forbidden if authorized_roles.map(&:name).count == 1 && current_user_roles.first.name == 'manager' && current_user_roles.where(name: 'manager').where.not(target_id: nil).empty?
|
29
|
+
raise ActionErrors::Forbidden unless authorized_roles.any?
|
30
|
+
end
|
31
|
+
|
32
|
+
def authorize_action(*given_roles)
|
33
|
+
authorize_action!(*given_roles)
|
34
|
+
rescue
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
def super_admin_user?
|
39
|
+
auth_request_env['super_admin_user'] ||= current_user_roles
|
40
|
+
.where(name: :administrator, target_id: nil)
|
41
|
+
.any?
|
42
|
+
end
|
43
|
+
|
44
|
+
# :nodoc:
|
45
|
+
# Reek complains about multiple calls to `request.env` and/or not refering to object state...
|
46
|
+
define_method(:auth_request_env) { request.env }
|
47
|
+
|
48
|
+
define_method(:current_user_roles) { current_user.roles }
|
49
|
+
define_method(:authorized_roles) { auth_request_env['authorized_roles'] }
|
50
|
+
#
|
51
|
+
# def match_roles_on
|
52
|
+
# auth_request_env['match_roles_on']
|
53
|
+
# end
|
54
|
+
|
55
|
+
def self.parse_given_roles(given_roles = [])
|
56
|
+
given_roles = [:administrator] unless given_roles.any?
|
57
|
+
options = given_roles.last.is_a?(Hash) ? given_roles.pop.with_indifferent_access : {}
|
58
|
+
[given_roles, options]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Authegy
|
4
|
+
# Person holds the "Profile" for a given User, but we can also have just
|
5
|
+
# Person profiles without a user, as is the case for "Board Members"
|
6
|
+
class Person < ApplicationRecord
|
7
|
+
include Authegy::Authorizable
|
8
|
+
|
9
|
+
self.table_name = :people
|
10
|
+
self.abstract_class = true
|
11
|
+
|
12
|
+
# Validations from 'validatable':
|
13
|
+
validates_uniqueness_of :email,
|
14
|
+
allow_blank: true,
|
15
|
+
if: :will_save_change_to_email?
|
16
|
+
|
17
|
+
validates_format_of :email,
|
18
|
+
with: Devise.email_regexp,
|
19
|
+
allow_blank: true,
|
20
|
+
if: :will_save_change_to_email?
|
21
|
+
|
22
|
+
has_one :user, class_name: '::User', inverse_of: :person, foreign_key: :id
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Authegy
|
4
|
+
#= Authegy::Role
|
5
|
+
# A `Role`
|
6
|
+
class Role < ApplicationRecord
|
7
|
+
self.table_name = :roles
|
8
|
+
self.abstract_class = true
|
9
|
+
|
10
|
+
validates :name, format: {
|
11
|
+
with: /\A[a-z_]+\z/,
|
12
|
+
message: 'only allows letters and underscores'
|
13
|
+
}
|
14
|
+
|
15
|
+
has_many :assignments, class_name: '::RoleAssignment', inverse_of: :role
|
16
|
+
has_many :actors, -> { distinct }, through: :assignments, source: :actor
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Authegy
|
4
|
+
# A `RoleAssignment` associates a `Person` to an optional "resource", and
|
5
|
+
# assigns a particular roleholds the "Profile" for a given User, but we can
|
6
|
+
# also have just Person profiles without a user, as is the case for
|
7
|
+
# "Board Members"
|
8
|
+
class RoleAssignment < ApplicationRecord
|
9
|
+
self.table_name = :role_assignments
|
10
|
+
self.abstract_class = true
|
11
|
+
|
12
|
+
belongs_to :actor, class_name: '::Person', foreign_key: :actor_id
|
13
|
+
belongs_to :role
|
14
|
+
belongs_to :resource, optional: true, polymorphic: true
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'devise/models/validatable_with_person_email'
|
4
|
+
require 'devise/models/database_authenticatable_with_person_email'
|
5
|
+
|
6
|
+
module Authegy
|
7
|
+
#= User
|
8
|
+
#
|
9
|
+
# Represents a person which is able to sign-in to the application.
|
10
|
+
# Users are intended for authentification, the actual profile sits in Person.
|
11
|
+
class User < ApplicationRecord
|
12
|
+
self.table_name = :users
|
13
|
+
self.abstract_class = true
|
14
|
+
|
15
|
+
devise :database_authenticatable_with_person_email,
|
16
|
+
:validatable_with_person_email
|
17
|
+
|
18
|
+
belongs_to :person, inverse_of: :user, foreign_key: :id
|
19
|
+
delegate :email, :email=, :name, to: :person, allow_nil: true
|
20
|
+
|
21
|
+
delegate :assigned_roles, :assign_role, :has_role?, :has_any_role?,
|
22
|
+
:remove_role, :role_assignments, to: :person
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
#= DatabaseAuthenticatableWithPersonEmail
|
4
|
+
#
|
5
|
+
# Overrides Devise::Models::DatabaseAuthenticatable, so but instead of
|
6
|
+
# expecting the `email` field to be in the authenticatable model, is located
|
7
|
+
# instead in the associated `Person` model
|
8
|
+
module DatabaseAuthenticatableWithPersonEmail
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
# Include the original module:
|
13
|
+
devise :database_authenticatable
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
Devise::Models.config self
|
18
|
+
|
19
|
+
# Override of
|
20
|
+
# Devise::Models::Authenticatable.find_first_by_auth_conditions:
|
21
|
+
def find_first_by_auth_conditions(tainted_conditions, opts={})
|
22
|
+
filter = devise_parameter_filter.filter(tainted_conditions).merge opts
|
23
|
+
person_filter = filter.extract! :email
|
24
|
+
matching_person_scope = Person.where person_filter
|
25
|
+
User.where(filter).joins(:person).merge(matching_person_scope).first
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
#= ValidatableWithPersonEmail
|
4
|
+
#
|
5
|
+
# A re-implementation of Devise::Models::Validatable, but instead of
|
6
|
+
# expecting the `email` field to be in the authenticatable model, is located
|
7
|
+
# instead in the `Person` associated model
|
8
|
+
module ValidatableWithPersonEmail
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
validates_presence_of :password, if: :password_required?
|
13
|
+
validates_confirmation_of :password, if: :password_required?
|
14
|
+
|
15
|
+
validates_length_of :password,
|
16
|
+
within: password_length,
|
17
|
+
allow_blank: true
|
18
|
+
|
19
|
+
validate :person_email_must_be_present
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
Devise::Models.config self, :email_regexp, :password_length
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
# Checks whether a password is needed or not. For validations only.
|
29
|
+
# Passwords are always required if it's a new record, or if the password
|
30
|
+
# or confirmation are being set somewhere.
|
31
|
+
def password_required?
|
32
|
+
!persisted? || !password.nil? || !password_confirmation.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
def person_email_must_be_present
|
36
|
+
return if person&.email.present?
|
37
|
+
errors.add :base, 'Person email must be present'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/base'
|
4
|
+
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
namespace 'authegy:install'
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
|
10
|
+
def generate_customized_devise_install
|
11
|
+
generate 'devise:install'
|
12
|
+
|
13
|
+
gsub_file 'config/initializers/devise.rb',
|
14
|
+
'config.sign_out_via = :delete',
|
15
|
+
'config.sign_out_via = %i[get delete]'
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_authegy_install
|
19
|
+
generate 'authegy:models People'
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_devise_routes
|
23
|
+
route <<~STRING
|
24
|
+
devise_for :users,
|
25
|
+
path: '/',
|
26
|
+
path_names: { sign_in: 'sign-in', sign_out: 'sign-out' }
|
27
|
+
STRING
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/active_record'
|
4
|
+
require 'generators/authegy/orm_helpers'
|
5
|
+
|
6
|
+
class ModelsGenerator < ActiveRecord::Generators::Base
|
7
|
+
namespace 'authegy:models'
|
8
|
+
include Authegy::Generators::OrmHelpers
|
9
|
+
source_root File.expand_path('templates', __dir__)
|
10
|
+
|
11
|
+
argument :attributes,
|
12
|
+
type: :array,
|
13
|
+
default: [],
|
14
|
+
banner: 'field:type field:type'
|
15
|
+
|
16
|
+
# class_option :primary_key_type, type: :string, desc: 'The type for primary key'
|
17
|
+
|
18
|
+
def copy_authegy_migration
|
19
|
+
# if (behavior == :invoke && model_exists?) || (behavior == :revoke && migration_exists?(table_name))
|
20
|
+
# migration_template "migration_existing.rb", "#{migration_path}/add_devise_to_#{table_name}.rb", migration_version: migration_version
|
21
|
+
# else
|
22
|
+
migration_template(
|
23
|
+
'models_migration.erb',
|
24
|
+
"#{migration_path}/create_authegy_model_tables.rb",
|
25
|
+
migration_version: migration_version
|
26
|
+
)
|
27
|
+
# end
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_app_models
|
31
|
+
copy_file 'person_model.rb', 'app/models/person.rb'
|
32
|
+
copy_file 'role_model.rb', 'app/models/role.rb'
|
33
|
+
copy_file 'user_model.rb', 'app/models/user.rb'
|
34
|
+
copy_file 'role_assignment_model.rb', 'app/models/role_assignment.rb'
|
35
|
+
end
|
36
|
+
|
37
|
+
def rails5_and_up?
|
38
|
+
Rails::VERSION::MAJOR >= 5
|
39
|
+
end
|
40
|
+
|
41
|
+
def migration_version
|
42
|
+
if rails5_and_up?
|
43
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Authegy
|
4
|
+
module Generators
|
5
|
+
module OrmHelpers
|
6
|
+
def model_contents
|
7
|
+
buffer = <<-CONTENT
|
8
|
+
# Include default devise modules. Others available are:
|
9
|
+
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
|
10
|
+
devise :database_authenticatable, :registerable,
|
11
|
+
:recoverable, :rememberable, :validatable
|
12
|
+
CONTENT
|
13
|
+
buffer
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def model_exists?
|
19
|
+
File.exist?(File.join(destination_root, model_path))
|
20
|
+
end
|
21
|
+
|
22
|
+
def migration_exists?(table_name)
|
23
|
+
Dir.glob("#{File.join(destination_root, migration_path)}/[0-9]*_*.rb").grep(/\d+_add_devise_to_#{table_name}.rb$/).first
|
24
|
+
end
|
25
|
+
|
26
|
+
def migration_path
|
27
|
+
if Rails.version >= '5.0.3'
|
28
|
+
db_migrate_path
|
29
|
+
else
|
30
|
+
@migration_path ||= File.join("db", "migrate")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def model_path
|
35
|
+
@model_path ||= File.join("app", "models", "#{file_path}.rb")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateAuthegyModelTables < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
def change
|
5
|
+
create_people_table
|
6
|
+
create_users_table
|
7
|
+
create_roles_table
|
8
|
+
create_role_assignments_table
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_people_table
|
12
|
+
create_table :people do |t|
|
13
|
+
t.string :first_name, null: false
|
14
|
+
t.string :last_name, null: false
|
15
|
+
t.string :email, index: { unique: true }
|
16
|
+
|
17
|
+
# Feel free to add additional fields, such as 'nickname', etc:
|
18
|
+
# t.string :phone
|
19
|
+
|
20
|
+
t.timestamps null: false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_users_table
|
25
|
+
create_table :users do |t|
|
26
|
+
## Database authenticatable
|
27
|
+
t.string :encrypted_password, null: false, default: ''
|
28
|
+
|
29
|
+
## Recoverable
|
30
|
+
t.string :reset_password_token, index: { unique: true }
|
31
|
+
t.datetime :reset_password_sent_at
|
32
|
+
|
33
|
+
## Rememberable
|
34
|
+
t.datetime :remember_created_at
|
35
|
+
|
36
|
+
## Trackable
|
37
|
+
# t.integer :sign_in_count, default: 0, null: false
|
38
|
+
# t.datetime :current_sign_in_at
|
39
|
+
# t.datetime :last_sign_in_at
|
40
|
+
# t.inet :current_sign_in_ip
|
41
|
+
# t.inet :last_sign_in_ip
|
42
|
+
|
43
|
+
## Confirmable
|
44
|
+
# t.string :confirmation_token, index: { unique: true }
|
45
|
+
# t.datetime :confirmed_at
|
46
|
+
# t.datetime :confirmation_sent_at
|
47
|
+
# t.string :unconfirmed_email # Only if using reconfirmable
|
48
|
+
|
49
|
+
## Lockable
|
50
|
+
# # Only if lock strategy is :failed_attempts:
|
51
|
+
# t.integer :failed_attempts, default: 0, null: false
|
52
|
+
# # Only if unlock strategy is :email or :both:
|
53
|
+
# t.string :unlock_token, index: { unique: true }
|
54
|
+
# t.datetime :locked_at
|
55
|
+
|
56
|
+
t.timestamps null: false
|
57
|
+
end
|
58
|
+
|
59
|
+
# The `users.id` column is actually a foreign key to the `people` table:
|
60
|
+
add_foreign_key :users, :people, column: :id
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_roles_table
|
64
|
+
create_table :roles do |t|
|
65
|
+
t.string :name, null: false, comment: 'Name of the role'
|
66
|
+
t.text :description, comment: 'Description of the role'
|
67
|
+
|
68
|
+
t.timestamps null: false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_role_assignments_table
|
73
|
+
create_table :role_assignments do |t|
|
74
|
+
t.references :actor, foreign_key: { to_table: :people }
|
75
|
+
|
76
|
+
t.references :role,
|
77
|
+
foreign_key: { to_table: :roles },
|
78
|
+
comment: 'The role assigned to the actor'
|
79
|
+
|
80
|
+
t.references :resource, polymorphic: true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Person holds the "Profile" for a given User, but we can also have just Person
|
4
|
+
# profiles without a user, as is the case for "Board Members"
|
5
|
+
class Person < Authegy::Person
|
6
|
+
# Authegy::Person already includes validations for the email field, and
|
7
|
+
# associations for :user, :role_assignments, :assigned_roles, and methods
|
8
|
+
# for authorization, such as :assign_role, :has_role?, etc.
|
9
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#= User
|
4
|
+
#
|
5
|
+
# Represents a person which is able to sign-in to the application.
|
6
|
+
# Users are intended for authentification, the actual profile sits in Person.
|
7
|
+
class User < Authegy::User
|
8
|
+
# Authegy::User class already includes associations to :person,
|
9
|
+
# and delegations to :person such as :email, :has_role?, etc.
|
10
|
+
|
11
|
+
# Include devise modules. Others available are:
|
12
|
+
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
|
13
|
+
devise :database_authenticatable_with_person_email, :registerable,
|
14
|
+
:recoverable, :rememberable, :validatable_with_person_email
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: authegy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Roberto Quintanilla
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: devise
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.6'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 4.6.1
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '4.6'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 4.6.1
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sqlite3
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.3.6
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.3.6
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: bundler
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '1.17'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '1.17'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rake
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '10.0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '10.0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '3.0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '3.0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: rspec-rails
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
description: Opinionated app strategy used for authentication & role-based authorization.
|
118
|
+
email:
|
119
|
+
- vov@icalialabs.com
|
120
|
+
executables: []
|
121
|
+
extensions: []
|
122
|
+
extra_rdoc_files: []
|
123
|
+
files:
|
124
|
+
- CHANGELOG.md
|
125
|
+
- README.md
|
126
|
+
- app/assets/config/authegy_manifest.js
|
127
|
+
- app/assets/javascripts/authegy/application.js
|
128
|
+
- app/assets/stylesheets/authegy/application.css
|
129
|
+
- app/controllers/authegy/application_controller.rb
|
130
|
+
- app/helpers/authegy/application_helper.rb
|
131
|
+
- app/jobs/authegy/application_job.rb
|
132
|
+
- app/mailers/authegy/application_mailer.rb
|
133
|
+
- app/models/authegy/application_record.rb
|
134
|
+
- app/views/layouts/authegy/application.html.erb
|
135
|
+
- lib/authegy.rb
|
136
|
+
- lib/authegy/authorizable.rb
|
137
|
+
- lib/authegy/controller_helpers.rb
|
138
|
+
- lib/authegy/engine.rb
|
139
|
+
- lib/authegy/models/person.rb
|
140
|
+
- lib/authegy/models/role.rb
|
141
|
+
- lib/authegy/models/role_assignment.rb
|
142
|
+
- lib/authegy/models/user.rb
|
143
|
+
- lib/authegy/version.rb
|
144
|
+
- lib/devise/models/database_authenticatable_with_person_email.rb
|
145
|
+
- lib/devise/models/validatable_with_person_email.rb
|
146
|
+
- lib/generators/authegy/USAGE
|
147
|
+
- lib/generators/authegy/install_generator.rb
|
148
|
+
- lib/generators/authegy/models_generator.rb
|
149
|
+
- lib/generators/authegy/orm_helpers.rb
|
150
|
+
- lib/generators/authegy/templates/models_migration.erb
|
151
|
+
- lib/generators/authegy/templates/person_model.rb
|
152
|
+
- lib/generators/authegy/templates/role_assignment_model.rb
|
153
|
+
- lib/generators/authegy/templates/role_model.rb
|
154
|
+
- lib/generators/authegy/templates/user_model.rb
|
155
|
+
- lib/tasks/authegy_tasks.rake
|
156
|
+
homepage: https://github.com/vovimayhem/authegy-gem
|
157
|
+
licenses:
|
158
|
+
- MIT
|
159
|
+
metadata:
|
160
|
+
allowed_push_host: https://rubygems.org
|
161
|
+
homepage_uri: https://github.com/vovimayhem/authegy-gem
|
162
|
+
source_code_uri: https://github.com/vovimayhem/authegy
|
163
|
+
changelog_uri: https://github.com/vovimayhem/authegy/blob/master/CHANGELOG.md
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - ">="
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
requirements: []
|
179
|
+
rubygems_version: 3.0.1
|
180
|
+
signing_key:
|
181
|
+
specification_version: 4
|
182
|
+
summary: Opinionated app strategy used for authentication & role-based authorization.
|
183
|
+
test_files: []
|