active_entry 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []