KnockRails3 2.1.1

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.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +39 -0
  4. data/app/controllers/knock_rails3/application_controller.rb +11 -0
  5. data/app/controllers/knock_rails3/auth_token_controller.rb +47 -0
  6. data/app/model/knock_rails3/auth_token.rb +78 -0
  7. data/config/routes.rb +3 -0
  8. data/lib/KnockRails3.rb +31 -0
  9. data/lib/generators/knock_rails3/install_generator.rb +13 -0
  10. data/lib/generators/knock_rails3/token_controller_generator.rb +27 -0
  11. data/lib/generators/templates/entity_token_controller.rb.erb +2 -0
  12. data/lib/generators/templates/knock_rails3.rb +59 -0
  13. data/lib/knock_rails3/authenticable.rb +60 -0
  14. data/lib/knock_rails3/engine.rb +6 -0
  15. data/lib/knock_rails3/version.rb +3 -0
  16. data/lib/tasks/KnockRails3_tasks.rake +4 -0
  17. data/test/dummy/README.rdoc +28 -0
  18. data/test/dummy/Rakefile +6 -0
  19. data/test/dummy/app/assets/javascripts/application.js +13 -0
  20. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  21. data/test/dummy/app/controllers/admin_protected_controller.rb +7 -0
  22. data/test/dummy/app/controllers/admin_token_controller.rb +2 -0
  23. data/test/dummy/app/controllers/application_controller.rb +7 -0
  24. data/test/dummy/app/controllers/composite_name_entity_protected_controller.rb +7 -0
  25. data/test/dummy/app/controllers/current_users_controller.rb +9 -0
  26. data/test/dummy/app/controllers/custom_unauthorized_entity_controller.rb +13 -0
  27. data/test/dummy/app/controllers/guest_protected_controller.rb +7 -0
  28. data/test/dummy/app/controllers/protected_resources_controller.rb +7 -0
  29. data/test/dummy/app/controllers/v1/test_namespaced_controller.rb +17 -0
  30. data/test/dummy/app/controllers/vendor_protected_controller.rb +11 -0
  31. data/test/dummy/app/controllers/vendor_token_controller.rb +2 -0
  32. data/test/dummy/app/helpers/application_helper.rb +2 -0
  33. data/test/dummy/app/models/admin.rb +16 -0
  34. data/test/dummy/app/models/composite_name_entity.rb +3 -0
  35. data/test/dummy/app/models/guest.rb +7 -0
  36. data/test/dummy/app/models/user.rb +3 -0
  37. data/test/dummy/app/models/v1/user.rb +5 -0
  38. data/test/dummy/app/models/vendor.rb +3 -0
  39. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  40. data/test/dummy/bin/bundle +3 -0
  41. data/test/dummy/bin/rails +4 -0
  42. data/test/dummy/bin/rake +4 -0
  43. data/test/dummy/bin/setup +29 -0
  44. data/test/dummy/config.ru +4 -0
  45. data/test/dummy/config/application.rb +28 -0
  46. data/test/dummy/config/boot.rb +5 -0
  47. data/test/dummy/config/database.yml +25 -0
  48. data/test/dummy/config/environment.rb +5 -0
  49. data/test/dummy/config/environments/development.rb +41 -0
  50. data/test/dummy/config/environments/production.rb +79 -0
  51. data/test/dummy/config/environments/test.rb +47 -0
  52. data/test/dummy/config/initializers/assets.rb +11 -0
  53. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  54. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  55. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  56. data/test/dummy/config/initializers/inflections.rb +16 -0
  57. data/test/dummy/config/initializers/knock.rb +8 -0
  58. data/test/dummy/config/initializers/mime_types.rb +4 -0
  59. data/test/dummy/config/initializers/session_store.rb +3 -0
  60. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  61. data/test/dummy/config/locales/en.yml +23 -0
  62. data/test/dummy/config/routes.rb +17 -0
  63. data/test/dummy/config/secrets.yml +22 -0
  64. data/test/dummy/db/migrate/20150713101607_create_users.rb +10 -0
  65. data/test/dummy/db/migrate/20160519075733_create_admins.rb +10 -0
  66. data/test/dummy/db/migrate/20160522051816_create_vendors.rb +10 -0
  67. data/test/dummy/db/migrate/20160522181712_create_composite_name_entities.rb +10 -0
  68. data/test/dummy/db/migrate/20161127203222_create_v1_users.rb +12 -0
  69. data/test/dummy/db/schema.rb +50 -0
  70. data/test/dummy/public/404.html +67 -0
  71. data/test/dummy/public/422.html +67 -0
  72. data/test/dummy/public/500.html +66 -0
  73. data/test/dummy/public/favicon.ico +0 -0
  74. data/test/dummy/test/controllers/admin_protected_controller_test.rb +49 -0
  75. data/test/dummy/test/controllers/admin_token_controller_test.rb +22 -0
  76. data/test/dummy/test/controllers/composite_name_entity_protected_controller_test.rb +49 -0
  77. data/test/dummy/test/controllers/current_users_controller_test.rb +31 -0
  78. data/test/dummy/test/controllers/custom_unauthorized_entity_controller_test.rb +42 -0
  79. data/test/dummy/test/controllers/guest_protected_controller_test.rb +22 -0
  80. data/test/dummy/test/controllers/protected_resources_controller_test.rb +62 -0
  81. data/test/dummy/test/controllers/v1/test_namespaced_controller_test.rb +19 -0
  82. data/test/dummy/test/controllers/vendor_protected_controller_test.rb +55 -0
  83. data/test/dummy/test/controllers/vendor_token_controller_test.rb +22 -0
  84. data/test/dummy/test/models/admin_test.rb +7 -0
  85. data/test/dummy/test/models/user_test.rb +4 -0
  86. data/test/dummy/test/models/vendor_test.rb +7 -0
  87. data/test/fixtures/admins.yml +5 -0
  88. data/test/fixtures/composite_name_entities.yml +5 -0
  89. data/test/fixtures/users.yml +9 -0
  90. data/test/fixtures/v1_users.yml +6 -0
  91. data/test/fixtures/vendors.yml +5 -0
  92. data/test/generators/install_generator_test.rb +12 -0
  93. data/test/generators/token_controller_generator_test.rb +31 -0
  94. data/test/knock_test.rb +9 -0
  95. data/test/model/knock/auth_token_test.rb +123 -0
  96. data/test/support/generators_test_helper.rb +9 -0
  97. data/test/test_helper.rb +45 -0
  98. metadata +292 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e9f0af023a92177f1547e7aab56b1a72a49a8aa4
