grape_devise_token_auth 0.1.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 52925f8c667a9fb733ff96c62b0954d58d58d7cd
4
- data.tar.gz: fa72880434bd05f866161c0c8da9bc9a0af3cb94
3
+ metadata.gz: a6c0879cd01d03c9f719c86c7ee0fe21ddba87d2
4
+ data.tar.gz: bea840a724adba030833ceec4d7418a1eedbd19f
5
5
  SHA512:
6
- metadata.gz: da3ffa3915aa58fe11c467c9e15dee10cb1f78a09a8faa77a0c3fa5b4e8aaaaa2d3de24bc7c500a1a28b226e91279e5f5441b2b50a3d37be89ae74d56d76abba
7
- data.tar.gz: 19b085008ec2b60507a3a968013b78c7ad0bcab3e5cf739cfcae49331c0a6cefe6e79a030a96f12a15f21b874b09fa47115e41420a8503427aa0aafb40f5630b
6
+ metadata.gz: ed1bd798383fee3650292ffe6553fa40ad3eaaba13416d4f24358bbaea61151e471624c5d515d03d72661381351cebab4d4883693af29bc523f3f292769a1349
7
+ data.tar.gz: 4be80289b09ad4ad60e96484290ae900faa32352a36eef00f4f6f38bc5d6770728873369cca078f663e6c6ebf1d40087bdda9bb0cca3bd53acfe3307f417321c
data/README.md CHANGED
@@ -32,7 +32,7 @@ Place this line in an initializer in your rails app or at least somewhere before
32
32
  the grape API will get loaded:
33
33
 
34
34
  ```ruby
35
- GrapeDeviseTokenAuth.setup!(true)
35
+ GrapeDeviseTokenAuth.setup!
36
36
  ```
37
37
 
38
38
  Within the Grape API:
@@ -47,13 +47,30 @@ class Posts < Grape::API
47
47
  end
