wor-authentication 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e28959f4b22ee0d7e9e845be60500c49ce91d631
4
+ data.tar.gz: 38a0c50a898809ed6d3f5ce05a880316908748ca
5
+ SHA512:
6
+ metadata.gz: 231e7a6cede8153f8b09873200364b7a70daf04a1e9a96e93e6639c0bfb3c46a0bad32b865f69952a57ac028e6420ea1efdcf5a2490bd0fa1ecec05b1f67e2e9
7
+ data.tar.gz: 88141b32c3f2eac550785a86ade9e7a0d10bb20a3404e994e2572288b07eae450e4ce01709c882dfb25f29aa67f53cbeae9732489cc78207d406f53724192c70
@@ -0,0 +1,331 @@
1
+ spec/dummy/db/*.sqlite3
2
+ spec/dummy/db/*.sqlite3-journal
3
+ spec/dummy/log/*.log
4
+ spec/dummy/tmp/
5
+
6
+ /.bundle/
7
+ /.yardoc
8
+ /Gemfile.lock
9
+ /_yardoc/
10
+ /coverage/
11
+ /doc/
12
+ /pkg/
13
+ /spec/reports/
14
+ /tmp/
15
+ *.gem
16
+
17
+ # Created by https://www.gitignore.io/api/ruby,rubymine,rails,emacs,vim,sublimetext,osx,macos,linux,windows
18
+
19
+ ### Emacs ###
20
+ # -*- mode: gitignore; -*-
21
+ *~
22
+ \#*\#
23
+ /.emacs.desktop
24
+ /.emacs.desktop.lock
25
+ *.elc
26
+ auto-save-list
27
+ tramp
28
+ .\#*
29
+
30
+ # Org-mode
31
+ .org-id-locations
32
+ *_archive
33
+
34
+ # flymake-mode
35
+ *_flymake.*
36
+
37
+ # eshell files
38
+ /eshell/history
39
+ /eshell/lastdir
40
+
41
+ # elpa packages
42
+ /elpa/
43
+
44
+ # reftex files
45
+ *.rel
46
+
47
+ # AUCTeX auto folder
48
+ /auto/
49
+
50
+ # cask packages
51
+ .cask/
52
+ dist/
53
+
54
+ # Flycheck
55
+ flycheck_*.el
56
+
57
+ # server auth directory
58
+ /server/
59
+
60
+ # projectiles files
61
+ .projectile
62
+
63
+ # directory configuration
64
+ .dir-locals.el
65
+
66
+ ### Linux ###
67
+
68
+ # temporary files which can be created if a process still has a handle open of a deleted file
69
+ .fuse_hidden*
70
+
71
+ # KDE directory preferences
72
+ .directory
73
+
74
+ # Linux trash folder which might appear on any partition or disk
75
+ .Trash-*
76
+
77
+ # .nfs files are created when an open file is removed but is still being accessed
78
+ .nfs*
79
+
80
+ ### macOS ###
81
+ *.DS_Store
82
+ .AppleDouble
83
+ .LSOverride
84
+
85
+ # Icon must end with two \r
86
+ Icon
87
+
88
+
89
+ # Thumbnails
90
+ ._*
91
+
92
+ # Files that might appear in the root of a volume
93
+ .DocumentRevisions-V100
94
+ .fseventsd
95
+ .Spotlight-V100
96
+ .TemporaryItems
97
+ .Trashes
98
+ .VolumeIcon.icns
99
+ .com.apple.timemachine.donotpresent
100
+
101
+ # Directories potentially created on remote AFP share
102
+ .AppleDB
103
+ .AppleDesktop
104
+ Network Trash Folder
105
+ Temporary Items
106
+ .apdisk
107
+
108
+ ### OSX ###
109
+
110
+ # Icon must end with two \r
111
+
112
+
113
+ # Thumbnails
114
+
115
+ # Files that might appear in the root of a volume
116
+
117
+ # Directories potentially created on remote AFP share
118
+
119
+ ### Rails ###
120
+ *.rbc
121
+ capybara-*.html
122
+ .rspec
123
+ /log
124
+ /tmp
125
+ /db/*.sqlite3
126
+ /db/*.sqlite3-journal
127
+ /public/system
128
+ /coverage/
129
+ /spec/tmp
130
+ **.orig
131
+ rerun.txt
132
+ pickle-email-*.html
133
+
134
+ # TODO Comment out this rule if you are OK with secrets being uploaded to the repo
135
+ config/initializers/secret_token.rb
136
+
137
+ # Only include if you have production secrets in this file, which is no longer a Rails default
138
+ # config/secrets.yml
139
+
140
+ # dotenv
141
+ # TODO Comment out this rule if environment variables can be committed
142
+ .env
143
+
144
+ ## Environment normalization:
145
+ /.bundle
146
+ /vendor/bundle
147
+
148
+ # these should all be checked in to normalize the environment:
149
+ # Gemfile.lock, .ruby-version, .ruby-gemset
150
+
151
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
152
+ .rvmrc
153
+
154
+ # if using bower-rails ignore default bower_components path bower.json files
155
+ /vendor/assets/bower_components
156
+ *.bowerrc
157
+ bower.json
158
+
159
+ # Ignore pow environment settings
160
+ .powenv
161
+
162
+ # Ignore Byebug command history file.
163
+ .byebug_history
164
+
165
+ ### Ruby ###
166
+ *.gem
167
+ /.config
168
+ /InstalledFiles
169
+ /pkg/
170
+ /spec/reports/
171
+ /spec/examples.txt
172
+ /test/tmp/
173
+ /test/version_tmp/
174
+ /tmp/
175
+
176
+ # Used by dotenv library to load environment variables.
177
+ # .env
178
+
179
+ ## Specific to RubyMotion:
180
+ .dat*
181
+ .repl_history
182
+ build/
183
+ *.bridgesupport
184
+ build-iPhoneOS/
185
+ build-iPhoneSimulator/
186
+
187
+ ## Specific to RubyMotion (use of CocoaPods):
188
+ #
189
+ # We recommend against adding the Pods directory to your .gitignore. However
190
+ # you should judge for yourself, the pros and cons are mentioned at:
191
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
192
+ #
193
+ # vendor/Pods/
194
+
195
+ ## Documentation cache and generated files:
196
+ /.yardoc/
197
+ /_yardoc/
198
+ /doc/
199
+ /rdoc/
200
+
201
+ ## Environment normalization:
202
+ /.bundle/
203
+ /lib/bundler/man/
204
+
205
+ # for a library or gem, you might want to ignore these files since the code is
206
+ # intended to run in multiple environments; otherwise, check them in:
207
+ # Gemfile.lock
208
+ # .ruby-version
209
+ # .ruby-gemset
210
+
211
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
212
+
213
+ ### RubyMine ###
214
+ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
215
+ # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
216
+
217
+ # User-specific stuff:
218
+ .idea/**/workspace.xml
219
+ .idea/**/tasks.xml
220
+
221
+ # Sensitive or high-churn files:
222
+ .idea/**/dataSources/
223
+ .idea/**/dataSources.ids
224
+ .idea/**/dataSources.xml
225
+ .idea/**/dataSources.local.xml
226
+ .idea/**/sqlDataSources.xml
227
+ .idea/**/dynamic.xml
228
+ .idea/**/uiDesigner.xml
229
+
230
+ # Gradle:
231
+ .idea/**/gradle.xml
232
+ .idea/**/libraries
233
+
234
+ # Mongo Explorer plugin:
235
+ .idea/**/mongoSettings.xml
236
+
237
+ ## File-based project format:
238
+ *.iws
239
+
240
+ ## Plugin-specific files:
241
+
242
+ # IntelliJ
243
+ /out/
244
+
245
+ # mpeltonen/sbt-idea plugin
246
+ .idea_modules/
247
+
248
+ # JIRA plugin
249
+ atlassian-ide-plugin.xml
250
+
251
+ # Crashlytics plugin (for Android Studio and IntelliJ)
252
+ com_crashlytics_export_strings.xml
253
+ crashlytics.properties
254
+ crashlytics-build.properties
255
+ fabric.properties
256
+
257
+ ### RubyMine Patch ###
258
+ # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
259
+
260
+ # *.iml
261
+ # modules.xml
262
+ # .idea/misc.xml
263
+ # *.ipr
264
+
265
+ ### SublimeText ###
266
+ # cache files for sublime text
267
+ *.tmlanguage.cache
268
+ *.tmPreferences.cache
269
+ *.stTheme.cache
270
+
271
+ # workspace files are user-specific
272
+ *.sublime-workspace
273
+
274
+ # project files should be checked into the repository, unless a significant
275
+ # proportion of contributors will probably not be using SublimeText
276
+ # *.sublime-project
277
+
278
+ # sftp configuration file
279
+ sftp-config.json
280
+
281
+ # Package control specific files
282
+ Package Control.last-run
283
+ Package Control.ca-list
284
+ Package Control.ca-bundle
285
+ Package Control.system-ca-bundle
286
+ Package Control.cache/
287
+ Package Control.ca-certs/
288
+ Package Control.merged-ca-bundle
289
+ Package Control.user-ca-bundle
290
+ oscrypto-ca-bundle.crt
291
+ bh_unicode_properties.cache
292
+
293
+ # Sublime-github package stores a github token in this file
294
+ # https://packagecontrol.io/packages/sublime-github
295
+ GitHub.sublime-settings
296
+
297
+ ### Vim ###
298
+ # swap
299
+ [._]*.s[a-v][a-z]
300
+ [._]*.sw[a-p]
301
+ [._]s[a-v][a-z]
302
+ [._]sw[a-p]
303
+ # session
304
+ Session.vim
305
+ # temporary
306
+ .netrwhist
307
+ # auto-generated tag files
308
+ tags
309
+
310
+ ### Windows ###
311
+ # Windows thumbnail cache files
312
+ Thumbs.db
313
+ ehthumbs.db
314
+ ehthumbs_vista.db
315
+
316
+ # Folder config file
317
+ Desktop.ini
318
+
319
+ # Recycle Bin used on file shares
320
+ $RECYCLE.BIN/
321
+
322
+ # Windows Installer files
323
+ *.cab
324
+ *.msi
325
+ *.msm
326
+ *.msp
327
+
328
+ # Windows shortcuts
329
+ *.lnk
330
+
331
+ # End of https://www.gitignore.io/api/ruby,rubymine,rails,emacs,vim,sublimetext,osx,macos,linux,windows
@@ -0,0 +1,12 @@
1
+ AllCops:
2
+ Exclude:
3
+ - wor-requests.gemspec
4
+
5
+ Documentation:
6
+ Enabled: false
7
+
8
+ LineLength:
9
+ Max: 99
10
+
11
+ FrozenStringLiteralComment:
12
+ Enabled: false
@@ -0,0 +1,19 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0
4
+ - 2.1
5
+ - 2.2
6
+ - 2.3.3
7
+ - 2.4.0
8
+
9
+ install:
10
+ - gem install bundler
11
+ - bundle install --retry=3
12
+
13
+ script:
14
+ - bundle exec rspec
15
+ - bundle exec rubocop -R --format simple
16
+
17
+ addons:
18
+ code_climate:
19
+ repo_token:
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wor-authentication.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Alejandro Bezdjian, aka alebian
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,163 @@
1
+ # Wolox on Rails - Authentication
2
+ [![Build Status](https://travis-ci.org/Wolox/wor-authentication.svg)](https://travis-ci.org/Wolox/wor-authentication)
3
+ [![Code Climate](https://codeclimate.com/github/Wolox/wor-authentication/badges/gpa.svg)](https://codeclimate.com/github/Wolox/wor-authentication)
4
+ [![Test Coverage](https://codeclimate.com/github/Wolox/wor-authentication/badges/coverage.svg)](https://codeclimate.com/github/Wolox/wor-authentication/coverage)
5
+ [![Issue Count](https://codeclimate.com/github/Wolox/wor-authentication/badges/issue_count.svg)](https://codeclimate.com/github/Wolox/wor-authentication)
6
+
7
+ Gem to add authentication to your application using JWT, with expirable, renewable and customizable tokens!
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'wor-authentication'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install wor-authentication
24
+
25
+ ## Usage
26
+
27
+ ### Basic configuration
28
+
29
+ The first step is to define a parent controller from which all other controllers will have to extend to have only-authenticated routes. So, let's do that in our `ApplicationController.rb`:
30
+ ```ruby
31
+ class ApplicationController < ActionController::Base
32
+ include Wor::Authentication::Controller
33
+ before_action :authenticate_request
34
+ end
35
+ ```
36
+ > To know which exceptions can be thrown by the gem, please check the [exceptions file](./lib/wor/authentication/exceptions.rb).
37
+
38
+ Second and last step, we have to define the routes to achieve authentication and a controller to handle them.
39
+ ```ruby
40
+ # routes.rb
41
+ Rails.application.routes.draw do
42
+ # your routes go here
43
+ post '/' => 'authentication#create'
44
+ post '/renew' => 'authentication#renew'
45
+ post '/invalidate_all' => 'authentication#invalidate_all'
46
+ end
47
+
48
+ # authentication_controller.rb
49
+ class AuthenticationController < ApplicationController
50
+ include Wor::Authentication::SessionsController
51
+ skip_before_action :authenticate_request, only: [:create]
52
+ end
53
+ ```
54
+ > Note that our controller extends from ApplicationController.
55
+
56
+ ### <a name='custom-validations'> User tracking and custom validations
57
+
58
+ #### Validations before giving out a token? Override `authenticate_entity`:
59
+
60
+ ```ruby
61
+ # authentication_controller.rb
62
+ def authenticate_entity(params)
63
+ user ||= User.find_by(email: params[:email])
64
+ return nil unless user.present? && user.valid_password?(params[:password])
65
+ end
66
+ ```
67
+ > Returning no value or false won't create the authentication token.
68
+
69
+ #### Keeping track of users? Override: `entity_payload`:
70
+
71
+ ```ruby
72
+ # authentication_controller.rb
73
+ ENTITY_KEY = :user_id
74
+
75
+ def entity_payload(user)
76
+ { ENTITY_KEY => user.id }
77
+ end
78
+
79
+ def find_authenticable_entity(entity_payload_returned_object)
80
+ User.find_by(id: entity_payload_returned_object.fetch(ENTITY_KEY))
81
+ end
82
+ ```
83
+
84
+ #### Validations in every request? Override `entity_custom_validation_value` to get it verified as the following:
85
+
86
+ ```ruby
87
+ # authentication_controller.rb
88
+ def entity_custom_validation_value(user)
89
+ user.some_value_that_shouldnt_change
90
+ end
91
+ ```
92
+ This method will be called before creating the token and in every request to compare if the returned values are the same. If values mismatch, the token won't be valid anymore. If values are the same, expiration validations will be checked.
93
+ > If it is desired to update this value when renewing the token, override: `entity_custom_validation_renew_value`.
94
+
95
+ #### Invalidating all tokens for a user? Override `entity_custom_validation_invalidate_all_value` as the following:
96
+
97
+ ```ruby
98
+ # authentication_controller.rb
99
+ def entity_custom_validation_invalidate_all_value(user)
100
+ user.some_value_that_shouldnt_change = 'some-new-value'
101
+ user.save
102
+ end
103
+ ```
104
+ This method is the one executed when we want to invalidate sessions for the authenticated user. An option to achieve that can be to override the value that will be then compared in every request with `entity_custom_validation_value` method, so that initial stored value mismatch with the new different value.
105
+ > This works only if `entity_custom_validation_value` has been overridden.
106
+
107
+
108
+ ### Some other useful configurations
109
+
110
+ #### Want to modify tokens ttl? Override `new_token_expiration_date` as the following:
111
+
112
+ ```ruby
113
+ def new_token_expiration_date
114
+ (Time.zone.now + 2.days).to_i
115
+ end
116
+ ```
117
+
118
+ #### Want to modify tokens maximum useful day? Override `token_maximum_useful_date` as the following:
119
+
120
+ ```ruby
121
+ def token_maximum_useful_date
122
+ (Time.zone.now + 30.days).to_i
123
+ end
124
+ ```
125
+
126
+ ## Contributing
127
+
128
+ 1. Fork it
129
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
130
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
131
+ 4. Run rubocop lint (`rubocop -R --format simple`)
132
+ 5. Run rspec tests (`bundle exec rspec`)
133
+ 6. Push your branch (`git push origin my-new-feature`)
134
+ 7. Create a new Pull Request
135
+
136
+ ## About ##
137
+
138
+ This project is maintained by [Alejandro Bezdjian](https://github.com/alebian) along with [Michel Agopian](https://github.com/mishuagopian) and it was written by [Wolox](http://www.wolox.com.ar).
139
+ ![Wolox](https://raw.githubusercontent.com/Wolox/press-kit/master/logos/logo_banner.png)
140
+
141
+ ## License
142
+
143
+ **wor-authentication** is available under the MIT [license](https://raw.githubusercontent.com/Wolox/wor-authentication/master/LICENSE.md).
144
+
145
+ Copyright (c) 2017 Alejandro Bezdjian (aka alebian), Michel Agopian (aka mishuagopian)
146
+
147
+ Permission is hereby granted, free of charge, to any person obtaining a copy
148
+ of this software and associated documentation files (the "Software"), to deal
149
+ in the Software without restriction, including without limitation the rights
150
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
151
+ copies of the Software, and to permit persons to whom the Software is
152
+ furnished to do so, subject to the following conditions:
153
+
154
+ The above copyright notice and this permission notice shall be included in
155
+ all copies or substantial portions of the Software.
156
+
157
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
159
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
160
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
161
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
162
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
163
+ THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,12 @@
1
+ require_relative 'authentication/controller'
2
+ require_relative 'authentication/decoded_token'
3
+ require_relative 'authentication/exceptions'
4
+ require_relative 'authentication/sessions_controller'
5
+ require_relative 'authentication/token_manager'
6
+ require_relative 'authentication/version'
7
+
8
+ module Wor
9
+ module Authentication
10
+ # Your code goes here...
11
+ end
12
+ end
@@ -0,0 +1,60 @@
1
+ require 'devise'
2
+
3
+ module Wor
4
+ module Authentication
5
+ module Controller
6
+
7
+ def authenticate_request
8
+ entity = find_authenticable_entity(decoded_token)
9
+ decoded_token.validate!(entity_custom_validation_value(entity))
10
+ end
11
+
12
+ def decoded_token
13
+ @decoded_token ||= Wor::Authentication::TokenManager.new(token_key).decode(authentication_token)
14
+ end
15
+
16
+ ##
17
+ # Helpers which may be overrided
18
+ ##
19
+
20
+ def token_renew_id
21
+ Devise.friendly_token(32)
22
+ end
23
+
24
+ def new_token_expiration_date
25
+ (Time.zone.now + 2.days).to_i
26
+ end
27
+
28
+ def token_maximum_useful_date
29
+ (Time.zone.now + 30.days).to_i
30
+ end
31
+
32
+ def authentication_token
33
+ request.headers['Authorization'].split(' ').last
34
+ end
35
+
36
+ def entity_custom_validation_value(entity)
37
+ nil
38
+ end
39
+
40
+ def entity_custom_validation_renew_value(entity)
41
+ entity_custom_validation_value(entity)
42
+ end
43
+
44
+ def entity_custom_validation_invalidate_all_value(entity)
45
+ nil
46
+ end
47
+
48
+ # Explain in README
49
+ def token_key
50
+ raise Wor::Authentication::Exceptions::SubclassMustImplementError unless defined?(Rails)
51
+ raise Wor::Authentication::Exceptions::NoKeyProvidedError unless Rails.application.secrets.secret_key_base.present?
52
+ Rails.application.secrets.secret_key_base
53
+ end
54
+
55
+ def authenticate_entity(params) {} end
56
+ def find_authenticable_entity(decoded_token) {} end
57
+ def entity_payload(entity) {} end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,47 @@
1
+ module Wor
2
+ module Authentication
3
+ class DecodedToken
4
+ attr_reader :payload
5
+
6
+ def initialize(payload)
7
+ @payload = payload
8
+ end
9
+
10
+ def validate!(entity_custom_validation = nil)
11
+ raise Wor::Authentication::Exceptions::EntityCustomValidationError unless valid_entity_custom_validation?(entity_custom_validation)
12
+ raise Wor::Authentication::Exceptions::NotRenewableTokenError unless able_to_renew?
13
+ raise Wor::Authentication::Exceptions::ExpiredTokenError if expired?
14
+ end
15
+
16
+ def fetch(key)
17
+ return payload[key.to_sym] if payload[key.to_sym]
18
+ return payload[key.to_s] if payload[key.to_s]
19
+ nil
20
+ end
21
+
22
+ def expired?
23
+ return false unless fetch(:expiration_date).present?
24
+ # TODO: Use a ruby standard library for time
25
+ Time.zone.now.to_i > fetch(:expiration_date)
26
+ end
27
+
28
+ def able_to_renew?
29
+ return false unless fetch(:maximum_useful_date).present?
30
+ # TODO: Use a ruby standard library for time
31
+ Time.zone.now.to_i < fetch(:maximum_useful_date)
32
+ end
33
+
34
+ def valid_renew_id?(renew_id)
35
+ return true unless fetch(:renew_id).present? && renew_id.present?
36
+ renew_id == fetch(:renew_id)
37
+ end
38
+
39
+ private
40
+
41
+ def valid_entity_custom_validation?(entity_custom_validation)
42
+ return true unless fetch(:entity_custom_validation).present?
43
+ entity_custom_validation == fetch(:entity_custom_validation)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ module Wor
2
+ module Authentication
3
+ module Exceptions
4
+ class SubclassMustImplementError < StandardError ; end
5
+ class NoKeyProvidedError < StandardError ; end
6
+ class ExpiredTokenError < StandardError ; end
7
+ class NotRenewableTokenError < StandardError ; end
8
+ class EntityCustomValidationError < StandardError ; end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,82 @@
1
+ module Wor
2
+ module Authentication
3
+ module SessionsController
4
+
5
+ def create
6
+ entity = authenticate_entity(authenticate_params)
7
+ if entity
8
+ token_data = generate_access_token(entity)
9
+ render json: {
10
+ access_token: token_data[:token], renew_id: token_data[:renew_id]
11
+ }, status: :ok
12
+ else
13
+ render_error('Invalid authentication credentials', :unauthorized)
14
+ end
15
+ end
16
+
17
+ def renew
18
+ if !decoded_token.valid_renew_id?(renew_token_params[:renew_id])
19
+ render_error('Invalid renew_id', :unauthorized)
20
+ else
21
+ render json: { access_token: renew_access_token(current_entity) }, status: :ok
22
+ end
23
+ end
24
+
25
+ def invalidate_all
26
+ # should we rescue anything here ?
27
+ # if invalidating uses db and fails, or something like that
28
+ entity_custom_validation_invalidate_all_value(current_entity)
29
+ head :ok
30
+ end
31
+
32
+ def generate_access_token(entity)
33
+ renew_id = token_renew_id
34
+ payload = entity_payload(entity).merge(
35
+ entity_custom_validation: entity_custom_validation_value(entity),
36
+ expiration_date: new_token_expiration_date,
37
+ maximum_useful_date: token_maximum_useful_date,
38
+ renew_id: renew_id
39
+ )
40
+ { token: Wor::Authentication::TokenManager.new(token_key).encode(payload), renew_id: renew_id }
41
+ end
42
+
43
+ def renew_access_token(entity)
44
+ payload = decoded_token.payload
45
+ payload[:expiration_date] = new_token_expiration_date
46
+ payload[:entity_custom_validation] = entity_custom_validation_renew_value(entity)
47
+ Wor::Authentication::TokenManager.new(token_key).encode(payload)
48
+ end
49
+
50
+ private
51
+
52
+ def current_entity
53
+ current_entity ||= find_authenticable_entity(decoded_token)
54
+ end
55
+
56
+ def render_error(error_message, status)
57
+ render json: { error: error_message }, status: status
58
+ end
59
+
60
+ # I'm pretty sure this should be set by gems users and not us
61
+ def authenticate_params
62
+ params.require(:session).permit(:email, :password)
63
+ end
64
+ # I'm pretty sure this should be set by gems users and not us
65
+ def renew_token_params
66
+ params.require(:session).permit(:renew_id)
67
+ end
68
+
69
+ def render_not_renewable_token
70
+ render_error('Access token is not valid anymore', :unauthorized)
71
+ end
72
+
73
+ def render_expired_token
74
+ render_error('Expired token', :unauthorized)
75
+ end
76
+
77
+ def render_entity_invalid_custom_validation
78
+ render_error('Entity invalid custom validation', :unauthorized)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,22 @@
1
+ require 'jwt'
2
+
3
+ module Wor
4
+ module Authentication
5
+ class TokenManager
6
+ def initialize(key)
7
+ @key = key
8
+ end
9
+
10
+ def encode(payload)
11
+ JWT.encode(payload, @key)
12
+ end
13
+
14
+ def decode(token)
15
+ payload = JWT.decode(token, @key)[0]
16
+ Wor::Authentication::DecodedToken.new(payload)
17
+ rescue
18
+ nil
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ module Wor
2
+ module Authentication
3
+ VERSION = '0.1.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wor/authentication/version'
5
+ require 'date'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'wor-authentication'
9
+ spec.version = Wor::Authentication::VERSION
10
+ spec.platform = Gem::Platform::RUBY
11
+ spec.date = Date.today
12
+ spec.authors = ['alebian', 'mishuagopian']
13
+ spec.email = ['alejandro.bezdjian@wolox.com.ar', 'michel.agopian@wolox.com.ar']
14
+
15
+ spec.summary = 'Gem to add authentication to your application.'
16
+ spec.description = 'Gem to add authentication to your application using JWT, with expirable, renewable and customizable tokens.'
17
+ spec.homepage = 'https://github.com/Wolox/wor-authentication'
18
+ spec.license = 'MIT'
19
+
20
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec)/}) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec)/})
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency 'railties', '>= 4.1.0', '< 5.1'
25
+ spec.add_dependency 'devise', '>= 4.2.0'
26
+ spec.add_dependency 'jwt', '>= 1.5'
27
+ spec.add_dependency 'rails', '>= 4.0'
28
+
29
+ spec.add_development_dependency 'byebug', '~> 9.0'
30
+ spec.add_development_dependency 'rubocop', '~> 0.47'
31
+ spec.add_development_dependency 'bundler', '~> 1.13'
32
+ spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rspec', '~> 3.0'
34
+ spec.add_development_dependency 'rspec-rails', '~> 3.5'
35
+ spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0.0'
36
+ spec.add_development_dependency 'generator_spec'
37
+ spec.add_development_dependency 'simplecov'
38
+ spec.add_development_dependency 'timecop'
39
+ spec.add_development_dependency 'sqlite3'
40
+ end
metadata ADDED
@@ -0,0 +1,278 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wor-authentication
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - alebian
8
+ - mishuagopian
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-04-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 4.1.0
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: '5.1'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: 4.1.0
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.1'
34
+ - !ruby/object:Gem::Dependency
35
+ name: devise
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 4.2.0
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 4.2.0
48
+ - !ruby/object:Gem::Dependency
49
+ name: jwt
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.5'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rails
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '4.0'
69
+ type: :runtime
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: byebug
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '9.0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '9.0'
90
+ - !ruby/object:Gem::Dependency
91
+ name: rubocop
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.47'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.47'
104
+ - !ruby/object:Gem::Dependency
105
+ name: bundler
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.13'
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.13'
118
+ - !ruby/object:Gem::Dependency
119
+ name: rake
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '10.0'
132
+ - !ruby/object:Gem::Dependency
133
+ name: rspec
134
+ requirement: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.0'
146
+ - !ruby/object:Gem::Dependency
147
+ name: rspec-rails
148
+ requirement: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.5'
153
+ type: :development
154
+ prerelease: false
155
+ version_requirements: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '3.5'
160
+ - !ruby/object:Gem::Dependency
161
+ name: codeclimate-test-reporter
162
+ requirement: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: 1.0.0
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 1.0.0
174
+ - !ruby/object:Gem::Dependency
175
+ name: generator_spec
176
+ requirement: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ type: :development
182
+ prerelease: false
183
+ version_requirements: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ - !ruby/object:Gem::Dependency
189
+ name: simplecov
190
+ requirement: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ type: :development
196
+ prerelease: false
197
+ version_requirements: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ - !ruby/object:Gem::Dependency
203
+ name: timecop
204
+ requirement: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ type: :development
210
+ prerelease: false
211
+ version_requirements: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ - !ruby/object:Gem::Dependency
217
+ name: sqlite3
218
+ requirement: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ type: :development
224
+ prerelease: false
225
+ version_requirements: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ description: Gem to add authentication to your application using JWT, with expirable,
231
+ renewable and customizable tokens.
232
+ email:
233
+ - alejandro.bezdjian@wolox.com.ar
234
+ - michel.agopian@wolox.com.ar
235
+ executables: []
236
+ extensions: []
237
+ extra_rdoc_files: []
238
+ files:
239
+ - ".gitignore"
240
+ - ".rubocop.yml"
241
+ - ".travis.yml"
242
+ - Gemfile
243
+ - LICENSE.md
244
+ - README.md
245
+ - Rakefile
246
+ - lib/wor/authentication.rb
247
+ - lib/wor/authentication/controller.rb
248
+ - lib/wor/authentication/decoded_token.rb
249
+ - lib/wor/authentication/exceptions.rb
250
+ - lib/wor/authentication/sessions_controller.rb
251
+ - lib/wor/authentication/token_manager.rb
252
+ - lib/wor/authentication/version.rb
253
+ - wor-authentication.gemspec
254
+ homepage: https://github.com/Wolox/wor-authentication
255
+ licenses:
256
+ - MIT
257
+ metadata: {}
258
+ post_install_message:
259
+ rdoc_options: []
260
+ require_paths:
261
+ - lib
262
+ required_ruby_version: !ruby/object:Gem::Requirement
263
+ requirements:
264
+ - - ">="
265
+ - !ruby/object:Gem::Version
266
+ version: '0'
267
+ required_rubygems_version: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ">="
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ requirements: []
273
+ rubyforge_project:
274
+ rubygems_version: 2.6.7
275
+ signing_key:
276
+ specification_version: 4
277
+ summary: Gem to add authentication to your application.
278
+ test_files: []