4
+ data.tar.gz: 5ee385e7811b37f4d0cfb9a69db494f50600383b
5
+ SHA512:
6
+ metadata.gz: '0739ec58775ca1e7e8930266029600ede81f86ea59a614aa6a8914ad485decec68ac9574f3178a3a6ffa4d9c069353c97d0b4cffea47c22b6cdf84ae74b73fb4'
7
+ data.tar.gz: aca684c4d0b825404052d246991a6d3e6c45e740624a18e5f7b1ec4aafb1c351c6a6d4c670e0e80ebe2ef1dd1aede41155416d86c99c3fbf8985993bb9efbcdc
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Arnaud MESUREUR
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.
@@ -0,0 +1,39 @@
1
+ require "rubygems"
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rdoc/task'
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = 'KnockRails3'
14
+ rdoc.options << '--line-numbers'
15
+ rdoc.rdoc_files.include('README.rdoc')
16
+ rdoc.rdoc_files.include('lib/**/*.rb')
17
+ end
18
+
19
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
20
+ load 'rails/tasks/engine.rake'
21
+
22
+
23
+ load 'rails/tasks/statistics.rake'
24
+
25
+
26
+
27
+ Bundler::GemHelper.install_tasks
28
+
29
+ require 'rake/testtask'
30
+
31
+ Rake::TestTask.new(:test) do |t|
32
+ t.libs << 'lib'
33
+ t.libs << 'test'
34
+ t.pattern = 'test/**/*_test.rb'
35
+ t.verbose = false
36
+ end
37
+
38
+
39
+ task default: :test
@@ -0,0 +1,11 @@
1
+ module KnockRails3
2
+ class ApplicationController < ActionController::Base
3
+ rescue_from KnockRails3.not_found_exception_class_name, with: :not_found
4
+
5
+ private
6
+
7
+ def not_found
8
+ head :not_found
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,47 @@
1
+ require_dependency "knock_rails3/application_controller"
2
+
3
+ module KnockRails3
4
+ class AuthTokenController < ApplicationController
5
+ before_filter :authenticate
6
+
7
+ def create
8
+ render json: auth_token, status: :created
9
+ end
10
+
11
+ private
12
+ def authenticate
13
+ unless entity.present? && entity.authenticate(auth_params[:password])
14
+ raise KnockRails3.not_found_exception_class
15
+ end
16
+ end
17
+
18
+ def auth_token
19
+ if entity.respond_to? :to_token_payload
20
+ AuthToken.new payload: entity.to_token_payload
21
+ else
22
+ AuthToken.new payload: { sub: entity.id }
23
+ end
24
+ end
25
+
26
+ def entity
27
+ @entity ||=
28
+ if entity_class.respond_to? :from_token_request
29
+ entity_class.from_token_request request
30
+ else
31
+ entity_class.find_by_email(auth_params[:email])
32
+ end
33
+ end
34
+
35
+ def entity_class
36
+ entity_name.constantize
37
+ end
38
+
39
+ def entity_name
40
+ self.class.name.scan(/\w+/).last.split('TokenController').first
41
+ end
42
+
43
+ def auth_params
44
+ params[:auth]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,78 @@
1
+ require 'jwt'
2
+
3
+ module KnockRails3
4
+ class AuthToken
5
+ attr_reader :token
6
+ attr_reader :payload
7
+
8
+ def initialize payload: {}, token: nil, verify_options: {}
9
+ if token.present?
10
+ @payload, _ = JWT.decode token.to_s, decode_key, true, options.merge(verify_options)
11
+ @token = token
12
+ else
13
+ @payload = claims.merge(payload)
14
+ @token = JWT.encode @payload,
15
+ secret_key,
16
+ KnockRails3.token_signature_algorithm
17
+ end
18
+ end
19
+
20
+ def entity_for entity_class
21
+ if entity_class.respond_to? :from_token_payload
22
+ entity_class.from_token_payload @payload
23
+ else
24
+ entity_class.find @payload['sub']
25
+ end
26
+ end
27
+
28
+ def to_json options = {}
29
+ {jwt: @token}.to_json
30
+ end
31
+
32
+ private
33
+ def secret_key
34
+ KnockRails3.token_secret_signature_key.call
35
+ end
36
+
37
+ def decode_key
38
+ KnockRails3.token_public_key || secret_key
39
+ end
40
+
41
+ def options
42
+ verify_claims.merge({
43
+ algorithm: KnockRails3.token_signature_algorithm
44
+ })
45
+ end
46
+
47
+ def claims
48
+ _claims = {}
49
+ _claims[:exp] = token_lifetime if verify_lifetime?
50
+ _claims[:aud] = token_audience if verify_audience?
51
+ _claims
52
+ end
53
+
54
+ def token_lifetime
55
+ KnockRails3.token_lifetime.from_now.to_i if verify_lifetime?
56
+ end
57
+
58
+ def verify_lifetime?
59
+ !KnockRails3.token_lifetime.nil?
60
+ end
61
+
62
+ def verify_claims
63
+ {
64
+ aud: token_audience,
65
+ verify_aud: verify_audience?,
66
+ verify_expiration: verify_lifetime?
67
+ }
68
+ end
69
+
70
+ def token_audience
71
+ verify_audience? && KnockRails3.token_audience.call
72
+ end
73
+
74
+ def verify_audience?
75
+ KnockRails3.token_audience.present?
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,3 @@
1
+ KnockRails3::Engine.routes.draw do
2
+ post 'auth_token' => 'auth_token#create'
3
+ end
@@ -0,0 +1,31 @@
1
+ require "knock_rails3/engine"
2
+
3
+ module KnockRails3
4
+ mattr_accessor :token_lifetime
5
+ self.token_lifetime = 1.day
6
+
7
+ mattr_accessor :token_audience
8
+ self.token_audience = nil
9
+
10
+ mattr_accessor :token_signature_algorithm
11
+ self.token_signature_algorithm = 'HS256'
12
+
13
+ mattr_accessor :token_secret_signature_key
14
+ self.token_secret_signature_key = -> { Rails.application.secrets.secret_key_base }
15
+
16
+ mattr_accessor :token_public_key
17
+ self.token_public_key = nil
18
+
19
+ mattr_accessor :not_found_exception_class_name
20
+ self.not_found_exception_class_name = 'ActiveRecord::RecordNotFound'
21
+
22
+ def self.not_found_exception_class
23
+ not_found_exception_class_name.to_s.constantize
24
+ end
25
+
26
+ # Default way to setup KnockRails3. Run `rails generate KnockRails3:install` to create
27
+ # a fresh initializer with all configuration values.
28
+ def self.setup
29
+ yield self
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators'
2
+
3
+ module KnockRails3
4
+ class InstallGenerator < Rails::Generators::Base
5
+ source_root File.expand_path("../../templates", __FILE__)
6
+
7
+ desc "Creates a KnockRails3 initializer."
8
+
9
+ def copy_initializer
10
+ template 'knock_rails3.rb', 'config/initializers/knock_rails3.rb'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ require 'rails/generators'
2
+
3
+ module KnockRails3
4
+ class TokenControllerGenerator < Rails::Generators::Base
5
+ source_root File.expand_path("../../templates", __FILE__)
6
+ argument :name, type: :string
7
+
8
+ desc <<-DESC
9
+ Creates a KnockRails3 token controller for the given entity
10
+ and add the corresponding routes.
11
+ DESC
12
+
13
+ def copy_controller_file
14
+ template 'entity_token_controller.rb.erb', "app/controllers/#{name.underscore}_token_controller.rb"
15
+ end
16
+
17
+ def add_route
18
+ route "post '#{name.underscore}_token' => '#{name.underscore}_token#create'"
19
+ end
20
+
21
+ private
22
+
23
+ def entity_name
24
+ name
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,2 @@
1
+ class <%= entity_name.camelize %>TokenController < KnockRails3::AuthTokenController
2
+ end
@@ -0,0 +1,59 @@
1
+ KnockRails3.setup do |config|
2
+
3
+ ## Expiration claim
4
+ ## ----------------
5
+ ##
6
+ ## How long before a token is expired. If nil is provided, token will
7
+ ## last forever.
8
+ ##
9
+ ## Default:
10
+ # config.token_lifetime = 1.day
11
+
12
+
13
+ ## Audience claim
14
+ ## --------------
15
+ ##
16
+ ## Configure the audience claim to identify the recipients that the token
17
+ ## is intended for.
18
+ ##
19
+ ## Default:
20
+ # config.token_audience = nil
21
+
22
+ ## If using Auth0, uncomment the line below
23
+ # config.token_audience = -> { Rails.application.secrets.auth0_client_id }
24
+
25
+ ## Signature algorithm
26
+ ## -------------------
27
+ ##
28
+ ## Configure the algorithm used to encode the token
29
+ ##
30
+ ## Default:
31
+ # config.token_signature_algorithm = 'HS256'
32
+
33
+ ## Signature key
34
+ ## -------------
35
+ ##
36
+ ## Configure the key used to sign tokens.
37
+ ##
38
+ ## Default:
39
+ # config.token_secret_signature_key = -> { Rails.application.secrets.secret_key_base }
40
+
41
+ ## If using Auth0, uncomment the line below
42
+ # config.token_secret_signature_key = -> { JWT.base64url_decode Rails.application.secrets.auth0_client_secret }
43
+
44
+ ## Public key
45
+ ## ----------
46
+ ##
47
+ ## Configure the public key used to decode tokens, if required.
48
+ ##
49
+ ## Default:
50
+ # config.token_public_key = nil
51
+
52
+ ## Exception Class
53
+ ## ---------------
54
+ ##
55
+ ## Configure the exception to be used when user cannot be found.
56
+ ##
57
+ ## Default:
58
+ # config.not_found_exception_class_name = 'ActiveRecord::RecordNotFound'
59
+ end
@@ -0,0 +1,60 @@
1
+ module KnockRails3::Authenticable
2
+ def authenticate_for entity_class
3
+ getter_name = "current_api_#{entity_class.to_s.parameterize.underscore}"
4
+ define_current_entity_getter(entity_class, getter_name)
5
+ public_send(getter_name)
6
+ end
7
+
8
+ private
9
+
10
+ def token
11
+ params[:token] || token_from_request_headers
12
+ end
13
+
14
+ def method_missing(method, *args)
15
+ prefix, api_prefix, entity_name = method.to_s.split('_', 3)
16
+ case prefix
17
+ when 'authenticate'
18
+ unauthorized_entity(entity_name) unless authenticate_entity(entity_name)
19
+ when 'current'
20
+ authenticate_entity(entity_name)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def authenticate_entity(entity_name)
27
+ if token
28
+ entity_class = entity_name.camelize.constantize
29
+ send(:authenticate_for, entity_class)
30
+ end
31
+ end
32
+
33
+ def unauthorized_entity(entity_name)
34
+ head(:unauthorized)
35
+ end
36
+
37
+ def token_from_request_headers
38
+ unless request.headers['Authorization'].nil?
39
+ request.headers['Authorization'].split.last
40
+ end
41
+ end
42
+
43
+ def define_current_entity_getter entity_class, getter_name
44
+ unless self.respond_to?(getter_name)
45
+ memoization_var_name = "@_#{getter_name}"
46
+ self.class.send(:define_method, getter_name) do
47
+ unless instance_variable_defined?(memoization_var_name)
48
+ current =
49
+ begin
50
+ KnockRails3::AuthToken.new(token: token).entity_for(entity_class)
51
+ rescue KnockRails3.not_found_exception_class, JWT::DecodeError
52
+ nil
53
+ end
54
+ instance_variable_set(memoization_var_name, current)
55
+ end
56
+ instance_variable_get(memoization_var_name)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,6 @@
1
+ module KnockRails3
2
+ class Engine < ::Rails::Engine
3
+ config.eager_load_paths += Dir["#{config.root}/lib/**/"]
4
+ isolate_namespace KnockRails3
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module KnockRails3
2
+ VERSION = "2.1.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :KnockRails3 do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.