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.
@@ -0,0 +1,158 @@
1
+ require 'omniauth/strategies/oauth2'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'rack/utils'
5
+ require 'uri'
6
+
7
+ module OmniAuth
8
+ module Strategies
9
+ class Oauthio < OmniAuth::Strategies::OAuth2
10
+ include OmniAuth::Strategy
11
+
12
+ args [:client_id, :client_secret]
13
+
14
+ # Give your strategy a name.
15
+ option :name, "oauthio"
16
+
17
+ # This is where you pass the options you would pass when
18
+ # initializing your consumer from the OAuth gem.
19
+ option :client_options, {
20
+ :site => 'https://oauth.io',
21
+ }
22
+
23
+ option :client_id, nil
24
+ option :client_secret, nil
25
+
26
+ # Returns true if the environment recognizes either the
27
+ # request or callback path.
28
+ def on_auth_path?
29
+ on_request_path? || on_callback_path?
30
+ end
31
+
32
+ def client_with_provider(provider)
33
+ options.client_options.merge!({authorize_url: "#{options.client_options.authorization_url}/#{provider}"})
34
+ client
35
+ end
36
+
37
+ def current_path
38
+ # This might not be completely safe. I want to ensure that the current_path does not have a format at the end
39
+ # so the .json should be removed.
40
+ super.split('.').first
41
+ end
42
+
43
+ def on_request_path?
44
+ if options.request_path.respond_to?(:call)
45
+ options.request_path.call(env)
46
+ else
47
+ on_path?(request_path)
48
+ end
49
+ end
50
+
51
+ def on_path?(path)
52
+ current_path.casecmp(path) == 0
53
+ end
54
+
55
+ def on_callback_path?
56
+ on_path?(callback_path)
57
+ end
58
+
59
+ def sub_provider
60
+ test = request.path.split("#{path_prefix}/#{name}/").last
61
+ slashes = test.split('/')
62
+ if slashes.length > 1
63
+ # return ''
64
+ return slashes.first.split('.').first
65
+ end
66
+
67
+ test.split('.').first
68
+ end
69
+
70
+ def request_path
71
+ options[:request_path].is_a?(String) ? options[:request_path] : "#{path_prefix}/#{name}/#{sub_provider}"
72
+ end
73
+
74
+ def callback_path
75
+ path = options[:callback_path] if options[:callback_path].is_a?(String)
76
+ path ||= current_path if options[:callback_path].respond_to?(:call) && options[:callback_path].call(env)
77
+ path ||= custom_path(:request_path)
78
+ path ||= "#{path_prefix}/#{name}/#{sub_provider}/callback"
79
+ path
80
+ end
81
+
82
+ def path_prefix
83
+ options[:path_prefix] || OmniAuth.config.path_prefix
84
+ end
85
+
86
+ def request_phase
87
+ params = authorize_params
88
+ # We may want to skip redirecting the user if calling from a SPA that does not want to reload the page.
89
+ # The json option will return a json response instead of redirecting.
90
+ if request.path_info.include?('.json')
91
+ json = {state: session['omniauth.state']}.to_json
92
+ return Rack::Response.new(json, 200, 'content-type' => 'application/json').finish
93
+ end
94
+
95
+ # TODO: Check the redirect url.
96
+ provider = params[:provider]
97
+ params = params.except(:provider)
98
+ redirect_url = client_with_provider(provider).auth_code.authorize_url({:redirect_uri => callback_url}.merge(params))
99
+ redirect redirect_url
100
+ end
101
+
102
+ def auth_hash
103
+ provider_info = ::Oauthio::Providers::Oauthio.new(access_token, client.secret, options)
104
+ provider = access_token.provider
105
+ hash = AuthHash.new(:provider => provider, :uid => provider_info.uid)
106
+ hash.info = provider_info.info unless provider_info.skip_info?
107
+ hash.credentials = provider_info.credentials if provider_info.credentials
108
+ hash.extra = provider_info.extra if provider_info.extra
109
+ hash
110
+ end
111
+
112
+ def callback_phase
113
+ #if request.params['error'] || request.params['error_reason']
114
+ # raise CallbackError.new(request.params['error'], request.params['error_description'] || request.params['error_reason'], request.params['error_uri'])
115
+ #end
116
+ if !options.provider_ignores_state && !verified_state?
117
+ raise CallbackError.new(nil, :csrf_detected)
118
+ end
119
+
120
+ self.access_token = build_access_token
121
+ self.access_token = access_token.refresh! if access_token.expired?
122
+
123
+ env['omniauth.auth'] = auth_hash
124
+ # Delete the omniauth.state after we have verified all requests
125
+ session.delete('omniauth.state')
126
+ call_app!
127
+
128
+ #rescue ::Oauthio::Error, CallbackError => e
129
+ rescue CallbackError => e
130
+ fail!(:invalid_credentials, e)
131
+ rescue ::MultiJson::DecodeError => e
132
+ fail!(:invalid_response, e)
133
+ rescue ::Timeout::Error, ::Errno::ETIMEDOUT => e
134
+ fail!(:timeout, e)
135
+ rescue ::SocketError => e
136
+ fail!(:failed_to_connect, e)
137
+ end
138
+
139
+ protected
140
+ # Client should only be access via client_with_provider
141
+ def client
142
+ state = session['omniauth.state']
143
+ options.client_options[:state] = state
144
+ ::Oauthio::Client.new(options.client_id, options.client_secret, deep_symbolize(options.client_options))
145
+ end
146
+
147
+ def verified_state?
148
+ state = request.params['state']
149
+ return false if state.to_s.empty?
150
+ state == session['omniauth.state']
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+
157
+
158
+
@@ -0,0 +1 @@
1
+ require 'omniauth/oauthio'
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'omniauth/oauthio/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'omniauth-oauthio'
7
+ s.version = OmniAuth::Oauthio::VERSION
8
+ s.authors = ['Jonathan Rowlands']
9
+ s.email = ['jonrowlands83@gmail.com']
10
+ s.summary = 'OAuth.io Strategy for OmniAuth'
11
+ s.homepage = 'https://github.com/jgrowl/omniauth-oauthio'
12
+ s.license = 'MIT'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
17
+ s.require_paths = ['lib']
18
+
19
+ s.add_runtime_dependency 'omniauth-oauth2', '~> 1.1'
20
+
21
+ s.add_development_dependency 'minitest'
22
+ s.add_development_dependency 'mocha'
23
+ s.add_development_dependency 'rake'
24
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,56 @@
1
+ #require 'bundler/setup'
2
+ #require 'minitest/autorun'
3
+ #require 'mocha/setup'
4
+ #require 'omniauth/strategies/facebook'
5
+ #
6
+ #OmniAuth.config.test_mode = true
7
+ #
8
+ #module BlockTestHelper
9
+ # def test(name, &blk)
10
+ # method_name = "test_#{name.gsub(/\s+/, '_')}"
11
+ # raise "Method already defined: #{method_name}" if instance_methods.include?(method_name.to_sym)
12
+ # define_method method_name, &blk
13
+ # end
14
+ #end
15
+ #
16
+ #module CustomAssertions
17
+ # def assert_has_key(key, hash, msg = nil)
18
+ # msg = message(msg) { "Expected #{hash.inspect} to have key #{key.inspect}" }
19
+ # assert hash.has_key?(key), msg
20
+ # end
21
+ #
22
+ # def refute_has_key(key, hash, msg = nil)
23
+ # msg = message(msg) { "Expected #{hash.inspect} not to have key #{key.inspect}" }
24
+ # refute hash.has_key?(key), msg
25
+ # end
26
+ #end
27
+ #
28
+ #class TestCase < Minitest::Test
29
+ # extend BlockTestHelper
30
+ # include CustomAssertions
31
+ #end
32
+ #
33
+ #class StrategyTestCase < TestCase
34
+ # def setup
35
+ # @request = stub('Request')
36
+ # @request.stubs(:params).returns({})
37
+ # @request.stubs(:cookies).returns({})
38
+ # @request.stubs(:env).returns({})
39
+ # @request.stubs(:scheme).returns({})
40
+ # @request.stubs(:ssl?).returns(false)
41
+ #
42
+ # @client_id = '123'
43
+ # @client_secret = '53cr3tz'
44
+ # end
45
+ #
46
+ # def strategy
47
+ # @strategy ||= begin
48
+ # args = [@client_id, @client_secret, @options].compact
49
+ # OmniAuth::Strategies::Facebook.new(nil, *args).tap do |strategy|
50
+ # strategy.stubs(:request).returns(@request)
51
+ # end
52
+ # end
53
+ # end
54
+ #end
55
+ #
56
+ #Dir[File.expand_path('../support/**/*', __FILE__)].each &method(:require)
@@ -0,0 +1,85 @@
1
+ ## NOTE it would be useful if this lived in omniauth-Oauthio eventually
2
+ #module OauthioStrategyTests
3
+ # def self.included(base)
4
+ # base.class_eval do
5
+ # include ClientTests
6
+ # include AuthorizeParamsTests
7
+ # include CSRFAuthorizeParamsTests
8
+ # include TokenParamsTests
9
+ # end
10
+ # end
11
+ #
12
+ # module ClientTests
13
+ # extend BlockTestHelper
14
+ #
15
+ # test 'should be initialized with symbolized client_options' do
16
+ # @options = { :client_options => { 'authorize_url' => 'https://example.com' } }
17
+ # assert_equal 'https://example.com', strategy.client.options[:authorize_url]
18
+ # end
19
+ # end
20
+ #
21
+ # module AuthorizeParamsTests
22
+ # extend BlockTestHelper
23
+ #
24
+ # test 'should include any authorize params passed in the :authorize_params option' do
25
+ # @options = { :authorize_params => { :foo => 'bar', :baz => 'zip' } }
26
+ # assert_equal 'bar', strategy.authorize_params['foo']
27
+ # assert_equal 'zip', strategy.authorize_params['baz']
28
+ # end
29
+ #
30
+ # test 'should include top-level options that are marked as :authorize_options' do
31
+ # @options = { :authorize_options => [:scope, :foo], :scope => 'bar', :foo => 'baz' }
32
+ # assert_equal 'bar', strategy.authorize_params['scope']
33
+ # assert_equal 'baz', strategy.authorize_params['foo']
34
+ # end
35
+ #
36
+ # test 'should exclude top-level options that are not passed' do
37
+ # @options = { :authorize_options => [:bar] }
38
+ # refute_has_key :bar, strategy.authorize_params
39
+ # refute_has_key 'bar', strategy.authorize_params
40
+ # end
41
+ # end
42
+ #
43
+ # module CSRFAuthorizeParamsTests
44
+ # extend BlockTestHelper
45
+ #
46
+ # test 'should store random state in the session when none is present in authorize or request params' do
47
+ # assert_includes strategy.authorize_params.keys, 'state'
48
+ # refute_empty strategy.authorize_params['state']
49
+ # refute_empty strategy.session['omniauth.state']
50
+ # assert_equal strategy.authorize_params['state'], strategy.session['omniauth.state']
51
+ # end
52
+ #
53
+ # test 'should not store state in the session when present in authorize params vs. a random one' do
54
+ # @options = { :authorize_params => { :state => 'bar' } }
55
+ # refute_empty strategy.authorize_params['state']
56
+ # refute_equal 'bar', strategy.authorize_params[:state]
57
+ # refute_empty strategy.session['omniauth.state']
58
+ # refute_equal 'bar', strategy.session['omniauth.state']
59
+ # end
60
+ #
61
+ # test 'should not store state in the session when present in request params vs. a random one' do
62
+ # @request.stubs(:params).returns({ 'state' => 'foo' })
63
+ # refute_empty strategy.authorize_params['state']
64
+ # refute_equal 'foo', strategy.authorize_params[:state]
65
+ # refute_empty strategy.session['omniauth.state']
66
+ # refute_equal 'foo', strategy.session['omniauth.state']
67
+ # end
68
+ # end
69
+ #
70
+ # module TokenParamsTests
71
+ # extend BlockTestHelper
72
+ #
73
+ # test 'should include any authorize params passed in the :token_params option' do
74
+ # @options = { :token_params => { :foo => 'bar', :baz => 'zip' } }
75
+ # assert_equal 'bar', strategy.token_params['foo']
76
+ # assert_equal 'zip', strategy.token_params['baz']
77
+ # end
78
+ #
79
+ # test 'should include top-level options that are marked as :token_options' do
80
+ # @options = { :token_options => [:scope, :foo], :scope => 'bar', :foo => 'baz' }
81
+ # assert_equal 'bar', strategy.token_params['scope']
82
+ # assert_equal 'baz', strategy.token_params['foo']
83
+ # end
84
+ # end
85
+ #end