48
48
  ```
49
49
 
50
- including the helpers line allows you to use methods the `current_user` and
51
- `authenticated?` within the API.
52
-
53
50
  The resource class option allows you to specific the scope that will be
54
51
  authenticated, this corresponds to your devise mapping.
55
52
 
56
- All calls will now be authenticated in the above API via rack middleware.
53
+ Individual endpoints can now be authenticated by calling `authenticate_YOUR_MAPPING_HERE!` (e.g. `authenticate_user!`)
54
+ within them.
55
+
56
+ For Example:
57
+
58
+ ```
59
+ get '/' do
60
+ authenticate_user!
61
+ present Post.all
62
+ end
63
+ ```
64
+
65
+ alternatively to portect all routes place the call in a before block:
66
+
67
+ ```
68
+ before do
69
+ authenticate_user!
70
+ end
71
+ ```
72
+
73
+ [A full example setup can be found here][6]
57
74
 
58
75
  ## Testing and Example
59
76
 
@@ -81,4 +98,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
81
98
  [3]: https://github.com/plataformatec/devise
82
99
  [4]: https://github.com/lynndylanhurley
83
100
  [5]: https://github.com/mcordell/rails_grape_auth
84
-
101
+ [6]: https://github.com/mcordell/rails_grape_auth/blob/7ca6b2f3d989fc23824aaf40fc353fc3e8de40ec/app/api/grape_api/posts.rb
@@ -0,0 +1,49 @@
1
+ module GrapeDeviseTokenAuth
2
+ class AuthHeaders
3
+ extend Forwardable
4
+
5
+ def initialize(warden, mapping, request_start, data)
6
+ @resource = warden.session_serializer.fetch(mapping)
7
+ @request_start = request_start
8
+ @data = data
9
+ end
10
+
11
+ def headers
12
+ return {} unless resource && resource.valid? && client_id
13
+ auth_headers_from_resource
14
+ end
15
+
16
+ private
17
+
18
+ def_delegators :@data, :token, :client_id
19
+ attr_reader :request_start, :resource
20
+
21
+ def batch_request?
22
+ @batch_request ||= resource.tokens[client_id] &&
23
+ resource.tokens[client_id]['updated_at'] &&
24
+ within_batch_request_window?
25
+ end
26
+
27
+ def within_batch_request_window?
28
+ end_of_window = Time.parse(resource.tokens[client_id]['updated_at']) +
29
+ GrapeDeviseTokenAuth.batch_request_buffer_throttle
30
+
31
+ request_start < end_of_window
32
+ end
33
+
34
+ def auth_headers_from_resource
35
+ auth_headers = {}
36
+ resource.with_lock do
37
+ if !GrapeDeviseTokenAuth.change_headers_on_each_request
38
+ auth_headers = resource.extend_batch_buffer(token, client_id)
39
+ elsif batch_request?
40
+ resource.extend_batch_buffer(token, client_id)
41
+ # don't set any headers in a batch request
42
+ else
43
+ auth_headers = resource.create_new_auth_token(client_id)
44
+ end
45
+ end
46
+ auth_headers
47
+ end
48
+ end
49
+ end
@@ -3,7 +3,18 @@ module GrapeDeviseTokenAuth
3
3
  def self.included(_base)
4
4
  Devise.mappings.keys.each do |mapping|
5
5
  define_method("current_#{mapping}") do
6
- warden.session_serializer.fetch(:user)
6
+ warden.session_serializer.fetch(mapping)
7
+ end
8
+
9
+ define_method("authenticate_#{mapping}!") do
10
+ authorizer_data = AuthorizerData.from_env(env)
11
+ devise_interface = DeviseInterface.new(authorizer_data)
12
+ token_authorizer = TokenAuthorizer.new(authorizer_data,
13
+ devise_interface)
14
+ user = token_authorizer.authenticate_from_token(mapping)
15
+ fail Unauthorized unless user
16
+ devise_interface.set_user_in_warden(mapping, user)
17
+ user
7
18
  end
8
19
  end
9
20
  end
@@ -0,0 +1,27 @@
1
+ module GrapeDeviseTokenAuth
2
+ class AuthorizerData
3
+ attr_reader :uid, :client_id, :token, :expiry, :warden
4
+
5
+ def initialize(uid, client_id, token, expiry, warden)
6
+ @uid = uid
7
+ @client_id = client_id
8
+ @token = token
9
+ @expiry = expiry
10
+ @warden = warden
11
+ end
12
+
13
+ def self.from_env(env)
14
+ new(
15
+ env[Configuration::UID_KEY],
16
+ env[Configuration::CLIENT_KEY] || 'default',
17
+ env[Configuration::ACCESS_TOKEN_KEY],
18
+ env[Configuration::EXPIRY_KEY],
19
+ env['warden']
20
+ )
21
+ end
22
+
23
+ def token_prerequisites_present?
24
+ token && uid
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ module GrapeDeviseTokenAuth
2
+ class Configuration
3
+ attr_accessor :batch_request_buffer_throttle, :change_headers_on_each_request, :authenticate_all
4
+ ACCESS_TOKEN_KEY = 'HTTP_ACCESS_TOKEN'
5
+ EXPIRY_KEY = 'HTTP_EXPIRY'
6
+ UID_KEY = 'HTTP_UID'
7
+ CLIENT_KEY = 'HTTP_CLIENT'
8
+
9
+ def initialize
10
+ @batch_request_buffer_throttle ||= DeviseTokenAuth.batch_request_buffer_throttle
11
+ @change_headers_on_each_request ||= DeviseTokenAuth.change_headers_on_each_request
12
+ @authenticate_all = false
13
+ end
14
+
15
+ def auth_all?
16
+ @authenticate_all
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module GrapeDeviseTokenAuth
2
+ class DeviseInterface
3
+ def initialize(data)
4
+ @warden = data.warden
5
+ @client_id = data.client_id
6
+ end
7
+
8
+ # extracted and simplified from Devise
9
+ def set_user_in_warden(scope, resource)
10
+ scope = Devise::Mapping.find_scope!(scope)
11
+ warden.session_serializer.store(resource, scope)
12
+ end
13
+
14
+ def mapping_to_class(m)
15
+ mapping = m ? Devise.mappings[m] : Devise.mappings.values.first
16
+ @resource_class = mapping.to
17
+ end
18
+
19
+ def exisiting_warden_user(resource_class)
20
+ warden_user = warden.user(resource_class.to_s.underscore.to_sym)
21
+ return unless warden_user && warden_user.tokens[@client_id].nil?
22
+ resource = warden_user
23
+ resource.create_new_auth_token
24
+ resource
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :warden
30
+ end
31
+ end
@@ -1,125 +1,59 @@
1
1
  module GrapeDeviseTokenAuth
2
2
  class Middleware
3
- ACCESS_TOKEN_KEY = 'HTTP_ACCESS_TOKEN'
4
- EXPIRY_KEY = 'HTTP_EXPIRY'
5
- UID_KEY = 'HTTP_UID'
6
- CLIENT_KEY = 'HTTP_CLIENT'
3
+ extend Forwardable
7
4
 
8
5
  def initialize(app, resource_name)
9
6
  @app = app
10
- resource_class_from_mapping(resource_name)
7
+ @resource_name = resource_name
11
8
  end
12
9
 
13
10
  def call(env)
14
11
  setup(env)
15
- user = authenticate_from_token
16
- return unauthorized unless user
17
- sign_in_user(user)
18
- responses_with_auth_headers(*@app.call(env))
12
+ begin
13
+ auth_all
14
+ responses_with_auth_headers(*@app.call(env))
15
+ rescue Unauthorized => _e
16
+ return unauthorized
17
+ end
19
18
  end
20
19
 
21
20
  private
22
21
 
23
- attr_reader :uid, :client_id, :token, :expiry, :user, :resource_class, :resource, :warden, :batch_request_buffer_throttle, :request_start
24
-
25
- def setup(env)
26
- @request_start = Time.now
27
- @uid = env[UID_KEY]
28
- @client_id = env[CLIENT_KEY] || 'default'
29
- @token = env[ACCESS_TOKEN_KEY]
30
- @expiry = env[EXPIRY_KEY]
31
- @warden = env['warden']
32
- end
33
-
34
- def sign_in_user(user)
35
- # user already logged in from devise:
36
- return resource if resource
37
- @resource = user
38
- set_user_in_warden(:user, user)
39
- end
40
-
41
- #extracted and simplified from Devise
42
- def set_user_in_warden(scope, resource)
43
- scope = Devise::Mapping.find_scope!(scope)
44
- warden.session_serializer.store(resource, scope)
45
- end
46
-
47
- def resource_from_existing_devise_user
48
- warden_user = warden.user(resource_class.to_s.underscore.to_sym)
49
- return unless warden_user && warden_user.tokens[client_id].nil?
50
- @resource = warden_user
51
- @resource.create_new_auth_token
52
- end
53
-
54
- def authenticate_from_token(mapping = nil)
55
- resource_class_from_mapping(mapping)
56
- return nil unless resource_class
57
-
58
- resource_from_existing_devise_user
59
- return resource if correct_resource_type_logged_in?
22
+ attr_reader :authorizer_data, :token_authorizer, :resource, :request_start
23
+ def_delegators :@authorizer_data, :warden, :token, :client_id
60
24
 
61
- return nil unless token_request_valid?
62
-
63
- user = resource_class.find_by_uid(uid)
64
-
65
- return nil unless user && user.valid_token?(token, client_id)
66
-
67
- user
68
- end
69
-
70
- def token_request_valid?
71
- token && uid
72
- end
73
-
74
- def correct_resource_type_logged_in?
75
- resource && resource.class == resource_class
76
- end
77
-
78
- def resource_class_from_mapping(m)
79
- mapping = m ? Devise.mappings[m] : Devise.mappings.values.first
80
- @resource_class = mapping.to
25
+ def auth_all
26
+ return if skip_auth_all?
27
+ user = token_authorizer.authenticate_from_token(@resource_name)
28
+ fail Unauthorized unless user
29
+ sign_in_user(user)
81
30
  end
82
31
 
83
- def valid?
84
- keys_present? && !expired?
32
+ def skip_auth_all?
33
+ !GrapeDeviseTokenAuth.configuration.auth_all?
85
34
  end
86
35
 
87
- def keys_present?
88
- uid.present? && client_id.present? && token.present?
36
+ def setup(env)
37
+ @request_start = Time.now
38
+ @authorizer_data = AuthorizerData.from_env(env)
39
+ @devise_interface = DeviseInterface.new(@authorizer_data)
40
+ @token_authorizer = TokenAuthorizer.new(@authorizer_data,
41
+ @devise_interface)
89
42
  end
90
43
 
91
- def expired?
92
- env[EXPIRY_KEY].to_i < Time.now.to_i
44
+ def sign_in_user(user)
45
+ @devise_interface.set_user_in_warden(@resource_name, user)
93
46
  end
94
47
 
95
48
  def responses_with_auth_headers(status, headers, response)
49
+ auth_headers = AuthHeaders.new(warden, @resource_name, request_start, authorizer_data)
96
50
  [
97
51
  status,
98
- headers.merge(auth_headers),
52
+ headers.merge(auth_headers.headers),
99
53
  response
100
54
  ]
101
55
  end
102
56
 
103
- def auth_headers
104
- return {} unless resource && resource.valid? && client_id
105
- auth_headers_from_resource
106
- end
107
-
108
- def auth_headers_from_resource
109
- auth_headers = {}
110
- resource.with_lock do
111
- if !DeviseTokenAuth.change_headers_on_each_request
112
- auth_headers = resource.extend_batch_buffer(token, client_id)
113
- elsif batch_request?
114
- resource.extend_batch_buffer(token, client_id)
115
- # don't set any headers in a batch request
116
- else
117
- auth_headers = resource.create_new_auth_token(client_id)
118
- end
119
- end
120
- auth_headers
121
- end
122
-
123
57
  def unauthorized
124
58
  [401,
125
59
  { 'Content-Type' => 'application/json'
@@ -127,17 +61,5 @@ module GrapeDeviseTokenAuth
127
61
  []
128
62
  ]
129
63
  end
130
-
131
- def batch_request?
132
- @batch_request ||= resource.tokens[client_id] &&
133
- resource.tokens[client_id]['updated_at'] &&
134
- within_batch_request_window?
135
- end
136
-
137
- def within_batch_request_window?
138
- end_of_window = Time.parse(resource.tokens[client_id]['updated_at']) +
139
- DeviseTokenAuth.batch_request_buffer_throttle
140
- request_start < end_of_window
141
- end
142
64
  end
143
65
  end
@@ -0,0 +1,46 @@
1
+ module GrapeDeviseTokenAuth
2
+ class TokenAuthorizer
3
+ extend Forwardable
4
+
5
+ def initialize(data, devise_interface)
6
+ @data = data
7
+ @devise_interface = devise_interface
8
+ end
9
+
10
+ def authenticate_from_token(mapping = nil)
11
+ @resource_class = devise_interface.mapping_to_class(mapping)
12
+ return nil unless resource_class
13
+
14
+ resource_from_existing_devise_user
15
+ return resource if correct_resource_type_logged_in?
16
+
17
+ return nil unless data.token_prerequisites_present?
18
+ load_user_from_uid
19
+ return nil unless user_authenticated?
20
+
21
+ user
22
+ end
23
+
24
+ private
25
+
26
+ attr_accessor :resource_class
27
+ attr_reader :data, :resource, :user, :devise_interface
28
+ def_delegators :@data, :warden, :uid, :token, :client_id
29
+
30
+ def user_authenticated?
31
+ user && user.valid_token?(token, client_id)
32
+ end
33
+
34
+ def load_user_from_uid
35
+ @user = resource_class.find_by_uid(uid)
36
+ end
37
+
38
+ def resource_from_existing_devise_user
39
+ @resource = @devise_interface.exisiting_warden_user(resource_class)
40
+ end
41
+
42
+ def correct_resource_type_logged_in?
43
+ resource && resource.class == resource_class
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,4 @@
1
+ module GrapeDeviseTokenAuth
2
+ class Unauthorized < Exception
3
+ end
4
+ end
@@ -1,3 +1,3 @@
1
1
  module GrapeDeviseTokenAuth
2
- VERSION = "0.1.0"
2
+ VERSION = '0.1.1'
3
3
  end
@@ -1,18 +1,35 @@
1
- require 'grape_devise_token_auth/version'
2
- require 'grape_devise_token_auth/middleware'
3
- require 'grape_devise_token_auth/auth_helpers'
1
+ %w(version middleware auth_helpers authorizer_data unauthorized
2
+ token_authorizer configuration auth_headers devise_interface).each do |file|
3
+ require "grape_devise_token_auth/#{file}"
4
+ end
5
+
4
6
  require 'grape'
5
7
 
6
8
  module GrapeDeviseTokenAuth
7
- def self.setup!(middleware = false)
8
- add_auth_strategy if middleware
9
- end
9
+ class << self
10
+ extend Forwardable
11
+
12
+ def_delegators :configuration, :batch_request_buffer_throttle, :change_headers_on_each_request
13
+
14
+ def configuration
15
+ @configuration ||= Configuration.new
16
+ end
17
+
18
+ def config
19
+ yield(configuration)
20
+ end
21
+
22
+ def setup!(middleware = false)
23
+ yield(configuration) if block_given?
24
+ add_auth_strategy
25
+ end
10
26
 
11
- def self.add_auth_strategy
12
- Grape::Middleware::Auth::Strategies.add(
13
- :grape_devise_token_auth,
14
- GrapeDeviseTokenAuth::Middleware,
15
- ->(options) { [options[:resource_class]] }
16
- )
27
+ def add_auth_strategy
28
+ Grape::Middleware::Auth::Strategies.add(
29
+ :grape_devise_token_auth,
30
+ GrapeDeviseTokenAuth::Middleware,
31
+ ->(options) { [options[:resource_class]] }
32
+ )
33
+ end
17
34
  end
18
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape_devise_token_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Cordell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-20 00:00:00.000000000 Z
11
+ date: 2015-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -98,8 +98,14 @@ files:
98
98
  - bin/setup
99
99
  - grape_devise_token_auth.gemspec
100
100
  - lib/grape_devise_token_auth.rb
101
+ - lib/grape_devise_token_auth/auth_headers.rb
101
102
  - lib/grape_devise_token_auth/auth_helpers.rb
103
+ - lib/grape_devise_token_auth/authorizer_data.rb
104
+ - lib/grape_devise_token_auth/configuration.rb
105
+ - lib/grape_devise_token_auth/devise_interface.rb
102
106
  - lib/grape_devise_token_auth/middleware.rb
107
+ - lib/grape_devise_token_auth/token_authorizer.rb
108
+ - lib/grape_devise_token_auth/unauthorized.rb
103
109
  - lib/grape_devise_token_auth/version.rb
104
110
  homepage: https://github.com/mcordell/grape_devise_token_auth
105
111
  licenses: