tachiban 0.6.1 → 0.7.0
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/README.md +25 -52
- data/bin/tachiban +0 -1
- data/lib/tachiban.rb +16 -32
- data/lib/tachiban/version.rb +1 -1
- metadata +2 -4
- data/lib/tachiban/commands/commands.rb +0 -45
- data/lib/tachiban/policy_generator/policy_generator.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a4772cbc2387fbc462f6fd7f0bb3e1738521e1ede9a4d8b02e6cda05ab9ffc1
|
4
|
+
data.tar.gz: 16069ee6e897992462ce538ec514fdeef1c2798014f573265e293e15603f8b42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8d446ac3dd3f8762154859b8a32369d2e92a8eeb570a05bffdb8bc9674ed1676d288c8e71a1666887beda650e91db0c98becf306db4f097ff9ff00f1defac60
|
7
|
+
data.tar.gz: 4745b414ecf91bb84564b54febbab5febcd1c40d0e0df454140286b454b9af5938546a91da8f3f17ae7612a598eeada823f5e8616d8fc8377a90383089c36db6
|
data/README.md
CHANGED
@@ -10,11 +10,7 @@ offers the following functionalities (with methods listed below
|
|
10
10
|
- Authentication
|
11
11
|
- Session handling
|
12
12
|
- Password reset
|
13
|
-
- Authorization
|
14
|
-
|
15
|
-
The Tachiban logic (apart from the Authorization) and code were extracted from a Hanami based web app using
|
16
|
-
Hanami::Model and was also used in a Camping based web app using Active Record.
|
17
|
-
|
13
|
+
- Authorization has been moved to [Rokku](https://github.com/sebastjan-hribar/rokku)
|
18
14
|
|
19
15
|
## Installation
|
20
16
|
|
@@ -48,22 +44,16 @@ end
|
|
48
44
|
Prior to logging in or authenticating the user, retrieve the entity from the
|
49
45
|
database and assign it to the instance variable of `@user`.
|
50
46
|
|
51
|
-
|
52
|
-
**token** and **password_reset_sent_at (set as `Time.now`)**. The token can be used to compose
|
53
|
-
the password reset url and to later retrieve the correct user from
|
54
|
-
the database when the user visits the password reset url.
|
55
|
-
|
56
|
-
The **password_reset_sent_at** can be used to check the reset link validity.
|
47
|
+
In addition to that, the user entity must have the following attributes:
|
57
48
|
|
58
|
-
|
49
|
+
* **token** (used to compose the password reset url and get the user from the database)
|
50
|
+
* **password_reset_sent_at** (set as `Time.now` to check the reset link validity)
|
51
|
+
* **hashed_pass** (to hold the generated hashed password)
|
59
52
|
|
60
53
|
|
61
54
|
### Usage
|
62
55
|
|
63
56
|
#### Signup
|
64
|
-
The entity for which authentication is used must have the
|
65
|
-
attribute `hashed_pass` to hold the generated hashed password.
|
66
|
-
|
67
57
|
To create a user with a hashed password use the `hashed_password(password)`
|
68
58
|
method for the password and store it as the user's attribute `hashed_pass`.
|
69
59
|
|
@@ -81,14 +71,14 @@ def call(params)
|
|
81
71
|
end
|
82
72
|
```
|
83
73
|
|
84
|
-
####
|
74
|
+
#### Authentication and login
|
85
75
|
To authenticate a user use the `authenticated?(input_password)` method and log
|
86
76
|
them in with the `login` method. Authentication is successful if the user exists and passwords match.
|
87
77
|
|
88
|
-
The user is logged in by setting the user object as the `session[:current_user]`.
|
78
|
+
The user is logged in by setting the user object ID as the `session[:current_user]`.
|
89
79
|
After the user is logged in the session start time is defined as
|
90
|
-
`session[:session_start_time] = Time.now`. A flash message is also
|
91
|
-
assigned as
|
80
|
+
`session[:session_start_time] = Time.now`. A default flash message is also
|
81
|
+
assigned as 'You have been successfully logged in.'.
|
92
82
|
|
93
83
|
The `session[:session_start_time]` is then used by the `session_expired?`
|
94
84
|
method to determine whether the session has expired or not.
|
@@ -101,11 +91,9 @@ email = params[:entity_session][:email]
|
|
101
91
|
password = params[:entity_session][:password]
|
102
92
|
|
103
93
|
@user = EntityRepository.new.find_by_email(email)
|
104
|
-
login
|
94
|
+
login if authenticated?(password)
|
105
95
|
```
|
106
96
|
|
107
|
-
|
108
|
-
#### Authentication
|
109
97
|
To check whether the user is logged in use the `check_for_logged_in_user` method.
|
110
98
|
If the user is not logged in the `logout` method takes over.
|
111
99
|
|
@@ -116,10 +104,10 @@ expired and then restarts the session start time if the session
|
|
116
104
|
is still valid or proceeds with the following if the session
|
117
105
|
has expired:
|
118
106
|
|
119
|
-
- setting the `session[:current_user]` to `nil
|
120
|
-
- a flash message is set: `flash[:failed_notice] = "Your session has expired"
|
107
|
+
- setting the `session[:current_user]` to `nil`,
|
108
|
+
- a flash message is set: `flash[:failed_notice] = "Your session has expired"`,
|
121
109
|
- redirects to the `routes.root_path` which can be overwritten by assigning
|
122
|
-
a different url to @redirect_url
|
110
|
+
a different url to @redirect_url.
|
123
111
|
|
124
112
|
|
125
113
|
The `session_expired?` method compares the session start time
|
@@ -132,7 +120,7 @@ by default, but can be overwritten) with the current time.
|
|
132
120
|
if session_expired?
|
133
121
|
@redirect_url ||= routes.root_path
|
134
122
|
session[:current_user] = nil
|
135
|
-
flash[:failed_notice] = "Your session has expired"
|
123
|
+
flash[:failed_notice] = "Your session has expired."
|
136
124
|
redirect_to @redirect_url
|
137
125
|
else
|
138
126
|
restart_session_counter
|
@@ -189,37 +177,26 @@ password_reset_url_valid?(link_validity)
|
|
189
177
|
```
|
190
178
|
|
191
179
|
|
192
|
-
|
193
|
-
Authorization support was setup as inspired by [this blog post](http://billpatrianakos.me/blog/2013/10/22/authorize-users-based-on-roles-and-permissions-without-a-gem/).
|
194
|
-
|
195
|
-
Authorization features support the generation of policy files for each controller where authorized roles are specified for each action.
|
196
|
-
|
197
|
-
```ruby
|
198
|
-
tachiban -n mightyPoster -p post
|
199
|
-
```
|
200
|
-
The above CLI command will generate a policy file for the application mightyPoster (not the project) and the controller post. The file will be generated as `myProject/lib/mightyPoster/policies/PostPolicy.rb`
|
201
|
-
|
202
|
-
Each application would have its own `app/policies` folders.
|
180
|
+
### ToDo
|
203
181
|
|
204
|
-
|
182
|
+
- Add full Hanami app for testing purposes.
|
205
183
|
|
206
|
-
|
184
|
+
### Changelog
|
207
185
|
|
208
|
-
|
186
|
+
#### 0.7.0
|
209
187
|
|
210
|
-
|
211
|
-
|
212
|
-
```
|
188
|
+
Authorization was moved to a separate gem [Rokku](https://github.com/sebastjan-hribar/rokku).
|
189
|
+
Readme update.
|
213
190
|
|
191
|
+
Method: `Tachiban::login`
|
192
|
+
<br>Change:
|
193
|
+
Default flash message and redirect url provided.
|
214
194
|
|
215
|
-
### ToDo
|
216
195
|
|
217
|
-
|
218
|
-
- Add generators for adding authorization rules to existing policies.
|
219
|
-
- Add generators for entities with required attributes.
|
196
|
+
#### 0.6.1
|
220
197
|
|
198
|
+
Dependency change for **rake** to ">= 12.3.3".
|
221
199
|
|
222
|
-
### Changelog
|
223
200
|
|
224
201
|
#### 0.6.0
|
225
202
|
|
@@ -231,10 +208,6 @@ Method: `Tachiban::logout`
|
|
231
208
|
<br>Change:
|
232
209
|
Added `session.clear` to remove any other values upon logout.
|
233
210
|
|
234
|
-
#### 0.6.1
|
235
|
-
|
236
|
-
Dependency change for **rake** to ">= 12.3.3".
|
237
|
-
|
238
211
|
|
239
212
|
|
240
213
|
## Development
|
data/bin/tachiban
CHANGED
data/lib/tachiban.rb
CHANGED
@@ -5,7 +5,6 @@ require 'hanami/action/session'
|
|
5
5
|
|
6
6
|
module Hanami
|
7
7
|
module Tachiban
|
8
|
-
|
9
8
|
private
|
10
9
|
|
11
10
|
# ### Signup ###
|
@@ -19,7 +18,6 @@ private
|
|
19
18
|
BCrypt::Password.create(password)
|
20
19
|
end
|
21
20
|
|
22
|
-
|
23
21
|
# ### Login ###
|
24
22
|
|
25
23
|
# The authenticated? method returns true if the the following criteria
|
@@ -31,7 +29,6 @@ private
|
|
31
29
|
@user && BCrypt::Password.new(@user.hashed_pass) == input_pass
|
32
30
|
end
|
33
31
|
|
34
|
-
|
35
32
|
# The login method can be used in combination with the authenticated? method to
|
36
33
|
# log the user in if the authenticated? method returns true. The user is
|
37
34
|
# logged in by setting the user object id as the session[:current_user].
|
@@ -39,28 +36,34 @@ private
|
|
39
36
|
# by the session_expired? method to determine whether the session has
|
40
37
|
# expired or not.
|
41
38
|
|
39
|
+
# There are two defualt values set: one for flash message and
|
40
|
+
# the other for redirect url. Both can be overwritten by assigning
|
41
|
+
# new values for @flash_message and @login_redirect_url.
|
42
|
+
|
42
43
|
# Example:
|
43
44
|
# login if authenticated?(input_pass)
|
44
45
|
|
45
|
-
def login
|
46
|
+
def login
|
46
47
|
session[:current_user] = @user.id
|
47
48
|
session[:session_start_time] = Time.now
|
48
|
-
|
49
|
+
@flash_message ||= 'You have been successfully logged in.'
|
50
|
+
flash[:success_notice] = @flash_message
|
51
|
+
@login_redirect_url ||= routes.root_path
|
52
|
+
redirect_to @login_redirect_url
|
49
53
|
end
|
50
54
|
|
51
|
-
|
52
55
|
# The logout method sets the current user in the session to nil
|
53
|
-
# and performs a redirect to the
|
54
|
-
#
|
56
|
+
# and performs a redirect to the redirect_url which is set to
|
57
|
+
# /login, but can be overwritten as needed with a specific url
|
58
|
+
# by setting a new value for @logout_redirect_url.
|
55
59
|
|
56
60
|
def logout
|
57
61
|
session[:current_user] = nil
|
58
62
|
session.clear
|
59
|
-
@
|
60
|
-
redirect_to @
|
63
|
+
@logout_redirect_url ||= '/login'
|
64
|
+
redirect_to @logout_redirect_url
|
61
65
|
end
|
62
66
|
|
63
|
-
|
64
67
|
# ### Authentication ###
|
65
68
|
|
66
69
|
# The check_for_logged_in_user method can be used to check for each
|
@@ -68,10 +71,9 @@ private
|
|
68
71
|
# the logout method takes over.
|
69
72
|
|
70
73
|
def check_for_logged_in_user
|
71
|
-
|
74
|
+
logout unless session[:current_user]
|
72
75
|
end
|
73
76
|
|
74
|
-
|
75
77
|
# ### Session handling ###
|
76
78
|
|
77
79
|
# Session handling includes methods session_expired?,
|
@@ -88,7 +90,6 @@ private
|
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
91
|
-
|
92
93
|
# The restart_session_counter method resets the session start time to
|
93
94
|
# Time.now. It's used in the handle session method.
|
94
95
|
|
@@ -96,7 +97,6 @@ private
|
|
96
97
|
session[:session_start_time] = Time.now
|
97
98
|
end
|
98
99
|
|
99
|
-
|
100
100
|
# The handle_session method is used to handle the incoming requests
|
101
101
|
# based on the the session expiration. If the session has expired the
|
102
102
|
# session user is set to nil, a flash message of "Your session has expired"
|
@@ -110,16 +110,14 @@ private
|
|
110
110
|
if session_expired?
|
111
111
|
@redirect_url ||= routes.root_path
|
112
112
|
session[:current_user] = nil
|
113
|
-
flash[:failed_notice] =
|
113
|
+
flash[:failed_notice] = 'Your session has expired.'
|
114
114
|
redirect_to @redirect_url
|
115
115
|
else
|
116
116
|
restart_session_counter
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
|
121
120
|
# ### Password reset ###
|
122
|
-
|
123
121
|
def token
|
124
122
|
SecureRandom.urlsafe_base64
|
125
123
|
end
|
@@ -137,20 +135,6 @@ private
|
|
137
135
|
def password_reset_url_valid?(link_validity)
|
138
136
|
Time.now > @user.password_reset_sent_at + link_validity
|
139
137
|
end
|
140
|
-
|
141
|
-
|
142
|
-
# ### Authorization ###
|
143
|
-
# The authorized? method checks if the specified user has the required role
|
144
|
-
# and permission to access the action. It returns true or false and
|
145
|
-
# provides the basis for further actions in either case.
|
146
|
-
#
|
147
|
-
# Example: redirect_to "/" unless authorized?
|
148
|
-
|
149
|
-
def authorized?(controller, role, action)
|
150
|
-
Object.const_get(controller.downcase.capitalize + "Policy").new(role).send("#{action.downcase}?")
|
151
|
-
end
|
152
|
-
|
153
|
-
|
154
138
|
end
|
155
139
|
end
|
156
140
|
|
data/lib/tachiban/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tachiban
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastjan Hribar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -191,8 +191,6 @@ files:
|
|
191
191
|
- bin/setup
|
192
192
|
- bin/tachiban
|
193
193
|
- lib/tachiban.rb
|
194
|
-
- lib/tachiban/commands/commands.rb
|
195
|
-
- lib/tachiban/policy_generator/policy_generator.rb
|
196
194
|
- lib/tachiban/version.rb
|
197
195
|
- tachiban.gemspec
|
198
196
|
homepage: https://github.com/sebastjan-hribar/tachiban
|
@@ -1,45 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'optparse'
|
3
|
-
require_relative "../policy_generator/policy_generator.rb"
|
4
|
-
|
5
|
-
|
6
|
-
options = {}
|
7
|
-
optparse = OptionParser.new do |opts|
|
8
|
-
opts.banner = "\nHanami authorization policy generator
|
9
|
-
Usage: tachiban -n myapp -p user
|
10
|
-
Flags:
|
11
|
-
\n"
|
12
|
-
|
13
|
-
opts.on("-n", "--app_name APP", "Specify the application name for the policy") do |app_name|
|
14
|
-
options[:app_name] = app_name
|
15
|
-
end
|
16
|
-
|
17
|
-
opts.on("-p", "--policy POLICY", "Specify the policy name") do |policy|
|
18
|
-
options[:policy] = policy
|
19
|
-
end
|
20
|
-
|
21
|
-
opts.on("-h", "--help", "Displays help") do
|
22
|
-
puts opts
|
23
|
-
exit
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
begin
|
30
|
-
optparse.parse!
|
31
|
-
puts "Add flag -h or --help to see usage instructions." if options.empty?
|
32
|
-
mandatory = [:app_name, :policy]
|
33
|
-
missing = mandatory.select{ |arg| options[arg].nil? }
|
34
|
-
unless missing.empty?
|
35
|
-
raise OptionParser::MissingArgument.new(missing.join(', '))
|
36
|
-
end
|
37
|
-
|
38
|
-
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
|
39
|
-
puts $!.to_s
|
40
|
-
puts optparse
|
41
|
-
exit
|
42
|
-
end
|
43
|
-
|
44
|
-
puts "Performing task with options: #{options.inspect}"
|
45
|
-
generate_policy("#{options[:app_name]}", "#{options[:policy]}") if options[:policy]
|
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
|
-
# The generate_policy method creates the policy file for specified
|
4
|
-
# application and controller. By default all actions to check against
|
5
|
-
# are commented out.
|
6
|
-
# Uncomment the needed actions and define appropriate user role.
|
7
|
-
|
8
|
-
def generate_policy(app_name, controller_name)
|
9
|
-
app_name = app_name
|
10
|
-
controller = controller_name.downcase.capitalize
|
11
|
-
policy_txt = <<-TXT
|
12
|
-
class #{controller}Policy
|
13
|
-
def initialize(role)
|
14
|
-
@user_role = role
|
15
|
-
|
16
|
-
# Uncomment the required roles and add the
|
17
|
-
# appropriate user role to the @authorized_roles* array.
|
18
|
-
|
19
|
-
# @authorized_roles_for_new = []
|
20
|
-
# @authorized_roles_for_create = []
|
21
|
-
# @authorized_roles_for_show = []
|
22
|
-
# @authorized_roles_for_index = []
|
23
|
-
# @authorized_roles_for_edit = []
|
24
|
-
# @authorized_roles_for_update = []
|
25
|
-
# @authorized_roles_for_destroy = []
|
26
|
-
end
|
27
|
-
|
28
|
-
def new?
|
29
|
-
@authorized_roles_for_new.include? @user_role
|
30
|
-
end
|
31
|
-
def create?
|
32
|
-
@authorized_roles_for_create.include? @user_role
|
33
|
-
end
|
34
|
-
def show?
|
35
|
-
@authorized_roles_for_show.include? @user_role
|
36
|
-
end
|
37
|
-
def index?
|
38
|
-
@authorized_roles_for_index.include? @user_role
|
39
|
-
end
|
40
|
-
def edit?
|
41
|
-
@authorized_roles_for_edit.include? @user_role
|
42
|
-
end
|
43
|
-
def update?
|
44
|
-
@authorized_roles_for_update.include? @user_role
|
45
|
-
end
|
46
|
-
def destroy?
|
47
|
-
@authorized_roles_for_destroy.include? @user_role
|
48
|
-
end
|
49
|
-
end
|
50
|
-
TXT
|
51
|
-
|
52
|
-
|
53
|
-
FileUtils.mkdir_p "lib/#{app_name}/policies" unless File.directory?("lib/#{app_name}/policies")
|
54
|
-
unless File.file?("lib/#{app_name}/policies/#{controller}Policy.rb")
|
55
|
-
File.open("lib/#{app_name}/policies/#{controller}Policy.rb", 'w') { |file| file.write(policy_txt) }
|
56
|
-
end
|
57
|
-
puts("Generated policy: lib/#{app_name}/policies/#{controller}Policy.rb") if File.file?("lib/#{app_name}/policies/#{controller}Policy.rb")
|
58
|
-
end
|