rack-oauth 0.1.2
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/README.rdoc +49 -0
- data/Rakefile +68 -0
- data/VERSION +1 -0
- data/examples/rails-example/README +243 -0
- data/examples/rails-example/Rakefile +10 -0
- data/examples/rails-example/app/controllers/application_controller.rb +12 -0
- data/examples/rails-example/app/controllers/welcome_controller.rb +26 -0
- data/examples/rails-example/app/helpers/application_helper.rb +3 -0
- data/examples/rails-example/app/helpers/welcome_helper.rb +2 -0
- data/examples/rails-example/app/views/welcome/index.html.erb +2 -0
- data/examples/rails-example/config/boot.rb +110 -0
- data/examples/rails-example/config/database.yml +22 -0
- data/examples/rails-example/config/environment.rb +14 -0
- data/examples/rails-example/config/environments/development.rb +17 -0
- data/examples/rails-example/config/environments/production.rb +28 -0
- data/examples/rails-example/config/environments/test.rb +32 -0
- data/examples/rails-example/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/rails-example/config/initializers/inflections.rb +10 -0
- data/examples/rails-example/config/initializers/mime_types.rb +5 -0
- data/examples/rails-example/config/initializers/new_rails_defaults.rb +21 -0
- data/examples/rails-example/config/initializers/session_store.rb +15 -0
- data/examples/rails-example/config/locales/en.yml +5 -0
- data/examples/rails-example/config/routes.rb +6 -0
- data/examples/rails-example/db/development.sqlite3 +1 -0
- data/examples/rails-example/db/seeds.rb +7 -0
- data/examples/rails-example/db/test.sqlite3 +1 -0
- data/examples/rails-example/doc/README_FOR_APP +2 -0
- data/examples/rails-example/lib/tasks/rspec.rake +182 -0
- data/examples/rails-example/log/development.log +165 -0
- data/examples/rails-example/log/production.log +0 -0
- data/examples/rails-example/log/server.log +0 -0
- data/examples/rails-example/log/test.log +1591 -0
- data/examples/rails-example/public/404.html +30 -0
- data/examples/rails-example/public/422.html +30 -0
- data/examples/rails-example/public/500.html +30 -0
- data/examples/rails-example/public/favicon.ico +0 -0
- data/examples/rails-example/public/images/rails.png +0 -0
- data/examples/rails-example/public/javascripts/application.js +2 -0
- data/examples/rails-example/public/javascripts/controls.js +963 -0
- data/examples/rails-example/public/javascripts/dragdrop.js +973 -0
- data/examples/rails-example/public/javascripts/effects.js +1128 -0
- data/examples/rails-example/public/javascripts/prototype.js +4320 -0
- data/examples/rails-example/public/robots.txt +5 -0
- data/examples/rails-example/script/about +4 -0
- data/examples/rails-example/script/autospec +6 -0
- data/examples/rails-example/script/console +3 -0
- data/examples/rails-example/script/dbconsole +3 -0
- data/examples/rails-example/script/destroy +3 -0
- data/examples/rails-example/script/generate +3 -0
- data/examples/rails-example/script/performance/benchmarker +3 -0
- data/examples/rails-example/script/performance/profiler +3 -0
- data/examples/rails-example/script/plugin +3 -0
- data/examples/rails-example/script/runner +3 -0
- data/examples/rails-example/script/server +3 -0
- data/examples/rails-example/script/spec +10 -0
- data/examples/rails-example/script/spec_server +9 -0
- data/examples/rails-example/spec/integration/login_spec.rb +27 -0
- data/examples/rails-example/spec/rcov.opts +2 -0
- data/examples/rails-example/spec/spec.opts +4 -0
- data/examples/rails-example/spec/spec_helper.rb +12 -0
- data/examples/rails-example/tmp/webrat-1257205170.html +202 -0
- data/examples/rails-example/tmp/webrat-1257205276.html +31 -0
- data/examples/rails-example/tmp/webrat-1257205315.html +211 -0
- data/examples/rails-example/tmp/webrat-1257205333.html +31 -0
- data/examples/rails-example/tmp/webrat-1257205380.html +211 -0
- data/examples/rails-example/tmp/webrat-1257205757.html +211 -0
- data/examples/rails-example/tmp/webrat-1257210107.html +32 -0
- data/examples/rails-example/tmp/webrat-1257210160.html +32 -0
- data/examples/rails-example/tmp/webrat-1257210488.html +32 -0
- data/examples/rails-example/tmp/webrat-1257210501.html +32 -0
- data/examples/rails-example/tmp/webrat-1257210545.html +32 -0
- data/examples/rails-example/tmp/webrat-1257210564.html +32 -0
- data/examples/rails-example/tmp/webrat-1257210581.html +32 -0
- data/examples/rails-example/tmp/webrat-1257210600.html +32 -0
- data/examples/rails-example/tmp/webrat-1257210608.html +32 -0
- data/examples/sinatra-twitter.rb +47 -0
- data/examples/sinatra-twitter.ru +2 -0
- data/lib/rack/oauth.rb +1 -0
- data/lib/rack-oauth.rb +378 -0
- data/spec/data/authorized_access_token.yml +58 -0
- data/spec/data/authorized_oauth_verifier.yml +1 -0
- data/spec/data/authorized_request_secret.yml +1 -0
- data/spec/data/authorized_request_token.yml +1 -0
- data/spec/data/unauthorized_request_token.yml +56 -0
- data/spec/rack_oauth_middleware_spec.rb +156 -0
- data/spec/sample_sinatra_app_spec.rb +105 -0
- data/spec/spec_helper.rb +24 -0
- metadata +162 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
2
|
+
<head>
|
|
3
|
+
<title>Action Controller: Exception caught</title>
|
|
4
|
+
<style>
|
|
5
|
+
body { background-color: #fff; color: #333; }
|
|
6
|
+
|
|
7
|
+
body, p, ol, ul, td {
|
|
8
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
|
9
|
+
font-size: 13px;
|
|
10
|
+
line-height: 18px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
pre {
|
|
14
|
+
background-color: #eee;
|
|
15
|
+
padding: 10px;
|
|
16
|
+
font-size: 11px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
a { color: #000; }
|
|
20
|
+
a:visited { color: #666; }
|
|
21
|
+
a:hover { color: #fff; background-color:#000; }
|
|
22
|
+
</style>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
|
|
26
|
+
<h1>Routing Error</h1>
|
|
27
|
+
<p><pre>No route matches "/foo/bar" with {:method=>:get}</pre></p>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
</body>
|
|
32
|
+
</html>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
2
|
+
<head>
|
|
3
|
+
<title>Action Controller: Exception caught</title>
|
|
4
|
+
<style>
|
|
5
|
+
body { background-color: #fff; color: #333; }
|
|
6
|
+
|
|
7
|
+
body, p, ol, ul, td {
|
|
8
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
|
9
|
+
font-size: 13px;
|
|
10
|
+
line-height: 18px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
pre {
|
|
14
|
+
background-color: #eee;
|
|
15
|
+
padding: 10px;
|
|
16
|
+
font-size: 11px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
a { color: #000; }
|
|
20
|
+
a:visited { color: #666; }
|
|
21
|
+
a:hover { color: #fff; background-color:#000; }
|
|
22
|
+
</style>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
|
|
26
|
+
<h1>Routing Error</h1>
|
|
27
|
+
<p><pre>No route matches "/foo/bar" with {:method=>:get}</pre></p>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
</body>
|
|
32
|
+
</html>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
2
|
+
<head>
|
|
3
|
+
<title>Action Controller: Exception caught</title>
|
|
4
|
+
<style>
|
|
5
|
+
body { background-color: #fff; color: #333; }
|
|
6
|
+
|
|
7
|
+
body, p, ol, ul, td {
|
|
8
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
|
9
|
+
font-size: 13px;
|
|
10
|
+
line-height: 18px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
pre {
|
|
14
|
+
background-color: #eee;
|
|
15
|
+
padding: 10px;
|
|
16
|
+
font-size: 11px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
a { color: #000; }
|
|
20
|
+
a:visited { color: #666; }
|
|
21
|
+
a:hover { color: #fff; background-color:#000; }
|
|
22
|
+
</style>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
|
|
26
|
+
<h1>Routing Error</h1>
|
|
27
|
+
<p><pre>No route matches "/foo/bar" with {:method=>:get}</pre></p>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
</body>
|
|
32
|
+
</html>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
2
|
+
<head>
|
|
3
|
+
<title>Action Controller: Exception caught</title>
|
|
4
|
+
<style>
|
|
5
|
+
body { background-color: #fff; color: #333; }
|
|
6
|
+
|
|
7
|
+
body, p, ol, ul, td {
|
|
8
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
|
9
|
+
font-size: 13px;
|
|
10
|
+
line-height: 18px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
pre {
|
|
14
|
+
background-color: #eee;
|
|
15
|
+
padding: 10px;
|
|
16
|
+
font-size: 11px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
a { color: #000; }
|
|
20
|
+
a:visited { color: #666; }
|
|
21
|
+
a:hover { color: #fff; background-color:#000; }
|
|
22
|
+
</style>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
|
|
26
|
+
<h1>Routing Error</h1>
|
|
27
|
+
<p><pre>No route matches "/foo/bar" with {:method=>:get}</pre></p>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
</body>
|
|
32
|
+
</html>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
%w( rubygems sinatra haml ).each {|lib| require lib }
|
|
3
|
+
require File.dirname(__FILE__) + '/../lib/rack-oauth'
|
|
4
|
+
|
|
5
|
+
use Rack::Session::Cookie
|
|
6
|
+
|
|
7
|
+
use Rack::OAuth, :site => 'http://twitter.com', :key => '4JjFmhjfZyQ6rdbiql5A',
|
|
8
|
+
:secret => 'rv4ZaCgvxVPVjxHIDbMxTGFbIMxUa4KkIdPqL7HmaQo'
|
|
9
|
+
|
|
10
|
+
helpers do
|
|
11
|
+
|
|
12
|
+
# todo ... make wrapper that handles ENV?
|
|
13
|
+
def oauth
|
|
14
|
+
Rack::OAuth.get(env)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
get '/' do
|
|
20
|
+
haml :index
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
get '/creds' do
|
|
24
|
+
@user = oauth.request(env, '/account/verify_credentials.json') if oauth.verified?(env)
|
|
25
|
+
haml :index
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
get '/oauth_complete' do
|
|
29
|
+
redirect '/'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
get '/logout' do
|
|
33
|
+
session.clear
|
|
34
|
+
redirect '/'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
__END__
|
|
38
|
+
|
|
39
|
+
@@ index
|
|
40
|
+
|
|
41
|
+
%h1 Twitter OAuth Example
|
|
42
|
+
|
|
43
|
+
- if @user
|
|
44
|
+
%p User:
|
|
45
|
+
%pre~ @user.to_yaml
|
|
46
|
+
|
|
47
|
+
%pre~ session.to_yaml
|
data/lib/rack/oauth.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'rack-oauth'
|
data/lib/rack-oauth.rb
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rack'
|
|
3
|
+
require 'oauth'
|
|
4
|
+
|
|
5
|
+
# For some reason, getting the location our of a HeaderHash doesn't always work!
|
|
6
|
+
#
|
|
7
|
+
# sometimes you can see the header key/value in the HeaderHash, but you can't get it out!
|
|
8
|
+
class Rack::Utils::HeaderHash
|
|
9
|
+
def [] key
|
|
10
|
+
if not has_key?(key)
|
|
11
|
+
hash = to_hash
|
|
12
|
+
hash.keys.each do |hash_key|
|
|
13
|
+
if hash_key.downcase == key.downcase
|
|
14
|
+
return hash[hash_key]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module Rack #:nodoc:
|
|
23
|
+
|
|
24
|
+
# Rack Middleware for integrating OAuth into your application
|
|
25
|
+
#
|
|
26
|
+
# Note: this *requires* that a Rack::Session middleware be enabled
|
|
27
|
+
#
|
|
28
|
+
class OAuth
|
|
29
|
+
|
|
30
|
+
# Helper methods intended to be included in your Rails controller or
|
|
31
|
+
# in your Sinatra helpers block
|
|
32
|
+
module Methods
|
|
33
|
+
|
|
34
|
+
# [Internal] this method returns the Rack 'env' for the current request.
|
|
35
|
+
#
|
|
36
|
+
# This looks for #env or #request.env by default. If these don't return
|
|
37
|
+
# something, then we raise an exception and you should override this method
|
|
38
|
+
# so it returns the Rack env that we need.
|
|
39
|
+
def oauth_request_env
|
|
40
|
+
if respond_to?(:env)
|
|
41
|
+
env
|
|
42
|
+
elsif respond_to?(:request) and request.respond_to?(:env)
|
|
43
|
+
request.env
|
|
44
|
+
else
|
|
45
|
+
raise "Couldn't find 'env' ... please override #oauth_request_env"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Returns the instance of Rack::OAuth given a name (defaults to the default Rack::OAuth name)
|
|
50
|
+
def oauth name = nil
|
|
51
|
+
oauth = Rack::OAuth.get(oauth_request_env, nil)
|
|
52
|
+
raise "Couldn't find Rack::OAuth instance with name #{ name }" unless oauth
|
|
53
|
+
oauth
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Makes a request using the stored access token for the current session.
|
|
57
|
+
#
|
|
58
|
+
# Without a user logged in to an OAuth provider in the current session, this won't work.
|
|
59
|
+
#
|
|
60
|
+
# This is *not* the method to use to fire off requests for saved access tokens.
|
|
61
|
+
def oauth_request *args
|
|
62
|
+
oauth.request oauth_request_env, *args
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def oauth_request_with_access_token token, *args
|
|
66
|
+
oauth.request_with_access_token token, *args
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Get the access token object for the currently authorized session
|
|
70
|
+
def oauth_access_token name = nil
|
|
71
|
+
oauth(name).get_access_token(oauth_request_env)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# If Rack::OAuth#get_access_token is nil given the #oauth_request_env available
|
|
75
|
+
# (inotherwords, it's nil in our user's current session), then we didn't
|
|
76
|
+
# log in. If we have an access token for this particular session, then
|
|
77
|
+
# we are logged in.
|
|
78
|
+
def logged_in? name = nil
|
|
79
|
+
!! oauth_access_token(name)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Returns the path to rediret to for logging in via OAuth
|
|
83
|
+
def oauth_login_path name = nil
|
|
84
|
+
oauth(name).login_path
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class << self
|
|
90
|
+
|
|
91
|
+
# The name we use for Rack::OAuth instances when a name is not given.
|
|
92
|
+
#
|
|
93
|
+
# This is 'default' by default
|
|
94
|
+
attr_accessor :default_instance_name
|
|
95
|
+
|
|
96
|
+
# Set this equal to true to enable 'test mode'
|
|
97
|
+
attr_accessor :test_mode_enabled
|
|
98
|
+
def enable_test_mode() self.test_mode_enabled = true end
|
|
99
|
+
def disable_test_mode() self.test_mode_enabled = false end
|
|
100
|
+
def test_mode?() test_mode_enabled == true end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
@default_instance_name = 'default'
|
|
104
|
+
|
|
105
|
+
# Returns all of the Rack::OAuth instances found in this Rack 'env' Hash
|
|
106
|
+
def self.all env
|
|
107
|
+
env['rack.oauth']
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Simple helper to get an instance of Rack::OAuth by name found in this Rack 'env' Hash
|
|
111
|
+
def self.get env, name = nil
|
|
112
|
+
name = Rack::OAuth.default_instance_name if name.nil?
|
|
113
|
+
all(env)[name.to_s]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
DEFAULT_OPTIONS = {
|
|
117
|
+
:login_path => '/oauth_login',
|
|
118
|
+
:callback_path => '/oauth_callback',
|
|
119
|
+
:redirect_to => '/oauth_complete',
|
|
120
|
+
:rack_session => 'rack.session',
|
|
121
|
+
:json_parser => lambda {|json_string| require 'json'; JSON.parse(json_string); },
|
|
122
|
+
:access_token_getter => lambda {|key, oauth| oauth.get_access_token_via_instance_variable(key) },
|
|
123
|
+
:access_token_setter => lambda {|key, token, oauth| oauth.set_access_token_via_instance_variable(key, token) }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# A proc that accepts an argument for the KEY we're using to get an access token
|
|
127
|
+
# that should return the actual access token object.
|
|
128
|
+
#
|
|
129
|
+
# A second parameter is passed to your block with the Rack::OAuth instance
|
|
130
|
+
#
|
|
131
|
+
# This allows you to override how access tokens are persisted
|
|
132
|
+
attr_accessor :access_token_getter
|
|
133
|
+
alias get access_token_getter
|
|
134
|
+
alias get= access_token_getter=
|
|
135
|
+
|
|
136
|
+
# A proc that accepts an argument for the KEY we're using to set an access token
|
|
137
|
+
# and a second argument with the actual access token object.
|
|
138
|
+
#
|
|
139
|
+
# A third parameter is passed to your block with the Rack::OAuth instance
|
|
140
|
+
#
|
|
141
|
+
# This allows you to override how access tokens are persisted
|
|
142
|
+
attr_accessor :access_token_setter
|
|
143
|
+
alias set access_token_setter
|
|
144
|
+
alias set= access_token_setter=
|
|
145
|
+
|
|
146
|
+
# the URL that should initiate OAuth and redirect to the OAuth provider's login page
|
|
147
|
+
def login_path
|
|
148
|
+
::File.join *[@login_path.to_s, name_unless_default].compact
|
|
149
|
+
end
|
|
150
|
+
attr_writer :login_path
|
|
151
|
+
alias login login_path
|
|
152
|
+
alias login= login_path=
|
|
153
|
+
|
|
154
|
+
# the URL that the OAuth provider should callback to after OAuth login is complete
|
|
155
|
+
def callback_path
|
|
156
|
+
::File.join *[@callback_path.to_s, name_unless_default].compact
|
|
157
|
+
end
|
|
158
|
+
attr_writer :callback_path
|
|
159
|
+
alias callback callback_path
|
|
160
|
+
alias callback= callback_path=
|
|
161
|
+
|
|
162
|
+
# the URL that Rack::OAuth should redirect to after the OAuth has been completed (part of your app)
|
|
163
|
+
attr_accessor :redirect_to
|
|
164
|
+
alias redirect redirect_to
|
|
165
|
+
alias redirect= redirect_to=
|
|
166
|
+
|
|
167
|
+
# the name of the Rack env variable used for the session
|
|
168
|
+
attr_accessor :rack_session
|
|
169
|
+
|
|
170
|
+
# [required] Your OAuth consumer key
|
|
171
|
+
attr_accessor :consumer_key
|
|
172
|
+
alias key consumer_key
|
|
173
|
+
alias key= consumer_key=
|
|
174
|
+
|
|
175
|
+
# [required] Your OAuth consumer secret
|
|
176
|
+
attr_accessor :consumer_secret
|
|
177
|
+
alias secret consumer_secret
|
|
178
|
+
alias secret= consumer_secret=
|
|
179
|
+
|
|
180
|
+
# [required] The site you want to request OAuth for, eg. 'http://twitter.com'
|
|
181
|
+
attr_accessor :consumer_site
|
|
182
|
+
alias site consumer_site
|
|
183
|
+
alias site= consumer_site=
|
|
184
|
+
|
|
185
|
+
# a Proc that accepts a JSON string and returns a Ruby object. Defaults to using the 'json' gem, if available.
|
|
186
|
+
attr_accessor :json_parser
|
|
187
|
+
|
|
188
|
+
# an arbitrary name for this instance of Rack::OAuth
|
|
189
|
+
def name
|
|
190
|
+
@name.to_s
|
|
191
|
+
end
|
|
192
|
+
attr_writer :name
|
|
193
|
+
|
|
194
|
+
def initialize app, *args
|
|
195
|
+
@app = app
|
|
196
|
+
|
|
197
|
+
options = args.pop
|
|
198
|
+
@name = args.first || Rack::OAuth.default_instance_name
|
|
199
|
+
|
|
200
|
+
DEFAULT_OPTIONS.each {|name, value| send "#{name}=", value }
|
|
201
|
+
options.each {|name, value| send "#{name}=", value } if options
|
|
202
|
+
|
|
203
|
+
raise_validation_exception unless valid?
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def call env
|
|
207
|
+
env['rack.oauth'] ||= {}
|
|
208
|
+
env['rack.oauth'][name] = self
|
|
209
|
+
|
|
210
|
+
case env['PATH_INFO']
|
|
211
|
+
when login_path; do_login env
|
|
212
|
+
when callback_path; do_callback env
|
|
213
|
+
else; @app.call env
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def do_login env
|
|
218
|
+
|
|
219
|
+
if Rack::OAuth.test_mode?
|
|
220
|
+
session(env)[:token] = "Token"
|
|
221
|
+
session(env)[:secret] = "Secret"
|
|
222
|
+
set_access_token env, "AccessToken"
|
|
223
|
+
return [ 302, { 'Content-Type' => 'text/html', 'Location' => redirect_to }, [] ]
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
request = consumer.get_request_token :oauth_callback => ::File.join("http://#{ env['HTTP_HOST'] }", callback_path)
|
|
227
|
+
session(env)[:token] = request.token
|
|
228
|
+
session(env)[:secret] = request.secret
|
|
229
|
+
[ 302, { 'Content-Type' => 'text/html', 'Location' => request.authorize_url }, [] ]
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def do_callback env
|
|
233
|
+
session(env)[:verifier] = Rack::Request.new(env).params['oauth_verifier']
|
|
234
|
+
request = ::OAuth::RequestToken.new consumer, session(env)[:token], session(env)[:secret]
|
|
235
|
+
access = request.get_access_token :oauth_verifier => session(env)[:verifier]
|
|
236
|
+
|
|
237
|
+
# hold onto the access token
|
|
238
|
+
set_access_token env, access
|
|
239
|
+
|
|
240
|
+
[ 302, { 'Content-Type' => 'text/html', 'Location' => redirect_to }, [] ]
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Default implementation of access_token_getter
|
|
244
|
+
#
|
|
245
|
+
# Keeps tokens in an instance variable
|
|
246
|
+
def get_access_token_via_instance_variable key
|
|
247
|
+
@tokens[key] if @tokens
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Default implementation of access_token_setter
|
|
251
|
+
#
|
|
252
|
+
# Keeps tokens in an instance variable
|
|
253
|
+
def set_access_token_via_instance_variable key, token
|
|
254
|
+
@tokens ||= {}
|
|
255
|
+
@tokens[key] = token
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Returns the key to use (for this particular session) to get or set an
|
|
259
|
+
# access token for this Rack env
|
|
260
|
+
#
|
|
261
|
+
# TODO this will very likely change as we want to be able to get or set
|
|
262
|
+
# access tokens using useful data like a user's name in the future
|
|
263
|
+
def key_for_env env
|
|
264
|
+
val = session(env)[:token] + session(env)[:secret] if session(env)[:token] and session(env)[:secret]
|
|
265
|
+
session(env)[:token] + session(env)[:secret] if session(env)[:token] and session(env)[:secret]
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Gets an Access Token by key using access_token_getter (for this specific ENV)
|
|
269
|
+
def get_access_token env
|
|
270
|
+
access_token_getter.call key_for_env(env), self
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Sets an Access Token by key and value using access_token_setter (for this specific ENV)
|
|
274
|
+
def set_access_token env, token
|
|
275
|
+
access_token_setter.call key_for_env(env), token, self
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Usage:
|
|
279
|
+
#
|
|
280
|
+
# request '/account/verify_credentials.json'
|
|
281
|
+
# request 'GET', '/account/verify_credentials.json'
|
|
282
|
+
# request :post, '/statuses/update.json', :status => params[:tweet]
|
|
283
|
+
#
|
|
284
|
+
def request env, method, path = nil, *args
|
|
285
|
+
if method.to_s.start_with?('/')
|
|
286
|
+
path = method
|
|
287
|
+
method = :get
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
return Rack::OAuth.mock_response_for(method, path) if Rack::OAuth.test_mode?
|
|
291
|
+
|
|
292
|
+
consumer.request method.to_s.downcase.to_sym, path, get_access_token(env), *args
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Same as #request but you can manually pass your own request token
|
|
296
|
+
def request_with_access_token token, method, path = nil, *args
|
|
297
|
+
if method.to_s.start_with?('/')
|
|
298
|
+
path = method
|
|
299
|
+
method = :get
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
return Rack::OAuth.mock_response_for(method, path) if Rack::OAuth.test_mode?
|
|
303
|
+
|
|
304
|
+
consumer.request method.to_s.downcase.to_sym, path, token, *args
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Returns the mock response, if one has been set via #mock_request, for a method and path.
|
|
308
|
+
#
|
|
309
|
+
# Raises an exception if the response doesn't exist because we never want the test environment
|
|
310
|
+
# to *actually* make real requests!
|
|
311
|
+
def self.mock_response_for method, path
|
|
312
|
+
unless @mock_responses and @mock_responses[path] and @mock_responses[path][method]
|
|
313
|
+
raise "No mock response created for #{ method.inspect } #{ path.inspect }"
|
|
314
|
+
else
|
|
315
|
+
return @mock_responses[path][method]
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Set the response that should be returned when a particular method and path are called.
|
|
320
|
+
#
|
|
321
|
+
# This is used when Rack::OAuth::test_mode? is true
|
|
322
|
+
def self.mock_request method, path, response = nil
|
|
323
|
+
if method.to_s.start_with?('/')
|
|
324
|
+
response = path
|
|
325
|
+
path = method
|
|
326
|
+
method = :get
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
@mock_responses ||= {}
|
|
330
|
+
@mock_responses[path] ||= {}
|
|
331
|
+
@mock_responses[path][method] = response
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def verified? env
|
|
335
|
+
[ :token, :secret, :verifier ].all? { |required_session_key| session(env)[required_session_key] }
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def consumer
|
|
339
|
+
@consumer ||= ::OAuth::Consumer.new consumer_key, consumer_secret, :site => consumer_site
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def valid?
|
|
343
|
+
@errors = []
|
|
344
|
+
@errors << ":consumer_key option is required" unless consumer_key
|
|
345
|
+
@errors << ":consumer_secret option is required" unless consumer_secret
|
|
346
|
+
@errors << ":consumer_site option is required" unless consumer_site
|
|
347
|
+
@errors.empty?
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def raise_validation_exception
|
|
351
|
+
raise @errors.join(', ')
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# Returns a hash of session variables, specific to this instance of Rack::OAuth and the end-user
|
|
355
|
+
#
|
|
356
|
+
# All user-specific variables are stored in the session.
|
|
357
|
+
#
|
|
358
|
+
# The variables we currently keep track of are:
|
|
359
|
+
# - token
|
|
360
|
+
# - secret
|
|
361
|
+
# - verifier
|
|
362
|
+
#
|
|
363
|
+
# With all three of these, we can make arbitrary requests to our OAuth provider for this user.
|
|
364
|
+
def session env
|
|
365
|
+
raise "Rack env['rack.session'] is nil ... has a Rack::Session middleware be enabled? " +
|
|
366
|
+
"use :rack_session for custom key" if env[rack_session].nil?
|
|
367
|
+
env[rack_session]['rack.oauth'] ||= {}
|
|
368
|
+
env[rack_session]['rack.oauth'][name] ||= {}
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Returns the #name of this Rack::OAuth unless the name is 'default', in which case it returns nil
|
|
372
|
+
def name_unless_default
|
|
373
|
+
name == Rack::OAuth.default_instance_name ? nil : name
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
--- !ruby/object:OAuth::AccessToken
|
|
2
|
+
consumer: !ruby/object:OAuth::Consumer
|
|
3
|
+
http: !ruby/object:Net::HTTP
|
|
4
|
+
address: twitter.com
|
|
5
|
+
close_on_empty_response: false
|
|
6
|
+
curr_http_version: "1.1"
|
|
7
|
+
debug_output:
|
|
8
|
+
newimpl: true
|
|
9
|
+
open_timeout:
|
|
10
|
+
port: 80
|
|
11
|
+
read_timeout: 60
|
|
12
|
+
seems_1_0_server: false
|
|
13
|
+
socket:
|
|
14
|
+
ssl_context: !ruby/object:OpenSSL::SSL::SSLContext
|
|
15
|
+
ca_file: /etc/ssl/certs/ca-certificates.crt
|
|
16
|
+
ca_path:
|
|
17
|
+
cert:
|
|
18
|
+
cert_store:
|
|
19
|
+
client_ca:
|
|
20
|
+
client_cert_cb:
|
|
21
|
+
extra_chain_cert:
|
|
22
|
+
key:
|
|
23
|
+
options:
|
|
24
|
+
session_get_cb:
|
|
25
|
+
session_id_context:
|
|
26
|
+
session_new_cb:
|
|
27
|
+
session_remove_cb:
|
|
28
|
+
timeout:
|
|
29
|
+
tmp_dh_callback:
|
|
30
|
+
verify_callback:
|
|
31
|
+
verify_depth: 5
|
|
32
|
+
verify_mode: 1
|
|
33
|
+
started: false
|
|
34
|
+
use_ssl: false
|
|
35
|
+
http_method: :post
|
|
36
|
+
key: 4JjFmhjfZyQ6rdbiql5A
|
|
37
|
+
options:
|
|
38
|
+
:http_method: :post
|
|
39
|
+
:scheme: :header
|
|
40
|
+
:oauth_version: "1.0"
|
|
41
|
+
:proxy:
|
|
42
|
+
:request_token_path: /oauth/request_token
|
|
43
|
+
:authorize_path: /oauth/authorize
|
|
44
|
+
:site: http://twitter.com
|
|
45
|
+
:signature_method: HMAC-SHA1
|
|
46
|
+
:access_token_path: /oauth/access_token
|
|
47
|
+
secret: rv4ZaCgvxVPVjxHIDbMxTGFbIMxUa4KkIdPqL7HmaQo
|
|
48
|
+
params:
|
|
49
|
+
oauth_token_secret: K7Z5LHyweHKd3rPaaiHMUCaYQyAC0suWQcOPGfM
|
|
50
|
+
:user_id: "11043342"
|
|
51
|
+
user_id: "11043342"
|
|
52
|
+
:oauth_token_secret: K7Z5LHyweHKd3rPaaiHMUCaYQyAC0suWQcOPGfM
|
|
53
|
+
:screen_name: remitaylor
|
|
54
|
+
oauth_token: 11043342-rH2Rdn9AcLzVBIL3cnQqCJ96mb0Zp2XC56Qx4bsMB
|
|
55
|
+
:oauth_token: 11043342-rH2Rdn9AcLzVBIL3cnQqCJ96mb0Zp2XC56Qx4bsMB
|
|
56
|
+
screen_name: remitaylor
|
|
57
|
+
secret: K7Z5LHyweHKd3rPaaiHMUCaYQyAC0suWQcOPGfM
|
|
58
|
+
token: 11043342-rH2Rdn9AcLzVBIL3cnQqCJ96mb0Zp2XC56Qx4bsMB
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--- sCJz6SHIaQAUtAj4FOmTwwwpruV3fsGAWsrH3ynqQ
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--- XnS8UEe2l4iKAYqPBFhQ0wfI0s3i2nLE1RjnC1CbA
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--- 6dhuchM6Wzh9PpNv0KGB0h3AxzHLZ2Vy9erSJsOAv4
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
--- !ruby/object:OAuth::RequestToken
|
|
2
|
+
consumer: !ruby/object:OAuth::Consumer
|
|
3
|
+
http: !ruby/object:Net::HTTP
|
|
4
|
+
address: twitter.com
|
|
5
|
+
close_on_empty_response: false
|
|
6
|
+
curr_http_version: "1.1"
|
|
7
|
+
debug_output:
|
|
8
|
+
newimpl: true
|
|
9
|
+
open_timeout:
|
|
10
|
+
port: 80
|
|
11
|
+
read_timeout: 60
|
|
12
|
+
seems_1_0_server: false
|
|
13
|
+
socket:
|
|
14
|
+
ssl_context: !ruby/object:OpenSSL::SSL::SSLContext
|
|
15
|
+
ca_file: /etc/ssl/certs/ca-certificates.crt
|
|
16
|
+
ca_path:
|
|
17
|
+
cert:
|
|
18
|
+
cert_store:
|
|
19
|
+
client_ca:
|
|
20
|
+
client_cert_cb:
|
|
21
|
+
extra_chain_cert:
|
|
22
|
+
key:
|
|
23
|
+
options:
|
|
24
|
+
session_get_cb:
|
|
25
|
+
session_id_context:
|
|
26
|
+
session_new_cb:
|
|
27
|
+
session_remove_cb:
|
|
28
|
+
timeout:
|
|
29
|
+
tmp_dh_callback:
|
|
30
|
+
verify_callback:
|
|
31
|
+
verify_depth: 5
|
|
32
|
+
verify_mode: 1
|
|
33
|
+
started: false
|
|
34
|
+
use_ssl: false
|
|
35
|
+
http_method: :post
|
|
36
|
+
key: 4JjFmhjfZyQ6rdbiql5A
|
|
37
|
+
options:
|
|
38
|
+
:http_method: :post
|
|
39
|
+
:scheme: :header
|
|
40
|
+
:oauth_version: "1.0"
|
|
41
|
+
:proxy:
|
|
42
|
+
:request_token_path: /oauth/request_token
|
|
43
|
+
:authorize_path: AUTH_PATH
|
|
44
|
+
:site: http://twitter.com
|
|
45
|
+
:signature_method: HMAC-SHA1
|
|
46
|
+
:access_token_path: /oauth/access_token
|
|
47
|
+
secret: rv4ZaCgvxVPVjxHIDbMxTGFbIMxUa4KkIdPqL7HmaQo
|
|
48
|
+
params:
|
|
49
|
+
oauth_callback_confirmed: "true"
|
|
50
|
+
oauth_token_secret: XnS8UEe2l4iKAYqPBFhQ0wfI0s3i2nLE1RjnC1CbA
|
|
51
|
+
:oauth_callback_confirmed: "true"
|
|
52
|
+
:oauth_token_secret: XnS8UEe2l4iKAYqPBFhQ0wfI0s3i2nLE1RjnC1CbA
|
|
53
|
+
oauth_token: 6dhuchM6Wzh9PpNv0KGB0h3AxzHLZ2Vy9erSJsOAv4
|
|
54
|
+
:oauth_token: 6dhuchM6Wzh9PpNv0KGB0h3AxzHLZ2Vy9erSJsOAv4
|
|
55
|
+
secret: XnS8UEe2l4iKAYqPBFhQ0wfI0s3i2nLE1RjnC1CbA
|
|
56
|
+
token: 6dhuchM6Wzh9PpNv0KGB0h3AxzHLZ2Vy9erSJsOAv4
|