tachiban 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|