omniauth-oauthio 0.1.0
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 +7 -0
- data/.gitignore +10 -0
- data/Gemfile +7 -0
- data/LICENSE +20 -0
- data/README.md +118 -0
- data/Rakefile +8 -0
- data/example/Gemfile +4 -0
- data/example/Gemfile.lock +44 -0
- data/example/config.ru +110 -0
- data/lib/oauthio/access_token.rb +47 -0
- data/lib/oauthio/client.rb +158 -0
- data/lib/oauthio/providers/oauthio.rb +84 -0
- data/lib/oauthio/strategy/auth_code.rb +36 -0
- data/lib/omniauth/oauthio/version.rb +5 -0
- data/lib/omniauth/oauthio.rb +9 -0
- data/lib/omniauth/strategies/oauthio.rb +158 -0
- data/lib/omniauth-oauthio.rb +1 -0
- data/omniauth-oauthio.gemspec +24 -0
- data/test/helper.rb +56 -0
- data/test/support/shared_examples.rb +85 -0
- data/test/test.rb +541 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1dca97fafd16386f51832f166b84c5cf621d0bc3
|
4
|
+
data.tar.gz: 6a4e6e04a937c70cfcd1d80ede2ee635d6bc222d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 149abd7e8dbdb2a5cee853f596dc982b4ad26ced924d7b2a1852d8022bdee921aae34e6d0f237691b539d42b6b761cebfc64b712bd1abc22c909a77ad42fc9ea
|
7
|
+
data.tar.gz: 6db1a1e393399688ec32e1036394658d7e2554ae81805cbad6de147fa1187dd590c63676f7a35a15e9f8f09de2ad2aefa36467678022d74633499f8cb036d67a
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Jonathan Rowlands
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
omniauth-oauthio
|
2
|
+
=================
|
3
|
+
|
4
|
+
OAuth.io Strategy for OmniAuth
|
5
|
+
|
6
|
+
# TODO
|
7
|
+
|
8
|
+
Please note this strategy is still pretty experimental and is not complete
|
9
|
+
|
10
|
+
1. I am using this mainly with a pure javascript/angularjs single page application that connects to a rails api, but
|
11
|
+
there is no reason why this potentially work with a normal rails application that takes does not require javascript.
|
12
|
+
I believe there is some missing functionality there and requires further testing.
|
13
|
+
|
14
|
+
## Installing
|
15
|
+
|
16
|
+
Add to your `Gemfile`:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'omniauth-oauthio', path: 'https://github.com/jgrowl/omniauth-oauthio.git'
|
20
|
+
```
|
21
|
+
|
22
|
+
Then `bundle install`.
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
`OmniAuth::Strategies::Oauthio` is simply a Rack middleware. Read the OmniAuth docs for detailed instructions: https://github.com/intridea/omniauth.
|
27
|
+
|
28
|
+
Here's a quick example, adding the middleware to a Rails app in `config/initializers/omniauth.rb`:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
32
|
+
configure do |config|
|
33
|
+
config.path_prefix = '/users/auth'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
The following steps on the front-end need to occur:
|
39
|
+
|
40
|
+
1. Initialize the OAuth public key.
|
41
|
+
|
42
|
+
2. Perform get request to initiate the request_phase, using the .json option for SPA (This is to get a state string from the server).
|
43
|
+
|
44
|
+
3. Use OAuth.io's javascript api to initiate a popup (Passing along the state from step 2).
|
45
|
+
|
46
|
+
4. Perform get request to initiate callback_phase (Passing along the state and code received in step 3).
|
47
|
+
|
48
|
+
For example: (NOTE: I need to update this. I am currently using dart in my test app)
|
49
|
+
|
50
|
+
```coffeescript
|
51
|
+
OAuth.initialize('YOUR_PUBLIC_KEY')
|
52
|
+
|
53
|
+
$.get "http://localhost:3000/users/auth/oauthio.json", (data) ->
|
54
|
+
@options = data
|
55
|
+
|
56
|
+
OAuth.popup provider, @options, (err, res) ->
|
57
|
+
if (err)
|
58
|
+
console.log err
|
59
|
+
else
|
60
|
+
$.get "http://localhost:3000/users/auth/oauthio/twitter/callback.json?state=@options.state&code=@options.code", (data) ->
|
61
|
+
console.log(data)
|
62
|
+
# Perform additional login steps
|
63
|
+
```
|
64
|
+
|
65
|
+
## Configuring
|
66
|
+
|
67
|
+
### OAuth.io
|
68
|
+
|
69
|
+
Be sure to enable the Server-side (code) option on any providers you want to use with this strategy.
|
70
|
+
|
71
|
+
### Custom Callback URL/Path
|
72
|
+
|
73
|
+
You can set a custom `callback_url` or `callback_path` option to override the default value. See [OmniAuth::Strategy#callback_url](https://github.com/intridea/omniauth/blob/master/lib/omniauth/strategy.rb#L411) for more details on the default.
|
74
|
+
|
75
|
+
### Devise
|
76
|
+
To use with devise, in `config/initializers/devise.rb`
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
config.omniauth :oauthio, ENV['OAUTHIO_PUBLIC_KEY'], ENV['OAUTHIO_SECRET_KEY']
|
80
|
+
```
|
81
|
+
|
82
|
+
### Omniauth
|
83
|
+
|
84
|
+
Add an oauthio callback in `app/controllers/users/omniauth_callbacks_controller.rb`
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
|
88
|
+
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
89
|
+
def oauthio
|
90
|
+
|
91
|
+
# TODO: Do your login logic here! ie. look up the user by the uid or create one if it does not already exist!
|
92
|
+
|
93
|
+
respond_to do |format|
|
94
|
+
format.json { render json: auth_hash}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def auth_hash
|
99
|
+
request.env['omniauth.auth']
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
Create the method used in your callback in your `user.rb`
|
106
|
+
|
107
|
+
# Understanding server side flow
|
108
|
+
|
109
|
+
oauth.io describes how everything works in their [security](https://oauth.io/docs/security) section.
|
110
|
+
|
111
|
+

|
112
|
+
|
113
|
+
|
114
|
+
## Credit
|
115
|
+
|
116
|
+
https://oauth.io/
|
117
|
+
|
118
|
+
https://github.com/mkdynamic/omniauth-facebook
|
data/Rakefile
ADDED
data/example/Gemfile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
omniauth-facebook (1.6.0.rc1)
|
5
|
+
omniauth-oauth2 (~> 1.1)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
faraday (0.8.8)
|
11
|
+
multipart-post (~> 1.2.0)
|
12
|
+
hashie (2.0.5)
|
13
|
+
httpauth (0.2.0)
|
14
|
+
jwt (0.1.8)
|
15
|
+
multi_json (>= 1.5)
|
16
|
+
multi_json (1.8.2)
|
17
|
+
multipart-post (1.2.0)
|
18
|
+
oauth2 (0.8.1)
|
19
|
+
faraday (~> 0.8)
|
20
|
+
httpauth (~> 0.1)
|
21
|
+
jwt (~> 0.1.4)
|
22
|
+
multi_json (~> 1.0)
|
23
|
+
rack (~> 1.2)
|
24
|
+
omniauth (1.1.4)
|
25
|
+
hashie (>= 1.2, < 3)
|
26
|
+
rack
|
27
|
+
omniauth-oauth2 (1.1.1)
|
28
|
+
oauth2 (~> 0.8.0)
|
29
|
+
omniauth (~> 1.0)
|
30
|
+
rack (1.5.2)
|
31
|
+
rack-protection (1.5.1)
|
32
|
+
rack
|
33
|
+
sinatra (1.4.4)
|
34
|
+
rack (~> 1.4)
|
35
|
+
rack-protection (~> 1.4)
|
36
|
+
tilt (~> 1.3, >= 1.3.4)
|
37
|
+
tilt (1.4.1)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
omniauth-facebook!
|
44
|
+
sinatra
|
data/example/config.ru
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'omniauth-oauthio'
|
4
|
+
|
5
|
+
#SCOPE = 'email,read_stream'
|
6
|
+
#
|
7
|
+
#class App < Sinatra::Base
|
8
|
+
# # turn off sinatra default X-Frame-Options for FB canvas
|
9
|
+
# set :protection, :except => :frame_options
|
10
|
+
#
|
11
|
+
# # server-side flow
|
12
|
+
# get '/' do
|
13
|
+
# # NOTE: you would just hit this endpoint directly from the browser
|
14
|
+
# # in a real app. the redirect is just here to setup the root
|
15
|
+
# # path in this example sinatra app.
|
16
|
+
# redirect '/auth/facebook'
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # client-side flow
|
20
|
+
# get '/client-side' do
|
21
|
+
# content_type 'text/html'
|
22
|
+
# # NOTE: when you enable cookie below in the FB.init call
|
23
|
+
# # the GET request in the FB.login callback will send
|
24
|
+
# # a signed request in a cookie back the OmniAuth callback
|
25
|
+
# # which will parse out the authorization code and obtain
|
26
|
+
# # the access_token. This will be the exact same access_token
|
27
|
+
# # returned to the client in response.authResponse.accessToken.
|
28
|
+
# <<-END
|
29
|
+
# <html>
|
30
|
+
# <head>
|
31
|
+
# <title>Client-side Flow Example</title>
|
32
|
+
# <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js" type="text/javascript"></script>
|
33
|
+
# </head>
|
34
|
+
# <body>
|
35
|
+
# <div id="fb-root"></div>
|
36
|
+
#
|
37
|
+
# <script type="text/javascript">
|
38
|
+
# window.fbAsyncInit = function() {
|
39
|
+
# FB.init({
|
40
|
+
# appId : '#{ENV['APP_ID']}',
|
41
|
+
# status : true, // check login status
|
42
|
+
# cookie : true, // enable cookies to allow the server to access the session
|
43
|
+
# xfbml : true // parse XFBML
|
44
|
+
# });
|
45
|
+
# };
|
46
|
+
#
|
47
|
+
# (function(d) {
|
48
|
+
# var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
|
49
|
+
# js = d.createElement('script'); js.id = id; js.async = true;
|
50
|
+
# js.src = "//connect.facebook.net/en_US/all.js";
|
51
|
+
# d.getElementsByTagName('head')[0].appendChild(js);
|
52
|
+
# }(document));
|
53
|
+
#
|
54
|
+
# $(function() {
|
55
|
+
# $('a').click(function(e) {
|
56
|
+
# e.preventDefault();
|
57
|
+
#
|
58
|
+
# FB.login(function(response) {
|
59
|
+
# if (response.authResponse) {
|
60
|
+
# $('#connect').html('Connected! Hitting OmniAuth callback (GET /auth/facebook/callback)...');
|
61
|
+
#
|
62
|
+
# // since we have cookies enabled, this request will allow omniauth to parse
|
63
|
+
# // out the auth code from the signed request in the fbsr_XXX cookie
|
64
|
+
# $.getJSON('/auth/facebook/callback', function(json) {
|
65
|
+
# $('#connect').html('Connected! Callback complete.');
|
66
|
+
# $('#results').html(JSON.stringify(json));
|
67
|
+
# });
|
68
|
+
# }
|
69
|
+
# }, { scope: '#{SCOPE}' });
|
70
|
+
# });
|
71
|
+
# });
|
72
|
+
# </script>
|
73
|
+
#
|
74
|
+
# <p id="connect">
|
75
|
+
# <a href="#">Connect to FB</a>
|
76
|
+
# </p>
|
77
|
+
#
|
78
|
+
# <p id="results" />
|
79
|
+
# </body>
|
80
|
+
# </html>
|
81
|
+
# END
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# # auth via FB canvas and signed request param
|
85
|
+
# post '/canvas/' do
|
86
|
+
# # we just redirect to /auth/facebook here which will parse the
|
87
|
+
# # signed_request FB sends us, asking for auth if the user has
|
88
|
+
# # not already granted access, or simply moving straight to the
|
89
|
+
# # callback where they have already granted access.
|
90
|
+
# redirect "/auth/facebook?signed_request=#{request.params['signed_request']}"
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# get '/auth/:provider/callback' do
|
94
|
+
# content_type 'application/json'
|
95
|
+
# MultiJson.encode(request.env)
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# get '/auth/failure' do
|
99
|
+
# content_type 'application/json'
|
100
|
+
# MultiJson.encode(request.env)
|
101
|
+
# end
|
102
|
+
#end
|
103
|
+
#
|
104
|
+
#use Rack::Session::Cookie
|
105
|
+
#
|
106
|
+
#use OmniAuth::Builder do
|
107
|
+
# provider :facebook, ENV['APP_ID'], ENV['APP_SECRET'], :scope => SCOPE
|
108
|
+
#end
|
109
|
+
#
|
110
|
+
#run App.new
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Oauthio
|
2
|
+
class AccessToken < OAuth2::AccessToken
|
3
|
+
attr_reader :provider, :oauth_token, :oauth_token_secret
|
4
|
+
|
5
|
+
class << self
|
6
|
+
# Initializes an AccessToken from a Hash
|
7
|
+
#
|
8
|
+
# @param [Client] the OAuth2::Client instance
|
9
|
+
# @param [Hash] a hash of AccessToken property values
|
10
|
+
# @return [AccessToken] the initalized AccessToken
|
11
|
+
def from_hash(client, hash)
|
12
|
+
# new(client, hash.delete('access_token') || hash.delete(:access_token), hash)
|
13
|
+
new(client,
|
14
|
+
hash.delete('provider') || hash.delete(:provider),
|
15
|
+
hash.delete('access_token') || hash.delete(:access_token),
|
16
|
+
hash.delete('oauth_token') || hash.delete(:oauth_token),
|
17
|
+
hash.delete('oauth_token_secret') || hash.delete(:oauth_token_secret),
|
18
|
+
hash)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(client, provider, token, oauth_token, oauth_token_secret, opts = {})
|
23
|
+
super client, token, opts
|
24
|
+
@provider = provider
|
25
|
+
@oauth_token = oauth_token.to_s
|
26
|
+
@oauth_token_secret = oauth_token_secret.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def me()
|
30
|
+
k = @client.id
|
31
|
+
# oauthv = 1 # TODO: Update this
|
32
|
+
|
33
|
+
if !@token.empty?
|
34
|
+
# oauthv=#{oauthv}
|
35
|
+
oauthio_header = "k=#{k}&access_token=#{@token}"
|
36
|
+
elsif !@oauth_token.empty? && !@oauth_token_secret.empty?
|
37
|
+
# oauthv=#{oauthv}
|
38
|
+
oauthio_header = "k=#{k}&oauth_token=#{@oauth_token}&oauth_token_secret=#{@oauth_token_secret}"
|
39
|
+
else
|
40
|
+
# TODO: Throw error if no tokens found
|
41
|
+
end
|
42
|
+
opts = {headers: {oauthio: oauthio_header}}
|
43
|
+
me_url = client.me_url(provider)
|
44
|
+
request(:get, me_url, opts)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Oauthio
|
2
|
+
class Client < ::OAuth2::Client
|
3
|
+
|
4
|
+
# Instantiate a new OAuth 2.0 client using the
|
5
|
+
# Client ID and Client Secret registered to your
|
6
|
+
# application.
|
7
|
+
#
|
8
|
+
# @param [String] client_id the client_id value
|
9
|
+
# @param [String] client_secret the client_secret value
|
10
|
+
# @param [Hash] opts the options to create the client with
|
11
|
+
# @option opts [String] :site the OAuth2 provider site host
|
12
|
+
# @option opts [String] :authorize_url ('/oauth/authorize') absolute or relative URL path to the Authorization endpoint
|
13
|
+
# @option opts [String] :token_url ('/oauth/token') absolute or relative URL path to the Token endpoint
|
14
|
+
# @option opts [Symbol] :token_method (:post) HTTP method to use to request token (:get or :post)
|
15
|
+
# @option opts [Hash] :connection_opts ({}) Hash of connection options to pass to initialize Faraday with
|
16
|
+
# @option opts [FixNum] :max_redirects (5) maximum number of redirects to follow
|
17
|
+
# @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error
|
18
|
+
# on responses with 400+ status codes
|
19
|
+
# @yield [builder] The Faraday connection builder
|
20
|
+
def initialize(client_id, client_secret, opts = {}, &block)
|
21
|
+
_opts = opts.dup
|
22
|
+
@id = client_id
|
23
|
+
@secret = client_secret
|
24
|
+
@site = _opts.delete(:site)
|
25
|
+
@state = _opts.delete(:state)
|
26
|
+
ssl = _opts.delete(:ssl)
|
27
|
+
@options = {:authorize_url => '/auth',
|
28
|
+
:token_url => '/auth/access_token',
|
29
|
+
:me_url => '/auth/:provider/me',
|
30
|
+
:token_method => :post,
|
31
|
+
:connection_opts => {},
|
32
|
+
:connection_build => block,
|
33
|
+
:max_redirects => 5,
|
34
|
+
:raise_errors => true}.merge(_opts)
|
35
|
+
@options[:connection_opts][:ssl] = ssl if ssl
|
36
|
+
end
|
37
|
+
|
38
|
+
def me_url(provider, params = nil)
|
39
|
+
connection.build_url(options[:me_url], params).to_s.sub(/:provider/, provider)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Makes a request relative to the specified site root.
|
43
|
+
#
|
44
|
+
# @param [Symbol] verb one of :get, :post, :put, :delete
|
45
|
+
# @param [String] url URL path of request
|
46
|
+
# @param [Hash] opts the options to make the request with
|
47
|
+
# @option opts [Hash] :params additional query parameters for the URL of the request
|
48
|
+
# @option opts [Hash, String] :body the body of the request
|
49
|
+
# @option opts [Hash] :headers http request headers
|
50
|
+
# @option opts [Boolean] :raise_errors whether or not to raise an OAuth2::Error on 400+ status
|
51
|
+
# code response for this request. Will default to client option
|
52
|
+
# @option opts [Symbol] :parse @see Response::initialize
|
53
|
+
# @yield [req] The Faraday request
|
54
|
+
def request(verb, url, opts = {}) # rubocop:disable CyclomaticComplexity, MethodLength
|
55
|
+
url = connection.build_url(url, opts[:params]).to_s
|
56
|
+
|
57
|
+
response = connection.run_request(verb, url, opts[:body], opts[:headers]) do |req|
|
58
|
+
yield(req) if block_given?
|
59
|
+
end
|
60
|
+
|
61
|
+
# Only really care about the status and the actual return body.
|
62
|
+
# Oauth2 strategy wraps the response in a Response object that handles parsing and whatnot. That is great when
|
63
|
+
# support for multiple options is needed, however we only have to conform to a single interface. We will take
|
64
|
+
# the easy route of always expecting a json response.
|
65
|
+
status = response.status
|
66
|
+
headers = response.headers
|
67
|
+
response = JSON.parse(response.body)
|
68
|
+
response['status'] = status
|
69
|
+
response['headers'] = headers
|
70
|
+
response = Hashie::Mash.new response
|
71
|
+
|
72
|
+
case response.status
|
73
|
+
when 301, 302, 303, 307
|
74
|
+
opts[:redirect_count] ||= 0
|
75
|
+
opts[:redirect_count] += 1
|
76
|
+
return response if opts[:redirect_count] > options[:max_redirects]
|
77
|
+
if response.status == 303
|
78
|
+
verb = :get
|
79
|
+
opts.delete(:body)
|
80
|
+
end
|
81
|
+
request(verb, response.headers['location'], opts)
|
82
|
+
when 200..299, 300..399
|
83
|
+
# on non-redirecting 3xx statuses, just return the response
|
84
|
+
response
|
85
|
+
when 400..599
|
86
|
+
error = OAuth2::Error.new(response)
|
87
|
+
fail(error) if opts.fetch(:raise_errors, options[:raise_errors])
|
88
|
+
response.error = error
|
89
|
+
response
|
90
|
+
else
|
91
|
+
error = OAuth2::Error.new(response)
|
92
|
+
fail(error, "Unhandled status code value of #{response.status}")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Initializes an AccessToken by making a request to the token endpoint
|
97
|
+
#
|
98
|
+
# @param [Hash] params a Hash of params for the token endpoint
|
99
|
+
# @param [Hash] access token options, to pass to the AccessToken object
|
100
|
+
# @param [Class] class of access token for easier subclassing OAuth2::AccessToken
|
101
|
+
# @return [AccessToken] the initalized AccessToken
|
102
|
+
def get_token(params, access_token_opts = {}, access_token_class = AccessToken)
|
103
|
+
opts = {:raise_errors => options[:raise_errors], :parse => params.delete(:parse)}
|
104
|
+
if options[:token_method] == :post
|
105
|
+
headers = params.delete(:headers)
|
106
|
+
opts[:body] = params
|
107
|
+
opts[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
108
|
+
opts[:headers].merge!(headers) if headers
|
109
|
+
else
|
110
|
+
opts[:params] = params
|
111
|
+
end
|
112
|
+
response = request(options[:token_method], token_url, opts)
|
113
|
+
|
114
|
+
# Verify state in the response matches the one in the session
|
115
|
+
if response.state != @state
|
116
|
+
raise ::OmniAuth::Strategies::OAuth2::CallbackError.new(nil, :csrf_detected);
|
117
|
+
end
|
118
|
+
|
119
|
+
# error = Error.new(response)
|
120
|
+
# fail(error) if options[:raise_errors] && !(response.parsed.is_a?(Hash) && response.parsed['access_token'])
|
121
|
+
|
122
|
+
provider_client = ::Oauthio::Client.new(@id, @secret, { :site => @site })
|
123
|
+
access_token_class.from_hash(provider_client, response.merge(access_token_opts))
|
124
|
+
end
|
125
|
+
|
126
|
+
# The Authorization Code strategy
|
127
|
+
#
|
128
|
+
# @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1
|
129
|
+
def auth_code
|
130
|
+
@auth_code ||= Oauthio::Strategy::AuthCode.new(self)
|
131
|
+
end
|
132
|
+
|
133
|
+
# The Implicit strategy
|
134
|
+
#
|
135
|
+
# @see http://tools.ietf.org/html/draft-ietf-oauth-v2-26#section-4.2
|
136
|
+
def implicit
|
137
|
+
@implicit ||= OAuth2::Strategy::Implicit.new(self)
|
138
|
+
end
|
139
|
+
|
140
|
+
# The Resource Owner Password Credentials strategy
|
141
|
+
#
|
142
|
+
# @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.3
|
143
|
+
def password
|
144
|
+
@password ||= OAuth2::Strategy::Password.new(self)
|
145
|
+
end
|
146
|
+
|
147
|
+
# The Client Credentials strategy
|
148
|
+
#
|
149
|
+
# @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.4
|
150
|
+
def client_credentials
|
151
|
+
@client_credentials ||= OAuth2::Strategy::ClientCredentials.new(self)
|
152
|
+
end
|
153
|
+
|
154
|
+
def assertion
|
155
|
+
@assertion ||= OAuth2::Strategy::Assertion.new(self)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Oauthio
|
2
|
+
module Providers
|
3
|
+
class Oauthio
|
4
|
+
def initialize(access_token, secret, options)
|
5
|
+
@access_token = access_token
|
6
|
+
@secret = secret
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def uid
|
11
|
+
# This might not be uniform across all providers. Need to talk to oauthd guys to see if we can get the id
|
12
|
+
# in the list of things parsed out of the raw data.
|
13
|
+
raw_info['id']
|
14
|
+
end
|
15
|
+
|
16
|
+
def skip_info?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def info
|
21
|
+
prune!({
|
22
|
+
'name' => _raw_info['name'],
|
23
|
+
'alias' => _raw_info['alias'],
|
24
|
+
'bio' => _raw_info['bio'],
|
25
|
+
'avatar' => _raw_info['avatar'],
|
26
|
+
'firstname' => _raw_info['firstname'],
|
27
|
+
'lastname' => _raw_info['lastname'],
|
28
|
+
'gender' => _raw_info['gender'],
|
29
|
+
'location' => _raw_info['location'],
|
30
|
+
'local' => _raw_info['local'],
|
31
|
+
'company' => _raw_info['company'],
|
32
|
+
'occupation' => _raw_info['occupation'],
|
33
|
+
'language' => _raw_info['language'],
|
34
|
+
'birthdate' => _raw_info['birthdate'],
|
35
|
+
})
|
36
|
+
end
|
37
|
+
|
38
|
+
def extra
|
39
|
+
hash = {}
|
40
|
+
hash['raw_info'] = raw_info unless skip_info?
|
41
|
+
prune! hash
|
42
|
+
end
|
43
|
+
|
44
|
+
def _raw_info
|
45
|
+
@_raw_info ||= @access_token.me()['data'] || {}
|
46
|
+
@_raw_info
|
47
|
+
end
|
48
|
+
|
49
|
+
def raw_info
|
50
|
+
@raw_info ||= _raw_info['raw'] || {}
|
51
|
+
end
|
52
|
+
|
53
|
+
def info_options
|
54
|
+
# params = {:appsecret_proof => appsecret_proof}
|
55
|
+
# params.merge!({:fields => @options[:info_fields]}) if @options[:info_fields]
|
56
|
+
# params.merge!({:locale => @options[:locale]}) if @options[:locale]
|
57
|
+
#
|
58
|
+
# {:params => params}
|
59
|
+
end
|
60
|
+
|
61
|
+
def appsecret_proof
|
62
|
+
# @appsecret_proof ||= OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, @secret, @access_token.token)
|
63
|
+
end
|
64
|
+
|
65
|
+
def credentials
|
66
|
+
hash = {}
|
67
|
+
hash.merge!('token' => @access_token.token) if !@access_token.token.empty?
|
68
|
+
hash.merge!('oauth_token' => @access_token.oauth_token,
|
69
|
+
'oauth_token_secret' => @access_token.oauth_token_secret) if !@access_token.oauth_token.empty? && !@access_token.oauth_token_secret.empty?
|
70
|
+
hash.merge!('refresh_token' => @access_token.refresh_token) if @access_token.expires? && @access_token.refresh_token
|
71
|
+
hash.merge!('expires_at' => @access_token.expires_at) if @access_token.expires?
|
72
|
+
hash.merge!('expires' => @access_token.expires?)
|
73
|
+
hash
|
74
|
+
end
|
75
|
+
|
76
|
+
def prune!(hash)
|
77
|
+
hash.delete_if do |_, v|
|
78
|
+
prune!(v) if v.is_a?(Hash)
|
79
|
+
v.nil? || (v.respond_to?(:empty?) && v.empty?)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Oauthio
|
2
|
+
module Strategy
|
3
|
+
class AuthCode < OAuth2::Strategy::AuthCode
|
4
|
+
def initialize(client)
|
5
|
+
@client = client
|
6
|
+
end
|
7
|
+
|
8
|
+
# The required query parameters for the authorize URL
|
9
|
+
#
|
10
|
+
# @param [Hash] params additional query parameters
|
11
|
+
def authorize_params(params={})
|
12
|
+
params.merge('k' => @client.id)
|
13
|
+
end
|
14
|
+
|
15
|
+
#TODO: Put this in base.rb
|
16
|
+
# The OAuth client_id and client_secret
|
17
|
+
#
|
18
|
+
# @return [Hash]
|
19
|
+
def client_params
|
20
|
+
{'key' => @client.id, 'secret' => @client.secret}
|
21
|
+
end
|
22
|
+
|
23
|
+
# Retrieve an access token given the specified validation code.
|
24
|
+
#
|
25
|
+
# @param [String] code The Authorization Code value
|
26
|
+
# @param [Hash] params additional params
|
27
|
+
# @param [Hash] opts options
|
28
|
+
# @note that you must also provide a :redirect_uri with most OAuth 2.0 providers
|
29
|
+
def get_token(code, params = {}, opts = {})
|
30
|
+
params = {'code' => code}.merge(client_params).merge(params)
|
31
|
+
@client.get_token(params, opts)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|