grape_devise_token_auth 0.1.0 → 0.1.1

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
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: