api_guard 0.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 (35) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +597 -0
  4. data/Rakefile +24 -0
  5. data/app/controllers/api_guard/application_controller.rb +7 -0
  6. data/app/controllers/api_guard/authentication_controller.rb +29 -0
  7. data/app/controllers/api_guard/passwords_controller.rb +27 -0
  8. data/app/controllers/api_guard/registration_controller.rb +28 -0
  9. data/app/controllers/api_guard/tokens_controller.rb +27 -0
  10. data/app/models/api_guard/application_record.rb +5 -0
  11. data/app/views/layouts/api_guard/application.html.erb +14 -0
  12. data/config/routes.rb +4 -0
  13. data/lib/api_guard.rb +32 -0
  14. data/lib/api_guard/engine.rb +15 -0
  15. data/lib/api_guard/jwt_auth/authentication.rb +83 -0
  16. data/lib/api_guard/jwt_auth/blacklist_token.rb +31 -0
  17. data/lib/api_guard/jwt_auth/json_web_token.rb +66 -0
  18. data/lib/api_guard/jwt_auth/refresh_jwt_token.rb +42 -0
  19. data/lib/api_guard/models/concerns.rb +25 -0
  20. data/lib/api_guard/modules.rb +24 -0
  21. data/lib/api_guard/resource_mapper.rb +41 -0
  22. data/lib/api_guard/response_formatters/renderer.rb +19 -0
  23. data/lib/api_guard/route_mapper.rb +81 -0
  24. data/lib/api_guard/test/controller_helper.rb +11 -0
  25. data/lib/api_guard/version.rb +3 -0
  26. data/lib/generators/api_guard/controllers/USAGE +11 -0
  27. data/lib/generators/api_guard/controllers/controllers_generator.rb +23 -0
  28. data/lib/generators/api_guard/controllers/templates/authentication_controller.rb +27 -0
  29. data/lib/generators/api_guard/controllers/templates/passwords_controller.rb +25 -0
  30. data/lib/generators/api_guard/controllers/templates/registration_controller.rb +26 -0
  31. data/lib/generators/api_guard/controllers/templates/tokens_controller.rb +25 -0
  32. data/lib/generators/api_guard/initializer/USAGE +8 -0
  33. data/lib/generators/api_guard/initializer/initializer_generator.rb +11 -0
  34. data/lib/generators/api_guard/initializer/templates/initializer.rb +13 -0
  35. metadata +217 -0
