active_entry 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 15c793e52a2f7f0b43f1752bb61303f2fae758c763264fe3e73561ca3c272b8b
4
+ data.tar.gz: 49ba592be85bb9f3f1642d748e4cbc235b4f49461dca4483773fb1de85252028
5
+ SHA512:
6
+ metadata.gz: 1e009ca5bbd3b9c2d4153f96cf4dd864dd83196c317c276a7d2a71bde273325c6a59f2340e28ca6cadc83c4430da0fefa1f07846ffdd0d9e42409c2b91eab73e
7
+ data.tar.gz: 9e62985d0726b6323126b3929d7a3b9ad2d1d6d51e8488da8a6f7061b8c2d9efb94f284b260d69d344f0a8f140afa5b1428a4fb9c20d632a037542ca1d28da34
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2021 tobiasfeistmantl
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,182 @@
1
+ [<img src="active_entry_logo.png" alt="Active Entry Logo" width="250px"/>](https://github.com/TFM-Agency/active_entry)
2
+
3
+ # Active Entry - Simple and flexible authentication and authorization
4
+
5
+ Active Entry is a simple and secure authentication and authorization system for your Rails application, which lets you to authenticate and authorize directly in your controllers.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'active_entry'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install active_entry
22
+ ```
23
+
24
+ ## Usage
25
+ With Active Entry authentication and authorization is done in your Rails controllers. To enable authentication and authorization in one of your controllers, just add a before action for `authenticate!` and `authorize!` and the user has to authenticate and authorize on every call.
26
+ You probably want to control authentication and authorization for every controller action you have in your app. To enable this, just add the before action to the `ApplicationController`.
27
+
28
+ ```ruby
29
+ class ApplicationController < ActionController::Base
30
+ before_action :authenticate!, :authorize!
31
+ # ...
32
+ end
33
+ ```
34
+
35
+ If you try to open a page, you will get an `ActiveEntry::AuthenticationNotPerformedError` or `ActiveEntry::AuthorizationNotPerformedError`. This means that you have to instruct Active Entry when a user is authenticated/authorized and when not.
36
+ You can do this by defining the methods `authenticated?` and `authorized?` in your controller.
37
+
38
+ ```ruby
39
+ class DashboardController < ApplicationController
40
+ # Actions ...
41
+
42
+ private
43
+
44
+ def authenticated?
45
+ return true if user_signed_in?
46
+ end
47
+
48
+ def authorized?
49
+ return true if current_user.admin?
50
+ end
51
+ end
52
+ ```
53
+
54
+ Active Entry expects boolean return values from `authenticated?` and `authorized?`. `true` signals successful authentication/authorization, everything else not.
55
+
56
+ If the user is signed in, he is authenticated and authorized if he is an admin, otherwise an `ActiveEntry::NotAuthenticatedError` or `ActiveEntry::NotAuthorizedError` will be raised.
57
+ Now you just have to catch this error and react accordingly. Rails has the convinient `rescue_from` for that.
58
+
59
+ ```ruby
60
+ class ApplicationController < ActionController::Base
61
+ # ...
62
+
63
+ rescue_from ActiveEntry::NotAuthenticatedError, with: :not_authenticated
64
+ rescue_from ActiveEntry::NotAuthorizedError, with: :not_authorized
65
+
66
+ private
67
+
68
+ def not_authenticated
69
+ flash[:danger] = "You are not authenticated!"
70
+ redirect_to login_path
71
+ end
72
+
73
+ def not_authorized
74
+ flash[:danger] = "You are not authorized to call this action!"
75
+ redirect_to root_path
76
+ end
77
+ end
78
+ ```
79
+
80
+ In this example above, the user will be redirected with a flash message. But you can do whatever you want. For example logging.
81
+
82
+ Active Entry also has a few helper methods which help you to distinguish between RESTful controller actions.
83
+
84
+ The following methods are available:
85
+
86
+ * `read_action?` - If the called action just read. Actions: `index`, `show`
87
+ * `write_action?` - If the called action writes something. Actions: `new`, `create`, `edit`, `update`, `destroy`
88
+ * `change_action?` - If something will be updated or destroyed. Actions: `edit`, `update`, `destroy`
89
+ * `create_action?` - If something will be created. Actions: `new`, `create`
90
+ * `update_action?` - If something will be updated. Actions: `edit`, `update`
91
+ * `destroy_action?` - If something will be destroyed. Action: `destroy`
92
+
93
+ So you can for example do:
94
+
95
+ ```ruby
96
+ def authorized?
97
+ return true if read_action? # Everybody is authorized to call read actions
98
+
99
+ if write_action?
100
+ return true if admin_signed_in? # Just admins are allowed to call write actions
101
+ end
102
+ end
103
+ ```
104
+
105
+ This is pretty much everything you have to do for basic authentication or authorization!
106
+
107
+ ## Pass a custom error hash
108
+ You can pass an error hash to the exception and use this in your rescue method:
109
+
110
+ ```ruby
111
+ class ApplicationController < ActionController::Base
112
+ before_action :authenticate!, :authorize!
113
+
114
+ # ...
115
+
116
+ rescue_from ActiveEntry::NotAuthenticatedError, with: :not_authenticated
117
+ rescue_from ActiveEntry::NotAuthorizedError, with: :not_authorized
118
+
119
+ private
120
+
121
+ def not_authenticated(exception)
122
+ flash[:danger] = "You are not authenticated! Code: #{exception.error[:code]}"
123
+ redirect_to root_path
124
+ end
125
+
126
+ def not_authorized(exception)
127
+ flash[:danger] = "You are not authorized to call this action! Code: #{exception.error[:code]}"
128
+ redirect_to root_path
129
+ end
130
+
131
+ def authenticated?(error)
132
+ error[:code] = "ERROR"
133
+
134
+ return true if user_signed_in?
135
+ end
136
+
137
+ def authorized?(error)
138
+ error[:code] = "ERROR"
139
+
140
+ return true if read_action? # Everybody is authorized to call read actions
141
+
142
+ if write_action?
143
+ return true if admin_signed_in? # Just admins are allowed to call write actions
144
+ end
145
+ end
146
+ end
147
+ ```
148
+
149
+ ## Known Issues
150
+ The authentication/authorization is done in a before action. These Rails controller before callbacks are done in defined order. If you set an instance variable which is needed in the `authenticated?` or `authorized?` method, you have to call the before action after the other method again.
151
+
152
+ For example if you set `@user` in your controller in the `set_user` before action and you want to use the variable in `authorized?` action, you have to add the `authenticate!` or `authorize!` method after the `set_user` again, otherwise `@user` won't be available in `authenticate!` or `authorized?` yet.
153
+
154
+ ```ruby
155
+ class UsersController < ApplicationController
156
+ before_action :set_user
157
+ before_action :authenticate!, :authorize!
158
+
159
+ def show
160
+ end
161
+
162
+ private
163
+
164
+ def authenticated?
165
+ return true if user_signed_in?
166
+ end
167
+
168
+ def authorized?
169
+ return true if current_user == @user
170
+ end
171
+ end
172
+ ```
173
+
174
+ ## Contributing
175
+ Create pull requests on Github and help us to improve this Gem. There are some guidelines to follow:
176
+
177
+ * Follow the conventions
178
+ * Test all your implementations
179
+ * Document methods that aren't self-explaining (we are using [YARD](http://yardoc.org/))
180
+
181
+ ## License
182
+ 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,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,54 @@
1
+ require "active_entry/version"
2
+ require "active_entry/errors"
3
+ require "active_entry/controller_methods"
4
+ require "active_entry/railtie" if defined? Rails::Railtie
5
+
6
+ module ActiveEntry
7
+ # Authenticates the user
8
+ def authenticate!
9
+ # Raise an error if the #authenticate? action isn't defined.
10
+ #
11
+ # This ensures that you actually do authentication in your controller.
12
+ raise ActiveEntry::AuthenticationNotPerformedError unless defined?(authenticated?)
13
+
14
+ error = {}
15
+ is_authenticated = nil
16
+
17
+ if method(:authenticated?).arity > 0
18
+ is_authenticated = authenticated?(error)
19
+ else
20
+ is_authenticated = authenticated?
21
+ end
22
+
23
+ # If the authenticated? method returns not true
24
+ # it raises the ActiveEntry::NotAuthenticatedError.
25
+ #
26
+ # Use the .rescue_from method from ActionController::Base
27
+ # to catch the exception and show the user a proper error message.
28
+ raise ActiveEntry::NotAuthenticatedError.new(error) unless is_authenticated == true
29
+ end
30
+
31
+ # Authorizes the user.
32
+ def authorize!
33
+ # Raise an error if the #authorize? action isn't defined.
34
+ #
35
+ # This ensures that you actually do authorization in your controller.
36
+ raise ActiveEntry::AuthorizationNotPerformedError unless defined?(authorized?)
37
+
38
+ error = {}
39
+ is_authorized = nil
40
+
41
+ if method(:authorized?).arity > 0
42
+ is_authorized = authorized?(error)
43
+ else
44
+ is_authorized = authorized?
45
+ end
46
+
47
+ # If the authorized? method does not return true
48
+ # it raises the ActiveEntry::NotAuthorizedError
49
+ #
50
+ # Use the .rescue_from method from ActionController::Base
51
+ # to catch the exception and show the user a proper error message.
52
+ raise ActiveEntry::NotAuthorizedError.new(error) unless is_authorized == true
53
+ end
54
+ end
@@ -0,0 +1,83 @@
1
+ # @author Tobias Feistmantl
2
+ #
3
+ # Helper methods for your controller
4
+ # to identify RESTful actions.
5
+ module ActiveEntry
6
+ # @return [Boolean]
7
+ # True if the called action
8
+ # is a only-read action.
9
+ def read_action?
10
+ action_name == 'index' ||
11
+ action_name == 'show'
12
+ end
13
+
14
+ # @return [Boolean]
15
+ # True if the called action
16
+ # is a write action.
17
+ def write_action?
18
+ action_name == 'new' ||
19
+ action_name == 'create' ||
20
+ action_name == 'edit' ||
21
+ action_name == 'update' ||
22
+ action_name == 'destroy'
23
+ end
24
+
25
+ # @return [Boolean]
26
+ # True if the called action
27
+ # is a change action.
28
+ def change_action?
29
+ action_name == 'edit' ||
30
+ action_name == 'update' ||
31
+ action_name == 'destroy'
32
+ end
33
+
34
+ # @return [Boolean]
35
+ # True if the called action
36
+ # is the index action.
37
+ def index_action?
38
+ action_name == 'index'
39
+ end
40
+
41
+ # @return [Boolean]
42
+ # True if the called action
43
+ # is the show action.
44
+ def show_action?
45
+ action_name == 'show'
46
+ end
47
+
48
+ # @note
49
+ # Also true for the pseudo
50
+ # update action `new`.
51
+ #
52
+ # @note
53
+ # Only true for create methods
54
+ # such as new and create.
55
+ #
56
+ # @return [Boolean]
57
+ # True if the called action
58
+ # is a create action.
59
+ def create_action?
60
+ action_name == 'new' ||
61
+ action_name == 'create'
62
+ end
63
+
64
+ # @note
65
+ # Also true for the pseudo
66
+ # update action `edit`.
67
+ #
68
+ # @return [Boolean]
69
+ # True if the called action
70
+ # is a update action.
71
+ def update_action?
72
+ action_name == 'edit' ||
73
+ action_name == 'update'
74
+ end
75
+
76
+ # @return [Boolean]
77
+ # True if it's a destroy action.
78
+ def destroy_action?
79
+ action_name == 'destroy'
80
+ end
81
+
82
+ alias delete_action? destroy_action?
83
+ end
@@ -0,0 +1,66 @@
1
+ # @author Tobias Feistmantl
2
+ module ActiveEntry
3
+ # Generic authorization error.
4
+ # Other, more specific, errors inherit from this one.
5
+ #
6
+ # @raise [AuthorizationError]
7
+ # if something generic is happening.
8
+ class AuthorizationError < StandardError
9
+ end
10
+
11
+ # Error for controllers in which authorization isn't handled.
12
+ #
13
+ # @raise [AuthorizationNotPerformedError]
14
+ # if the #authorized? method isn't defined
15
+ # in the controller class.
16
+ class AuthorizationNotPerformedError < AuthorizationError
17
+ end
18
+
19
+ # Error if user unauthorized.
20
+ #
21
+ # @raise [NotAuthorizedError]
22
+ # if authorized? isn't returning true.
23
+ #
24
+ # @note
25
+ # Should always be called at the end
26
+ # of the #authorize! method.
27
+ class NotAuthorizedError < AuthorizationError
28
+ attr_reader :error
29
+
30
+ def initialize(error={})
31
+ @error = error
32
+ end
33
+ end
34
+
35
+
36
+ # Base class for authentication errors.
37
+ #
38
+ # @raise [AuthenticationError]
39
+ # if something generic happens.
40
+ class AuthenticationError < StandardError
41
+ end
42
+
43
+ # Error for controllers in which authentication isn't handled.
44
+ #
45
+ # @raise [AuthenticationNotPerformedError]
46
+ # if the #authenticated? method isn't defined
47
+ # in the controller class.
48
+ class AuthenticationNotPerformedError < AuthenticationError
49
+ end
50
+
51
+ # Error if user not authenticated
52
+ #
53
+ # @raise [NotAuthenticatedError]
54
+ # if authenticated? isn't returning true.
55
+ #
56
+ # @note
57
+ # Should always be called at the end
58
+ # of the #authenticate! method.
59
+ class NotAuthenticatedError < AuthenticationError
60
+ attr_reader :error
61
+
62
+ def initialize(error={})
63
+ @error = error
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveEntry
2
+ class Railtie < ::Rails::Railtie
3
+ initializer 'active_entry.include_in_action_controller' do
4
+ ActiveSupport.on_load :action_controller do
5
+ ::ActionController::Base.include(ActiveEntry)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveEntry
2
+ VERSION = '1.0.1'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :active_entry do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_entry
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - TFM Agency GmbH
8
+ - Tobias Feistmantl
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-03-02 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: 4.0.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 4.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec-rails
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: guard-rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: pry
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ description: An easy and flexible access control system. No need for policies, abilities,
71
+ etc. Do authentication and authorization directly in your controller.
72
+ email:
73
+ - hello@tfm.agency
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - MIT-LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - lib/active_entry.rb
82
+ - lib/active_entry/controller_methods.rb
83
+ - lib/active_entry/errors.rb
84
+ - lib/active_entry/railtie.rb
85
+ - lib/active_entry/version.rb
86
+ - lib/tasks/active_entry_tasks.rake
87
+ homepage: https://github.com/TFM-Agency/active_entry
88
+ licenses:
89
+ - MIT
90
+ metadata:
91
+ homepage_uri: https://github.com/TFM-Agency/active_entry
92
+ source_code_uri: https://github.com/TFM-Agency/active_entry
93
+ changelog_uri: https://github.com/TFM-Agency/active_entry/commits/main
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubygems_version: 3.2.3
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: An easy and flexible access control system for your Rails app.
113
+ test_files: []