tachiban 0.5.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 32f1f2b6604c7cda5393b06aad44f4ea84397a0d
4
- data.tar.gz: 6e6dbbb843fae38ed80dc10034071da0b669d3ef
2
+ SHA256:
3
+ metadata.gz: d18cad68d32567d0d583c417d817bd6980861ad662a505afd97cdfefe1c71f09
4
+ data.tar.gz: 720f7cb6014086b2de126283248ed728fabf003a9aa76772798b4e9ee3fbef33
5
5
  SHA512:
6
- metadata.gz: ee08ab9357babdfef72ad367eb31f2815a1dbfffed18d2c0e526b0d9b411edee1bfc1124d5cd02052677b08cd966a4e114ac55365fa9fd2d30440e72ed0edc7b
7
- data.tar.gz: 98e960466e21300d6973b405d493ecba1cb691a58e85296775468390a0c9acebe678cd8ce31665071342c025b5ecf731fbcf1b839f75b9a6283f009a427c2230
6
+ metadata.gz: bb298b0167b10f277c44ef4383c5d28e2e231e1a3ea731aca592c662afca362a42bbc25e55a854c1c330fef750b9d641ec26031a5a8cc412e312168f02ca86c1
7
+ data.tar.gz: cde4bc49bbef7f438732aff48502daabd750862a8fcf9d1feea9b5495e49e0f45b09952a292ef0ac105467981ec207ea186e3e36728be509528a271ad905718e
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *.gem
data/.travis.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.1
4
- before_install: gem install bundler -v 1.11.2
3
+ - 2.5.1
4
+ before_install: gem install bundler -v 2.0.2
data/CODE_OF_CONDUCT.md CHANGED
File without changes
data/Gemfile CHANGED
File without changes
data/LICENSE.txt CHANGED
File without changes
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Tachiban
2
2
 