@@ -0,0 +1,25 @@
1
+ module ApiGuard
2
+ module Models
3
+ module Concerns
4
+ extend ActiveSupport::Concern
5
+
6
+ class_methods do
7
+ def api_guard_associations(refresh_token: nil, blacklisted_token: nil)
8
+ return if ApiGuard.api_guard_associations[self.name]
9
+
10
+ ApiGuard.api_guard_associations[self.name] = {}
11
+ ApiGuard.api_guard_associations[self.name][:refresh_token] = refresh_token
12
+ ApiGuard.api_guard_associations[self.name][:blacklisted_token] = blacklisted_token
13
+ end
14
+
15
+ def refresh_token_association
16
+ ApiGuard.api_guard_associations.dig(self.name, :refresh_token)
17
+ end
18
+
19
+ def blacklisted_token_association
20
+ ApiGuard.api_guard_associations.dig(self.name, :blacklisted_token)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ require "api_guard/resource_mapper"
2
+ require "api_guard/jwt_auth/json_web_token"
3
+ require "api_guard/jwt_auth/authentication"
4
+ require "api_guard/jwt_auth/refresh_jwt_token"
5
+ require "api_guard/jwt_auth/blacklist_token"
6
+ require "api_guard/response_formatters/renderer"
7
+ require "api_guard/models/concerns"
8
+
9
+ module ApiGuard
10
+ module Modules
11
+ ActiveSupport.on_load(:action_controller) {
12
+ include ApiGuard::Resource
13
+ include ApiGuard::JwtAuth::JsonWebToken
14
+ include ApiGuard::JwtAuth::Authentication
15
+ include ApiGuard::JwtAuth::RefreshJwtToken
16
+ include ApiGuard::JwtAuth::BlacklistToken
17
+ include ApiGuard::ResponseFormatters::Renderer
18
+ }
19
+
20
+ ActiveSupport.on_load(:active_record) {
21
+ include ApiGuard::Models::Concerns
22
+ }
23
+ end
24
+ end
@@ -0,0 +1,41 @@
1
+ module ApiGuard
2
+ class ResourceMapper
3
+ attr_reader :resource_name, :resource_class, :resource_instance_name
4
+
5
+ def initialize(routes_for, class_name)
6
+ @resource_name = routes_for.singularize
7
+ @resource_class = class_name.constantize
8
+ @resource_instance_name = "@api_guard_#{routes_for}"
9
+ end
10
+ end
11
+
12
+ module Resource
13
+ def resource
14
+ instance_variable_get(mapped_resource_instance)
15
+ end
16
+
17
+ def resource=(new_resource)
18
+ instance_variable_set(mapped_resource_instance, new_resource)
19
+ end
20
+
21
+ def current_resource_mapping
22
+ request.env["api_guard.mapping"]
23
+ end
24
+
25
+ def resource_name
26
+ current_resource_mapping.resource_name
27
+ end
28
+
29
+ def resource_class
30
+ current_resource_mapping.resource_class
31
+ end
32
+
33
+ def mapped_resource_instance
34
+ current_resource_mapping.resource_instance_name
35
+ end
36
+
37
+ def init_resource(params)
38
+ self.resource = resource_class.new(params)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ module ApiGuard
2
+ module ResponseFormatters
3
+ module Renderer
4
+ def render_success(data: nil, message: nil)
5
+ resp_data = { status: 'success' }
6
+ resp_data[:message] = message if message
7
+
8
+ render json: resp_data, status: 200
9
+ end
10
+
11
+ def render_error(status, options = {})
12
+ data = { status: 'error' }
13
+ data[:error] = options[:object] ? options[:object].errors.full_messages[0] : options[:message]
14
+
15
+ render json: data, status: status
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,81 @@
1
+ # Referenced from devise gem:
2
+ # https://github.com/plataformatec/devise/blob/master/lib/devise/rails/routes.rb
3
+ #
4
+ # Customizable API routes
5
+ module ActionDispatch::Routing
6
+ class Mapper
7
+ def api_guard_routes(options = {})
8
+ routes_for = options.delete(:for).to_s || 'users'
9
+
10
+ controllers = default_controllers(options[:only], options[:except])
11
+ controller_options = options.delete(:controller)
12
+
13
+ options[:as] = options[:as] || routes_for.singularize
14
+ options[:path] = options[:path] || routes_for
15
+
16
+ api_guard_scope(routes_for) do |mapped_resource|
17
+ scope options do
18
+ generate_routes(mapped_resource, controller_options, controllers)
19
+ end
20
+ end
21
+ end
22
+
23
+ def api_guard_scope(routes_for)
24
+ mapped_resource = ApiGuard.mapped_resource[routes_for.to_sym].presence || ApiGuard.map_resource(routes_for, routes_for.classify)
25
+
26
+ constraint = lambda do |request|
27
+ request.env["api_guard.mapping"] = mapped_resource
28
+ true
29
+ end
30
+
31
+ constraints(constraint) do
32
+ yield(mapped_resource)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def default_controllers(only, except)
39
+ return only if only
40
+
41
+ controllers = %i[registration authentication tokens passwords]
42
+ except ? (controllers - except) : controllers
43
+ end
44
+
45
+ def generate_routes(mapped_resource, options, controllers)
46
+ options ||= {}
47
+
48
+ controllers -= %i[tokens] unless mapped_resource.resource_class.refresh_token_association
49
+
50
+ controllers.each do |controller|
51
+ send("#{controller.to_s}_routes", options[controller])
52
+ end
53
+ end
54
+
55
+ def authentication_routes(controller_name = nil)
56
+ controller_name = controller_name || 'api_guard/authentication'
57
+
58
+ post 'sign_in' => "#{controller_name}#create"
59
+ delete 'sign_out' => "#{controller_name}#destroy"
60
+ end
61
+
62
+ def registration_routes(controller_name = nil)
63
+ controller_name = controller_name || 'api_guard/registration'
64
+
65
+ post 'sign_up' => "#{controller_name}#create"
66
+ delete 'delete' => "#{controller_name}#destroy"
67
+ end
68
+
69
+ def passwords_routes(controller_name = nil)
70
+ controller_name = controller_name || 'api_guard/passwords'
71
+
72
+ patch 'passwords' => "#{controller_name}#update"
73
+ end
74
+
75
+ def tokens_routes(controller_name = nil)
76
+ controller_name = controller_name || 'api_guard/tokens'
77
+
78
+ post 'tokens' => "#{controller_name}#create"
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,11 @@
1
+ require 'api_guard/jwt_auth/json_web_token'
2
+ require 'api_guard/jwt_auth/refresh_jwt_token'
3
+
4
+ module ApiGuard
5
+ module Test
6
+ module ControllerHelper
7
+ include ApiGuard::JwtAuth::JsonWebToken
8
+ include ApiGuard::JwtAuth::RefreshJwtToken
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module ApiGuard
2
+ VERSION = '0.1.1'
3
+ end
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Generates all API Guard controllers in app/controllers/
3
+
4
+ Example:
5
+ rails generate api_guard:controllers users
6
+
7
+ This will create:
8
+ app/controllers/users/registration_controller.rb
9
+ app/controllers/users/authentication_controller.rb
10
+ app/controllers/users/tokens_controller.rb
11
+ app/controllers/users/passwords_controller.rb
@@ -0,0 +1,23 @@
1
+ module ApiGuard
2
+ class ControllersGenerator < Rails::Generators::Base
3
+ CONTROLLERS = %i[registration authentication tokens passwords]
4
+
5
+ desc 'Generates API Guard controllers in app/controllers/'
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ argument :scope, required: true,
9
+ desc: "The scope to create controllers in, e.g. users, admins"
10
+
11
+ class_option :controllers, aliases: "-c", type: :array,
12
+ desc: "Specify the controllers to generate (#{CONTROLLERS.join(', ')})"
13
+
14
+ def create_controllers
15
+ @controller_scope = scope.camelize
16
+ controllers = options[:controllers] || CONTROLLERS
17
+
18
+ controllers.each do |controller_name|
19
+ template "#{controller_name}_controller.rb", "app/controllers/#{scope}/#{controller_name}_controller.rb"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module <%= @controller_scope %>
2
+ class AuthenticationController < ApiGuard::AuthenticationController
3
+ # before_action :find_resource, only: [:create]
4
+ # before_action :authenticate_resource, only: [:destroy]
5
+
6
+ # def create
7
+ # if resource.authenticate(params[:password])
8
+ # create_token_and_set_header(resource, resource_name)
9
+ # render_success(data: resource)
10
+ # else
11
+ # render_error(422, message: 'Invalid login credentials')
12
+ # end
13
+ # end
14
+
15
+ # def destroy
16
+ # blacklist_token
17
+ # render_success(message: 'Signed out successfully')
18
+ # end
19
+
20
+ # private
21
+
22
+ # def find_resource
23
+ # self.resource = resource_class.find_by(email: params[:email].downcase.strip) if params[:email].present?
24
+ # render_error(422, message: 'Invalid login credentials') unless resource
25
+ # end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ module <%= @controller_scope %>
2
+ class PasswordsController < ApiGuard::PasswordsController
3
+ # before_action :authenticate_resource, only: [:update]
4
+
5
+ # def update
6
+ # invalidate_old_jwt_tokens(current_resource)
7
+ #
8
+ # if current_resource.update_attributes(password_params)
9
+ # blacklist_token
10
+ # destroy_all_refresh_tokens(current_resource)
11
+ #
12
+ # create_token_and_set_header(current_resource, resource_name)
13
+ # render_success(data: current_resource)
14
+ # else
15
+ # render_error(422, object: current_resource)
16
+ # end
17
+ # end
18
+
19
+ # private
20
+
21
+ # def password_params
22
+ # params.require(resource_name.to_sym).permit(:password, :password_confirmation)
23
+ # end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ module <%= @controller_scope %>
2
+ class RegistrationController < ApiGuard::RegistrationController
3
+ # before_action :authenticate_resource, only: [:destroy]
4
+
5
+ # def create
6
+ # init_resource(sign_up_params)
7
+ # if resource.save
8
+ # create_token_and_set_header(resource, resource_name)
9
+ # render_success(data: resource, message: "#{resource_name.capitalize} created successfully")
10
+ # else
11
+ # render_error(422, object: resource)
12
+ # end
13
+ # end
14
+
15
+ # def destroy
16
+ # current_resource.destroy
17
+ # render_success(message: "#{resource_name.capitalize} destroyed successfully")
18
+ # end
19
+
20
+ # private
21
+
22
+ # def sign_up_params
23
+ # params.require(resource_name.to_sym).permit(:email, :password, :password_confirmation)
24
+ # end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ module <%= @controller_scope %>
2
+ class TokensController < ApiGuard::TokensController
3
+ # before_action :authenticate_resource, only: [:create]
4
+ # before_action :find_refresh_token, only: [:create]
5
+
6
+ # def create
7
+ # @refresh_token.destroy
8
+ # create_token_and_set_header(current_resource, resource_name)
9
+ # render_success(data: current_resource)
10
+ # end
11
+
12
+ # private
13
+
14
+ # def find_refresh_token
15
+ # refresh_token_from_header = request.headers['Refresh-Token']
16
+ #
17
+ # if refresh_token_from_header
18
+ # @refresh_token = find_refresh_token_of(current_resource, refresh_token_from_header)
19
+ # return render_error(401, message: 'Invalid refresh token') unless @refresh_token
20
+ # else
21
+ # render_error(401, message: 'Refresh token is missing in the request')
22
+ # end
23
+ # end
24
+ end
25
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Creates initializer for configuring API Guard
3
+
4
+ Example:
5
+ rails generate api_guard:initializer
6
+
7
+ This will create:
8
+ config/initializers/api_guard.rb
@@ -0,0 +1,11 @@
1
+ module ApiGuard
2
+ class InitializerGenerator < Rails::Generators::Base
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ desc 'Creates initializer for configuring API Guard'
6
+
7
+ def create_initializer
8
+ copy_file 'initializer.rb', 'config/initializers/api_guard.rb'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ ApiGuard.setup do |config|
2
+ # Validity of the JWT access token
3
+ # Default: 1 day
4
+ config.token_validity = 1.day
5
+
6
+ # Secret key for signing (encoding & decoding) the JWT access token
7
+ # Default: 'secret_key_base' from Rails secrets
8
+ config.token_signing_secret = Rails.application.secrets.secret_key_base
9
+
10
+ # Invalidate old tokens on changing the password
11
+ # Default: false
12
+ config.invalidate_old_tokens_on_password_change = false
13
+ end
metadata ADDED
@@ -0,0 +1,217 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: api_guard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Gokul Murali
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-02-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jwt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.1.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.1.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: rails
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.1'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 5.1.5
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '5.1'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 5.1.5
53
+ - !ruby/object:Gem::Dependency
54
+ name: sqlite3
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.3'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.3.13
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.3.13
73
+ - !ruby/object:Gem::Dependency
74
+ name: bcrypt
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '3.1'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 3.1.11
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.1'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 3.1.11
93
+ - !ruby/object:Gem::Dependency
94
+ name: rspec-rails
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '3.7'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 3.7.2
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '3.7'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 3.7.2
113
+ - !ruby/object:Gem::Dependency
114
+ name: factory_bot_rails
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '4.8'
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 4.8.2
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '4.8'
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 4.8.2
133
+ - !ruby/object:Gem::Dependency
134
+ name: simplecov
135
+ requirement: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '0.16'
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: 0.16.1
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: '0.16'
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 0.16.1
153
+ description: JWT authentication solution for Rails APIs
154
+ email:
155
+ - m.gokul595@gmail.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - MIT-LICENSE
161
+ - README.md
162
+ - Rakefile
163
+ - app/controllers/api_guard/application_controller.rb
164
+ - app/controllers/api_guard/authentication_controller.rb
165
+ - app/controllers/api_guard/passwords_controller.rb
166
+ - app/controllers/api_guard/registration_controller.rb
167
+ - app/controllers/api_guard/tokens_controller.rb
168
+ - app/models/api_guard/application_record.rb
169
+ - app/views/layouts/api_guard/application.html.erb
170
+ - config/routes.rb
171
+ - lib/api_guard.rb
172
+ - lib/api_guard/engine.rb
173
+ - lib/api_guard/jwt_auth/authentication.rb
174
+ - lib/api_guard/jwt_auth/blacklist_token.rb
175
+ - lib/api_guard/jwt_auth/json_web_token.rb
176
+ - lib/api_guard/jwt_auth/refresh_jwt_token.rb
177
+ - lib/api_guard/models/concerns.rb
178
+ - lib/api_guard/modules.rb
179
+ - lib/api_guard/resource_mapper.rb
180
+ - lib/api_guard/response_formatters/renderer.rb
181
+ - lib/api_guard/route_mapper.rb
182
+ - lib/api_guard/test/controller_helper.rb
183
+ - lib/api_guard/version.rb
184
+ - lib/generators/api_guard/controllers/USAGE
185
+ - lib/generators/api_guard/controllers/controllers_generator.rb
186
+ - lib/generators/api_guard/controllers/templates/authentication_controller.rb
187
+ - lib/generators/api_guard/controllers/templates/passwords_controller.rb
188
+ - lib/generators/api_guard/controllers/templates/registration_controller.rb
189
+ - lib/generators/api_guard/controllers/templates/tokens_controller.rb
190
+ - lib/generators/api_guard/initializer/USAGE
191
+ - lib/generators/api_guard/initializer/initializer_generator.rb
192
+ - lib/generators/api_guard/initializer/templates/initializer.rb
193
+ homepage: https://github.com/Gokul595/api_guard
194
+ licenses:
195
+ - MIT
196
+ metadata: {}
197
+ post_install_message:
198
+ rdoc_options: []
199
+ require_paths:
200
+ - lib
201
+ required_ruby_version: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - ">="
204
+ - !ruby/object:Gem::Version
205
+ version: 2.3.0
206
+ required_rubygems_version: !ruby/object:Gem::Requirement
207
+ requirements:
208
+ - - ">="
209
+ - !ruby/object:Gem::Version
210
+ version: '0'
211
+ requirements: []
212
+ rubyforge_project:
213
+ rubygems_version: 2.6.14
214
+ signing_key:
215
+ specification_version: 4
216
+ summary: Rails API authentication made easy
217
+ test_files: []