devise_oauth_token_authenticatable 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in devise_oauth_token_authenticatable.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Marc Leglise
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # Devise OauthTokenAuthenticatable
2
+
3
+ Ruby gem that allows Rails 3 + Devise to authenticate users via an OAuth Access
4
+ Token from a 3rd party provider.
5
+
6
+ There are plenty of gems out there that deal with being an OAuth2 "consumer",
7
+ where you redirect users to an OAuth2 "provider", allowing you to hand off
8
+ authentication to a separate service. There are also plenty of gems that set
9
+ you up as your own OAuth2 provider. ***BUT***, what happens when you want to
10
+ separate your "authentication" server from your "resource" server?
11
+
12
+ This gem is meant to be used on an API "resource" server, where you want to
13
+ accept OAuth Access Tokens from a client, and validate them against a separate
14
+ "authentication" server. This communication is outside the scope of the
15
+ official [OAuth 2 spec](http://tools.ietf.org/html/draft-ietf-oauth-v2-27), but
16
+ there is a need for it anyway.
17
+
18
+ Comments and suggestions are welcome.
19
+
20
+ ## HERE BE DRAGONS!
21
+ This gem is an extraction from another project, and I'm ashamed to say does not
22
+ have any test coverage yet. If you have any suggestions for how to properly
23
+ test a Devise module like this, please drop me a line.
24
+
25
+ ## Requirements
26
+
27
+ * Devise authentication library
28
+ * Rails 3.1 or higher
29
+
30
+ ## Installation
31
+
32
+ ### Add this line to your application's Gemfile:
33
+
34
+ gem 'devise_oauth_token_authenticatable'
35
+
36
+ And then execute:
37
+
38
+ $ bundle
39
+
40
+ ### Configure Devise to point to your OAuth authorization server
41
+
42
+ ```ruby
43
+ # config/initializers/devise.rb
44
+ Devise.setup do |config|
45
+ # ==> Configuration for :oauth_token_authenticatable
46
+ config.oauth_client_id = "app-id-goes-here"
47
+ config.oauth_client_secret = "secret-key-goes-here"
48
+ config.oauth_token_validation_url = "/oauth/verify_credentials"
49
+ config.oauth_client_options = {
50
+ site: "https://your.oauth.host.com",
51
+ token_method: :get
52
+ }
53
+ end
54
+ ```
55
+
56
+ ### Configure User to support Access Token authentication
57
+
58
+ You must define the class method `find_for_oauth_token_authentication`, which
59
+ will be called by Devise when trying to lookup the user record. It will receive
60
+ one string parameter, the Access Token string, as provided by the client.
61
+
62
+ Your method can then call `validate_oauth_token`, which will do the heavy
63
+ lifting of contacting your OAuth Authentication Server at the
64
+ token_validation_url and returning an
65
+ [OAuth2::AccessToken](https://github.com/intridea/oauth2) object. Your method
66
+ can then act as appropriate with the returned data, including using the object
67
+ to make additional calls to the Authentication Server.
68
+
69
+ Your method should return `nil` if the user cannot be authenticated, or an
70
+ initialized (and persisted) User object if successful.
71
+
72
+ NOTE: The docs all refer to the `User` model, but it can be whatever model you
73
+ use with Devise.
74
+
75
+ ```ruby
76
+ class User
77
+ devise :oauth_token_authenticatable
78
+
79
+ def self.find_for_oauth_token_authentication(token_str)
80
+ access_token = validate_oauth_token(token_str)
81
+ return nil unless access_token
82
+ User.find_or_create_by_email( access_token.params['email'] )
83
+ end
84
+ end
85
+ ```
86
+
87
+ ## Practical Application
88
+
89
+ So what does this give you?
90
+
91
+ A client application can now make calls to your app, providing an access token
92
+ in either of two ways.
93
+
94
+ ### Option 1: Query string param
95
+
96
+ http://your.app.com/api/cool_stuff?access_token=1234abc
97
+
98
+ ### Option 2: Header param
99
+
100
+ GET /api/cool_stuff HTTP/1.1
101
+ Authorization: Bearer 1234abc
102
+ Host: your.app.com
103
+
104
+ Then, anywhere you would normally call `current_user` with Devise, it will be
105
+ automatically interpreted and turned into a real user object. But it's not
106
+ based on the session or cookie, it's based on the Access Token!
107
+
108
+ ## To Do
109
+
110
+ * Add tests!
111
+ * Remove the dependency on `rack-oauth2`
112
+ * Better error handling
113
+
114
+ ## Contributing
115
+
116
+ 1. Fork it
117
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
118
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
119
+ 4. Push to the branch (`git push origin my-new-feature`)
120
+ 5. Create new Pull Request
121
+
122
+ ## Credits
123
+
124
+ This gem was developed by Marc Leglise.
125
+ It borrows heavily from [devise\_oauth2\_providable](https://github.com/socialcast/devise_oauth2_providable)
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/devise/oauth_token_authenticatable/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "devise_oauth_token_authenticatable"
6
+ gem.version = Devise::OauthTokenAuthenticatable::VERSION
7
+ gem.authors = ["Marc Leglise"]
8
+ gem.email = ["mleglise@gmail.com"]
9
+ gem.summary = %q{Allows Rails 3 + Devise to authenticate users via an OAuth Access Token from a 3rd party provider.}
10
+ gem.description = %q{
11
+ There are plenty of gems out there that deal with being an OAuth2 "consumer",
12
+ where you redirect users to an OAuth2 "provider", allowing you to hand off
13
+ authentication to a separate service. There are also plenty of gems that set
14
+ you up as your own OAuth2 provider. ***BUT***, what happens when you want to
15
+ separate your "authentication" server from your "resource" server?
16
+
17
+ This gem is meant to be used on an API "resource" server, where you want to
18
+ accept OAuth Access Tokens from a client, and validate them against a separate
19
+ "authentication" server. This communication is outside the scope of the
20
+ official OAuth 2 spec, but there is a need for it anyway.
21
+ }
22
+ gem.homepage = "https://github.com/mleglise/devise_oauth_token_authenticatable"
23
+
24
+ gem.files = `git ls-files`.split($\)
25
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
26
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
27
+ gem.require_paths = ["lib"]
28
+
29
+ gem.add_runtime_dependency("rails", [">= 3.1.0"])
30
+ gem.add_runtime_dependency("devise", [">= 2.1.0"])
31
+ gem.add_runtime_dependency("oauth2", ["~> 0.6.1"])
32
+ gem.add_runtime_dependency("rack-oauth2", [">= 0.14.0"])
33
+ end
@@ -0,0 +1,67 @@
1
+ # Originally based on:
2
+ # https://github.com/socialcast/devise_oauth2_providable/blob/master/lib/devise/oauth2_providable/models/oauth2_password_grantable.rb
3
+
4
+ require 'devise/models'
5
+
6
+ module Devise
7
+ module Models
8
+ # The OauthTokenAuthenticatable module is responsible for validating an authentication token
9
+ # and returning basic data about the account.
10
+ #
11
+ # == Options
12
+ #
13
+ # OauthTokenAuthenticatable adds the following options to devise_for:
14
+ #
15
+ # * +oauth_token_validation_url+: Defines the relative URL path to validate a given Access Token. E.g. /api/getUserInfoByAccessToken
16
+ # * +oauth_client_id+: Your app ID, as registered with your authentication server.
17
+ # * +oauth_client_secret+: Your app secret, provided by your authentication server.
18
+ # * +oauth_client_options+: A hash of options passed to the OAuth2::Client. Should include the 'site' param.
19
+ #
20
+ module OauthTokenAuthenticatable
21
+ extend ActiveSupport::Concern
22
+
23
+ # Hook called after oauth token authentication.
24
+ def after_oauth_token_authentication
25
+ end
26
+
27
+ module ClassMethods
28
+ def find_for_oauth_token_authentication(conditions)
29
+ raise NotImplementedError, "You must define find_for_oauth_token_authentication in your User model"
30
+ end
31
+
32
+ def validate_oauth_token(token_str)
33
+ # Make a new OAuth2 client and call the validation URL
34
+ @@client ||= ::OAuth2::Client.new(oauth_client_id, oauth_client_secret, oauth_client_options)
35
+ params = { # Params for client.request
36
+ client_id: oauth_client_id,
37
+ access_token: token_str
38
+ }
39
+ access_token_opts = {} # Params initializing AccessToken object
40
+
41
+ opts = {}
42
+ if @@client.options[:token_method] == :post
43
+ headers = params.delete(:headers)
44
+ opts[:body] = params
45
+ opts[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
46
+ opts[:headers].merge!(headers) if headers
47
+ else
48
+ opts[:params] = params
49
+ end
50
+
51
+ response = @@client.request(@@client.options[:token_method], oauth_token_validation_url, opts)
52
+ # Return the OAuth2::AccessToken object
53
+ raise ::OAuth2::Error.new(response) if @@client.options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
54
+ ::OAuth2::AccessToken.from_hash(@@client, response.parsed.merge(access_token_opts))
55
+ end
56
+
57
+ Devise::Models.config(self,
58
+ :oauth_token_validation_url,
59
+ :oauth_client_id,
60
+ :oauth_client_secret,
61
+ :oauth_client_options
62
+ )
63
+ end
64
+
65
+ end # OauthTokenAuthenticatable
66
+ end # Models
67
+ end # Devise
@@ -0,0 +1,47 @@
1
+ # Originally based on:
2
+ # https://github.com/socialcast/devise_oauth2_providable/blob/master/lib/devise/oauth2_providable/strategies/oauth2_providable_strategy.rb
3
+
4
+ require 'devise/strategies/base'
5
+
6
+ # TODO: Specify a failure app that's custom for this strategy.
7
+ # If the strategy was valid (because it had an access token in the header or params)
8
+ # but it failed, then the responses should be in the 4XX range, not 3XX redirects
9
+
10
+ module Devise
11
+ module Strategies
12
+ class OauthTokenAuthenticatable < Authenticatable
13
+
14
+ def valid?
15
+ @req = Rack::OAuth2::Server::Resource::Bearer::Request.new(env)
16
+ @req.oauth2?
17
+ end
18
+
19
+ def authenticate!
20
+ @req.setup!
21
+ resource = mapping.to.find_for_oauth_token_authentication( @req.access_token )
22
+ if validate(resource)
23
+ resource.after_oauth_token_authentication
24
+ success! resource
25
+ elsif !halted?
26
+ fail(:invalid_token)
27
+ end
28
+ end
29
+
30
+ # Do not store OauthToken validation in session.
31
+ # This forces the strategy to check the token on every request.
32
+ def store?
33
+ false
34
+ end
35
+
36
+ private
37
+
38
+ # Do not use remember_me behavior with token.
39
+ def remember_me?
40
+ false
41
+ end
42
+
43
+ end # OauthTokenAuthenticatable
44
+ end # Strategies
45
+ end # Devise
46
+
47
+ Warden::Strategies.add(:oauth_token_authenticatable, Devise::Strategies::OauthTokenAuthenticatable)
@@ -0,0 +1,5 @@
1
+ module Devise
2
+ module OauthTokenAuthenticatable
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ # Originally based on:
2
+ # https://github.com/socialcast/devise_oauth2_providable/blob/master/lib/devise_oauth2_providable.rb
3
+
4
+ require 'devise'
5
+ require 'oauth2'
6
+ require 'rack/oauth2'
7
+ require 'devise/oauth_token_authenticatable/strategies/oauth_token_authenticatable_strategy'
8
+ require 'devise/oauth_token_authenticatable/models/oauth_token_authenticatable'
9
+ require 'devise/oauth_token_authenticatable/version'
10
+
11
+ module Devise
12
+ module OauthTokenAuthenticatable
13
+ CLIENT_ENV_REF = 'oauth2.client'
14
+ end
15
+
16
+ # Relative URL path to validate a given Access Token. E.g. /oauth/verify_credentials
17
+ mattr_accessor :oauth_token_validation_url
18
+ @@oauth_token_validation_url = nil
19
+
20
+ # Client ID for connecting to the authentication server.
21
+ mattr_accessor :oauth_client_id
22
+ @@oauth_client_id = nil
23
+
24
+ # Client Secret for connecting to the authentication server.
25
+ mattr_accessor :oauth_client_secret
26
+ @@oauth_client_secret = nil
27
+
28
+ # Client options hash, passed directly to ::OAuth2::Client.new
29
+ # From the OAuth2 documentation...
30
+ # @param [Hash] opts the options to create the client with
31
+ # @option opts [String] :site the OAuth2 provider site host
32
+ # @option opts [String] :authorize_url ('/oauth/authorize') absolute or relative URL path to the Authorization endpoint
33
+ # @option opts [String] :token_url ('/oauth/token') absolute or relative URL path to the Token endpoint
34
+ # @option opts [Symbol] :token_method (:post) HTTP method to use to request token (:get or :post)
35
+ # @option opts [Hash] :connection_opts ({}) Hash of connection options to pass to initialize Faraday with
36
+ # @option opts [FixNum] :max_redirects (5) maximum number of redirects to follow
37
+ # @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error
38
+ # on responses with 400+ status codes
39
+ mattr_accessor :oauth_client_options
40
+ @@oauth_client_options = {}
41
+
42
+ end
43
+
44
+ Devise.add_module(:oauth_token_authenticatable,
45
+ :strategy => true,
46
+ :model => 'devise/oauth_token_authenticatable/models/oauth_token_authenticatable'
47
+ )
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise_oauth_token_authenticatable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Marc Leglise
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-07-09 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rails
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 3
32
+ - 1
33
+ - 0
34
+ version: 3.1.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: devise
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 11
46
+ segments:
47
+ - 2
48
+ - 1
49
+ - 0
50
+ version: 2.1.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: oauth2
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 5
62
+ segments:
63
+ - 0
64
+ - 6
65
+ - 1
66
+ version: 0.6.1
67
+ type: :runtime
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: rack-oauth2
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 39
78
+ segments:
79
+ - 0
80
+ - 14
81
+ - 0
82
+ version: 0.14.0
83
+ type: :runtime
84
+ version_requirements: *id004
85
+ description: "\n\
86
+ There are plenty of gems out there that deal with being an OAuth2 \"consumer\",\n\
87
+ where you redirect users to an OAuth2 \"provider\", allowing you to hand off\n\
88
+ authentication to a separate service. There are also plenty of gems that set\n\
89
+ you up as your own OAuth2 provider. ***BUT***, what happens when you want to\n\
90
+ separate your \"authentication\" server from your \"resource\" server?\n\n\
91
+ This gem is meant to be used on an API \"resource\" server, where you want to\n\
92
+ accept OAuth Access Tokens from a client, and validate them against a separate\n\
93
+ \"authentication\" server. This communication is outside the scope of the\n\
94
+ official OAuth 2 spec, but there is a need for it anyway.\n "
95
+ email:
96
+ - mleglise@gmail.com
97
+ executables: []
98
+
99
+ extensions: []
100
+
101
+ extra_rdoc_files: []
102
+
103
+ files:
104
+ - .gitignore
105
+ - Gemfile
106
+ - LICENSE
107
+ - README.md
108
+ - Rakefile
109
+ - devise_oauth_token_authenticatable.gemspec
110
+ - lib/devise/oauth_token_authenticatable/models/oauth_token_authenticatable.rb
111
+ - lib/devise/oauth_token_authenticatable/strategies/oauth_token_authenticatable_strategy.rb
112
+ - lib/devise/oauth_token_authenticatable/version.rb
113
+ - lib/devise_oauth_token_authenticatable.rb
114
+ has_rdoc: true
115
+ homepage: https://github.com/mleglise/devise_oauth_token_authenticatable
116
+ licenses: []
117
+
118
+ post_install_message:
119
+ rdoc_options: []
120
+
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ hash: 3
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ hash: 3
138
+ segments:
139
+ - 0
140
+ version: "0"
141
+ requirements: []
142
+
143
+ rubyforge_project:
144
+ rubygems_version: 1.6.2
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: Allows Rails 3 + Devise to authenticate users via an OAuth Access Token from a 3rd party provider.
148
+ test_files: []
149
+