3
- [![Join the chat at https://gitter.im/sebastjan-hribar/tachiban](https://badges.gitter.im/sebastjan-hribar/tachiban.svg)](https://gitter.im/sebastjan-hribar/tachiban?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Gem Version](https://badge.fury.io/rb/tachiban.svg)](https://badge.fury.io/rb/tachiban)
3
+ [![Join the chat at https://gitter.im/sebastjan-hribar/tachiban](https://badges.gitter.im/sebastjan-hribar/tachiban.svg)](https://gitter.im/sebastjan-hribar/tachiban?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Gem Version](https://badge.fury.io/rb/tachiban.svg)](https://badge.fury.io/rb/tachiban) [![Build Status](https://travis-ci.org/sebastjan-hribar/tachiban.svg?branch=master)](https://travis-ci.org/sebastjan-hribar/tachiban)
4
4
 
5
5
  Tachiban (立ち番 - standing watch) provides simple authentication system for [Hanami web applications](http://hanamirb.org/) by using bcrypt for password hashing and
6
6
  offers the following functionalities (with methods listed below
@@ -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
 
@@ -44,26 +40,20 @@ end
44
40
 
45
41
  ## Usage
46
42
 
47
- #### Prerequisites
43
+ ### Prerequisites
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
- The password reset methods require the user entity to have the following attributes:
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.
57
-
58
- The only prerequisite for the authorization is the attribute of **role** for the user entity.
47
+ In addition to that, the user entity must have the following attributes:
59
48
 
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)
60
52
 
61
- #### Usage
62
53
 
63
- ###### Signup
64
- The entity for which authentication is used must have the
65
- attribute `hashed_pass` to hold the generated hashed password.
54
+ ### Usage
66
55
 
56
+ #### Signup
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
- ###### Login
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 `flash[:success_notice] = flash_message`.
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,25 +91,23 @@ 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("You have been successfully logged in.") if authenticated?(password)
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
 
112
100
 
113
- ###### Session handling
101
+ #### Session handling
114
102
  Tachiban handles session expiration by checking if a session has
115
103
  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
@@ -157,7 +145,7 @@ end
157
145
  ```
158
146
 
159
147
 
160
- ###### Password reset
148
+ #### Password reset
161
149
  The password reset feature provides a few simple methods to generate a
162
150
  token, email subject and body. It is also possible to specify and
163
151
  check the validity of the password reset url.
@@ -188,35 +176,43 @@ by the link validity: `Time.now > @user.password_reset_sent_at + link_validity`
188
176
  password_reset_url_valid?(link_validity)
189
177
  ```
190
178
 
179
+ ### Example of use in an application
180
+ [Using Tachiban with a Hanami app](https://sebastjan-hribar.github.io/programming/2021/09/03/tachiban-with-hanami.html)
191
181
 
192
- ###### Authorization
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
182
 
195
- Authorization features support the generation of policy files for each controller where authorized roles are specified for each action.
183
+ ### Changelog
196
184
 
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`
185
+ #### 0.8.0
201
186
 
202
- Each application would have its own `app/policies` folders.
187
+ Bug fix for determining the validity of the password update linke. Greater than instead of less than was used
188
+ to compare the time of the reset link email and the time when the user tries to update the password.
203
189
 
204
- **The command must be run in the project root folder.**
205
190
 
206
- Once the file is generated the authorized roles variables in the initialize block for required actions need to be uncommneted and supplied with specific roles.
191
+ #### 0.7.0
207
192
 
208
- Then we can check if a user is authorized:
193
+ Authorization was moved to a separate gem [Rokku](https://github.com/sebastjan-hribar/rokku).
194
+ Readme update.
195
+
196
+ Method: `Tachiban::login`
197
+ <br>Change:
198
+ Default flash message and redirect url provided.
199
+
200
+
201
+ #### 0.6.1
202
+
203
+ Dependency change for **rake** to ">= 12.3.3".
209
204
 
210
- ```ruby
211
- authorized?(controller, role, action)
212
- ```
213
205
 
206
+ #### 0.6.0
214
207
 
215
- ### ToDo
208
+ Method: `Tachiban::login`
209
+ <br>Change:
210
+ `session[:current_user]` is not set as the user object, but as the user object id.
211
+ ***
212
+ Method: `Tachiban::logout`
213
+ <br>Change:
214
+ Added `session.clear` to remove any other values upon logout.
216
215
 
217
- - Add support for level based authorizations. [x]
218
- - Add generators for adding authorization rules to existing policies.
219
- - Add generators for entities with required attributes.
220
216
 
221
217
 
222
218
  ## Development
data/Rakefile CHANGED
File without changes
data/bin/tachiban CHANGED
@@ -1,2 +1 @@
1
1
  #!/usr/bin/env ruby
2
- require_relative "../lib/tachiban/commands/commands.rb"
@@ -1,3 +1,3 @@
1
1
  module Tachiban
2
- VERSION = "0.5.0"
2
+ VERSION = "0.8.0"
3
3
  end
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,35 +29,41 @@ 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
- # logged in by setting the user object as the session[:current_user].
34
+ # logged in by setting the user object id as the session[:current_user].
38
35
  # After the user is logged in the session start time is defined, which is then used
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(flash_message)
46
- session[:current_user] = @user
46
+ def login
47
+ session[:current_user] = @user.id
47
48
  session[:session_start_time] = Time.now
48
- flash[:success_notice] = flash_message
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 @redirect_to which is set to
54
- # routes.root_path and can be overwritten as needed with a specific url.
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
- @redirect_url ||= routes.root_path
59
- redirect_to @redirect_url
62
+ session.clear
63
+ @logout_redirect_url ||= '/login'
64
+ redirect_to @logout_redirect_url
60
65
  end
61
66
 
62
-
63
67
  # ### Authentication ###
64
68
 
65
69
  # The check_for_logged_in_user method can be used to check for each
@@ -67,10 +71,9 @@ private
67
71
  # the logout method takes over.
68
72
 
69
73
  def check_for_logged_in_user
70
- logout unless session[:current_user]
74
+ logout unless session[:current_user]
71
75
  end
72
76
 
73
-
74
77
  # ### Session handling ###
75
78
 
76
79
  # Session handling includes methods session_expired?,
@@ -87,7 +90,6 @@ private
87
90
  end
88
91
  end
89
92
 
90
-
91
93
  # The restart_session_counter method resets the session start time to
92
94
  # Time.now. It's used in the handle session method.
93
95
 
@@ -95,7 +97,6 @@ private
95
97
  session[:session_start_time] = Time.now
96
98
  end
97
99
 
98
-
99
100
  # The handle_session method is used to handle the incoming requests
100
101
  # based on the the session expiration. If the session has expired the
101
102
  # session user is set to nil, a flash message of "Your session has expired"
@@ -109,16 +110,14 @@ private
109
110
  if session_expired?
110
111
  @redirect_url ||= routes.root_path
111
112
  session[:current_user] = nil
112
- flash[:failed_notice] = "Your session has expired"
113
+ flash[:failed_notice] = 'Your session has expired.'
113
114
  redirect_to @redirect_url
114
115
  else
115
116
  restart_session_counter
116
117
  end
117
118
  end
118
119
 
119
-
120
120
  # ### Password reset ###
121
-
122
121
  def token
123
122
  SecureRandom.urlsafe_base64
124
123
  end
@@ -134,22 +133,8 @@ private
134
133
 
135
134
  # State the link_validity in seconds.
136
135
  def password_reset_url_valid?(link_validity)
137
- Time.now > @user.password_reset_sent_at + link_validity
138
- end
139
-
140
-
141
- # ### Authorization ###
142
- # The authorized? method checks if the specified user has the required role
143
- # and permission to access the action. It returns true or false and
144
- # provides the basis for further actions in either case.
145
- #
146
- # Example: redirect_to "/" unless authorized?
147
-
148
- def authorized?(controller, role, action)
149
- Object.const_get(controller.downcase.capitalize + "Policy").new(role).send("#{action.downcase}?")
136
+ Time.now < @user.password_reset_sent_at + link_validity
150
137
  end
151
-
152
-
153
138
  end
154
139
  end
155
140
 
data/tachiban.gemspec CHANGED
@@ -17,14 +17,14 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_development_dependency "bundler", "~> 1.11"
21
- spec.add_development_dependency "rake", "~> 10.0"
20
+ spec.add_development_dependency "bundler", "~> 2.0"
21
+ spec.add_development_dependency "rake", "~> 12.3", ">= 12.3.3"
22
22
  spec.add_development_dependency "minitest", "~> 5.0"
23
23
  spec.add_development_dependency "hanami-model", "~> 1.0"
24
24
  spec.add_development_dependency "timecop", "0.8.1"
25
25
  spec.add_development_dependency 'hanami-controller', "~> 1.0"
26
26
  spec.add_development_dependency 'hanami-router', "~> 1.0"
27
- spec.add_development_dependency 'pry'
27
+ spec.add_development_dependency 'pry', "~> 0"
28
28
 
29
29
  spec.add_runtime_dependency "bcrypt", "~> 3.1"
30
30
  spec.add_runtime_dependency 'hanami-controller', "~> 1.0"
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.5.0
4
+ version: 0.8.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: 2017-08-22 00:00:00.000000000 Z
11
+ date: 2021-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,28 +16,34 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.11'
19
+ version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.11'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '12.3'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 12.3.3
34
37
  type: :development
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
41
  - - "~>"
39
42
  - !ruby/object:Gem::Version
40
- version: '10.0'
43
+ version: '12.3'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 12.3.3
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: minitest
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -112,14 +118,14 @@ dependencies:
112
118
  name: pry
113
119
  requirement: !ruby/object:Gem::Requirement
114
120
  requirements:
115
- - - ">="
121
+ - - "~>"
116
122
  - !ruby/object:Gem::Version
117
123
  version: '0'
118
124
  type: :development
119
125
  prerelease: false
120
126
  version_requirements: !ruby/object:Gem::Requirement
121
127
  requirements:
122
- - - ">="
128
+ - - "~>"
123
129
  - !ruby/object:Gem::Version
124
130
  version: '0'
125
131
  - !ruby/object:Gem::Dependency
@@ -185,8 +191,6 @@ files:
185
191
  - bin/setup
186
192
  - bin/tachiban
187
193
  - lib/tachiban.rb
188
- - lib/tachiban/commands/commands.rb
189
- - lib/tachiban/policy_generator/policy_generator.rb
190
194
  - lib/tachiban/version.rb
191
195
  - tachiban.gemspec
192
196
  homepage: https://github.com/sebastjan-hribar/tachiban
@@ -209,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
213
  version: '0'
210
214
  requirements: []
211
215
  rubyforge_project:
212
- rubygems_version: 2.5.2
216
+ rubygems_version: 2.7.7
213
217
  signing_key:
214
218
  specification_version: 4
215
219
  summary: Tachiban provides simple password hashing for user authentication with bcrypt
@@ -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