xaviershay-twitter-auth 0.1.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/README.markdown +119 -0
  2. data/Rakefile +31 -0
  3. data/VERSION.yml +4 -0
  4. data/app/controllers/sessions_controller.rb +66 -0
  5. data/app/models/twitter_auth/basic_user.rb +63 -0
  6. data/app/models/twitter_auth/generic_user.rb +93 -0
  7. data/app/models/twitter_auth/oauth_user.rb +44 -0
  8. data/app/views/sessions/_login_form.html.erb +17 -0
  9. data/app/views/sessions/new.html.erb +5 -0
  10. data/config/routes.rb +6 -0
  11. data/generators/twitter_auth/USAGE +12 -0
  12. data/generators/twitter_auth/templates/migration.rb +48 -0
  13. data/generators/twitter_auth/templates/twitter_auth.yml +47 -0
  14. data/generators/twitter_auth/templates/user.rb +5 -0
  15. data/generators/twitter_auth/twitter_auth_generator.rb +34 -0
  16. data/lib/twitter_auth.rb +99 -0
  17. data/lib/twitter_auth/controller_extensions.rb +69 -0
  18. data/lib/twitter_auth/cryptify.rb +30 -0
  19. data/lib/twitter_auth/dispatcher/basic.rb +46 -0
  20. data/lib/twitter_auth/dispatcher/oauth.rb +26 -0
  21. data/lib/twitter_auth/dispatcher/shared.rb +40 -0
  22. data/rails/init.rb +8 -0
  23. data/spec/controllers/controller_extensions_spec.rb +162 -0
  24. data/spec/controllers/sessions_controller_spec.rb +250 -0
  25. data/spec/fixtures/config/twitter_auth.yml +17 -0
  26. data/spec/fixtures/factories.rb +18 -0
  27. data/spec/fixtures/fakeweb.rb +18 -0
  28. data/spec/fixtures/twitter.rb +5 -0
  29. data/spec/models/twitter_auth/basic_user_spec.rb +122 -0
  30. data/spec/models/twitter_auth/generic_user_spec.rb +142 -0
  31. data/spec/models/twitter_auth/oauth_user_spec.rb +101 -0
  32. data/spec/schema.rb +41 -0
  33. data/spec/spec.opts +1 -0
  34. data/spec/spec_helper.rb +53 -0
  35. data/spec/twitter_auth/cryptify_spec.rb +51 -0
  36. data/spec/twitter_auth/dispatcher/basic_spec.rb +83 -0
  37. data/spec/twitter_auth/dispatcher/oauth_spec.rb +72 -0
  38. data/spec/twitter_auth/dispatcher/shared_spec.rb +26 -0
  39. data/spec/twitter_auth_spec.rb +160 -0
  40. metadata +127 -0
@@ -0,0 +1,8 @@
1
+ # Gem Dependencies
2
+ config.gem 'oauth'
3
+ config.gem 'ezcrypto'
4
+
5
+ require 'json'
6
+ require 'twitter_auth'
7
+
8
+ RAILS_DEFAULT_LOGGER.info("** TwitterAuth initialized properly.")
@@ -0,0 +1,162 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ ActionController::Routing::Routes.draw do |map|
4
+ map.connect ':controller/:action/:id'
5
+ end
6
+
7
+ class TwitterAuthTestController < ApplicationController
8
+ before_filter :login_required, :only => [:login_required_action]
9
+
10
+ def login_required_action
11
+ render :text => "You are logged in!"
12
+ end
13
+
14
+ def fail_auth
15
+ authentication_failed('Auth FAIL.')
16
+ end
17
+
18
+ def pass_auth
19
+ if params[:message]
20
+ authentication_succeeded(params[:message])
21
+ else
22
+ authentication_succeeded
23
+ end
24
+ end
25
+
26
+ def access_denied_action
27
+ access_denied
28
+ end
29
+
30
+ def redirect_back_action
31
+ redirect_back_or_default(params[:to] || '/')
32
+ end
33
+
34
+ def logout_keeping_session_action
35
+ logout_keeping_session!
36
+ redirect_back_or_default('/')
37
+ end
38
+
39
+ def current_user_action
40
+ @user = current_user
41
+ render :nothing => true
42
+ end
43
+ end
44
+
45
+ describe TwitterAuthTestController do
46
+ before do
47
+ controller.stub!(:cookies).and_return({})
48
+ end
49
+
50
+ %w(authentication_failed authentication_succeeded current_user authorized? login_required access_denied store_location redirect_back_or_default logout_keeping_session!).each do |m|
51
+ it "should respond to the extension method '#{m}'" do
52
+ controller.should respond_to(m)
53
+ end
54
+ end
55
+
56
+ describe "#authentication_failed" do
57
+ it 'should set the flash[:error] to the message passed in' do
58
+ get :fail_auth
59
+ flash[:error].should == 'Auth FAIL.'
60
+ end
61
+
62
+ it 'should redirect to the root' do
63
+ get :fail_auth
64
+ should redirect_to('/')
65
+ end
66
+ end
67
+
68
+ describe "#authentication_succeeded" do
69
+ it 'should set the flash[:notice] to a default success message' do
70
+ get :pass_auth
71
+ flash[:notice].should == 'You have logged in successfully.'
72
+ end
73
+
74
+ it 'should be able ot receive a custom message' do
75
+ get :pass_auth, :message => 'Eat at Joes.'
76
+ flash[:notice].should == 'Eat at Joes.'
77
+ end
78
+ end
79
+
80
+ describe '#current_user' do
81
+ it 'should find the user based on the session user_id' do
82
+ user = Factory.create(:twitter_oauth_user)
83
+ request.session[:user_id] = user.id
84
+ get(:current_user_action)
85
+ assigns[:user].should == user
86
+ end
87
+
88
+ it 'should log the user in through a cookie' do
89
+ user = Factory(:twitter_oauth_user, :remember_token => 'abc', :remember_token_expires_at => (Time.now + 10.days))
90
+ controller.stub!(:cookies).and_return({:remember_token => 'abc'})
91
+ get :current_user_action
92
+ assigns[:user].should == user
93
+ end
94
+
95
+ it 'should return nil if there is no user matching that id' do
96
+ request.session[:user_id] = 2345
97
+ get :current_user_action
98
+ assigns[:user].should be_nil
99
+ end
100
+ end
101
+
102
+ describe "#authorized?" do
103
+ it 'should be true if there is a current_user' do
104
+ user = Factory.create(:twitter_oauth_user)
105
+ controller.stub!(:current_user).and_return(user)
106
+ controller.send(:authorized?).should be_true
107
+ end
108
+
109
+ it 'should be false if there is not current_user' do
110
+ controller.stub!(:current_user).and_return(nil)
111
+ controller.send(:authorized?).should be_false
112
+ end
113
+ end
114
+
115
+ describe '#access_denied' do
116
+ it 'should redirect to the login path' do
117
+ get :access_denied_action
118
+ should redirect_to(login_path)
119
+ end
120
+
121
+ it 'should store the location first' do
122
+ controller.should_receive(:store_location).once
123
+ get :access_denied_action
124
+ end
125
+ end
126
+
127
+ describe '#redirect_back_or_default' do
128
+ it 'should redirect if there is a session[:return_to]' do
129
+ request.session[:return_to] = '/'
130
+ get :redirect_back_action, :to => '/notroot'
131
+ should redirect_to('/')
132
+ end
133
+
134
+ it 'should redirect to the default provided otherwise' do
135
+ get :redirect_back_action, :to => '/someurl'
136
+ should redirect_to('/someurl')
137
+ end
138
+ end
139
+
140
+ describe 'logout_keeping_session!' do
141
+ before do
142
+ @user = Factory.create(:twitter_oauth_user)
143
+ request.session[:user_id] = @user.id
144
+ end
145
+
146
+ it 'should unset session[:user_id]' do
147
+ get :logout_keeping_session_action
148
+ request.session[:user_id].should be_nil
149
+ end
150
+
151
+ it 'should unset current_user' do
152
+ controller.send(:current_user).should == @user
153
+ get :logout_keeping_session_action
154
+ controller.send(:current_user).should be_nil
155
+ end
156
+
157
+ it 'should unset the cookie' do
158
+ controller.send(:cookies).should_receive(:delete).with(:remember_token)
159
+ get :logout_keeping_session_action
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,250 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SessionsController do
4
+ integrate_views
5
+
6
+ describe 'routes' do
7
+ it 'should route /session/new to SessionsController#new' do
8
+ params_from(:get, '/session/new').should == {:controller => 'sessions', :action => 'new'}
9
+ end
10
+
11
+ it 'should route /login to SessionsController#new' do
12
+ params_from(:get, '/login').should == {:controller => 'sessions', :action => 'new'}
13
+ end
14
+
15
+ it 'should route /logout to SessionsController#destroy' do
16
+ params_from(:get, '/logout').should == {:controller => 'sessions', :action => 'destroy'}
17
+ end
18
+
19
+ it 'should route DELETE /session to SessionsController#destroy' do
20
+ params_from(:delete, '/session').should == {:controller => 'sessions', :action => 'destroy'}
21
+ end
22
+
23
+ it 'should route /oauth_callback to SessionsController#oauth_callback' do
24
+ params_from(:get, '/oauth_callback').should == {:controller => 'sessions', :action => 'oauth_callback'}
25
+ end
26
+
27
+ it 'should route POST /session to SessionsController#create' do
28
+ params_from(:post, '/session').should == {:controller => 'sessions', :action => 'create'}
29
+ end
30
+ end
31
+
32
+ describe 'with OAuth strategy' do
33
+ before do
34
+ stub_oauth!
35
+ end
36
+
37
+ describe '#new' do
38
+ it 'should retrieve a request token' do
39
+ get :new
40
+ assigns[:request_token].token.should == 'faketoken'
41
+ assigns[:request_token].secret.should == 'faketokensecret'
42
+ end
43
+
44
+ it 'should set session variables for the request token' do
45
+ get :new
46
+ session[:request_token].should == 'faketoken'
47
+ session[:request_token_secret].should == 'faketokensecret'
48
+ end
49
+
50
+ it 'should redirect to the oauth authorization url' do
51
+ get :new
52
+ response.should redirect_to('https://twitter.com/oauth/authorize?oauth_token=faketoken')
53
+ end
54
+
55
+ it 'should redirect to the oauth_callback if one is specified' do
56
+ TwitterAuth.stub!(:oauth_callback).and_return('http://localhost:3000/development')
57
+ TwitterAuth.stub!(:oauth_callback?).and_return(true)
58
+
59
+ get :new
60
+ response.should redirect_to('https://twitter.com/oauth/authorize?oauth_token=faketoken&oauth_callback=' + CGI.escape(TwitterAuth.oauth_callback))
61
+ end
62
+ end
63
+
64
+ describe '#oauth_callback' do
65
+ describe 'with no session info' do
66
+ it 'should set the flash[:error]' do
67
+ get :oauth_callback, :oauth_token => 'faketoken'
68
+ flash[:error].should == 'No authentication information was found in the session. Please try again.'
69
+ end
70
+
71
+ it 'should redirect to "/" by default' do
72
+ get :oauth_callback, :oauth_token => 'faketoken'
73
+ response.should redirect_to('/')
74
+ end
75
+
76
+ it 'should call authentication_failed' do
77
+ controller.should_receive(:authentication_failed).any_number_of_times
78
+ get :oauth_callback, :oauth_token => 'faketoken'
79
+ end
80
+ end
81
+
82
+ describe 'with proper info for new user' do
83
+ before do
84
+ @time = Time.now
85
+
86
+ Time.stub!(:now).and_return(@time)
87
+ ActiveSupport::SecureRandom.stub!(:hex).and_return(@remember_token)
88
+
89
+ request.session[:request_token] = 'faketoken'
90
+ request.session[:request_token_secret] = 'faketokensecret'
91
+ end
92
+
93
+ it "should create the user" do
94
+ get :oauth_callback, :oauth_token => 'faketoken'
95
+ assigns[:user].should_not be_nil
96
+ assigns[:user].login.should == 'twitterman'
97
+ end
98
+
99
+ it "should allow user attributes to be set in a callback" do
100
+ @controller.instance_eval do
101
+ def build_user(user)
102
+ user.login = 'hijacked'
103
+ end
104
+ end
105
+ get :oauth_callback, :oauth_token => 'faketoken'
106
+ assigns[:user].should_not be_nil
107
+ assigns[:user].login.should == 'hijacked'
108
+ end
109
+ end
110
+
111
+ describe 'with proper info' do
112
+ before do
113
+ @user = Factory.create(:twitter_oauth_user)
114
+ @time = Time.now
115
+ @remember_token = ActiveSupport::SecureRandom.hex(10)
116
+
117
+ Time.stub!(:now).and_return(@time)
118
+ ActiveSupport::SecureRandom.stub!(:hex).and_return(@remember_token)
119
+
120
+ request.session[:request_token] = 'faketoken'
121
+ request.session[:request_token_secret] = 'faketokensecret'
122
+ get :oauth_callback, :oauth_token => 'faketoken'
123
+ end
124
+
125
+ describe 'building the access token' do
126
+ it 'should rebuild the request token' do
127
+ correct_token = OAuth::RequestToken.new(TwitterAuth.consumer,'faketoken','faketokensecret')
128
+
129
+ %w(token secret).each do |att|
130
+ assigns[:request_token].send(att).should == correct_token.send(att)
131
+ end
132
+ end
133
+
134
+ it 'should exchange the request token for an access token' do
135
+ assigns[:access_token].should be_a(OAuth::AccessToken)
136
+ assigns[:access_token].token.should == 'fakeaccesstoken'
137
+ assigns[:access_token].secret.should == 'fakeaccesstokensecret'
138
+ end
139
+
140
+ it 'should wipe the request token after exchange' do
141
+ session[:request_token].should be_nil
142
+ session[:request_token_secret].should be_nil
143
+ end
144
+ end
145
+
146
+ describe 'identifying the user' do
147
+ it "should find the user" do
148
+ assigns[:user].should == @user
149
+ end
150
+
151
+ it "should assign the user id to the session" do
152
+ session[:user_id].should == @user.id
153
+ end
154
+
155
+ it "should call remember me" do
156
+ @user.reload
157
+ @user.remember_token.should == @remember_token
158
+ end
159
+
160
+ it "should set a cookie" do
161
+ cookies[:remember_token].should == @remember_token
162
+ end
163
+ end
164
+
165
+ describe "when OAuth doesn't work" do
166
+ before do
167
+ request.session[:request_token] = 'faketoken'
168
+ request.session[:request_token_secret] = 'faketokensecret'
169
+ @request_token = OAuth::RequestToken.new(TwitterAuth.consumer, session[:request_token], session[:request_token_secret])
170
+ OAuth::RequestToken.stub!(:new).and_return(@request_token)
171
+ end
172
+
173
+ it 'should call authentication_failed when it gets a 401 from OAuth' do
174
+ @request_token.stub!(:get_access_token).and_raise(Net::HTTPServerException.new('401 "Unauthorized"', '401 "Unauthorized"'))
175
+ controller.should_receive(:authentication_failed).with('This authentication request is no longer valid. Please try again.')
176
+ # the should raise_error is hacky because of the expectation
177
+ # stubbing the proper behavior :-(
178
+ lambda{get :oauth_callback, :oauth_token => 'faketoken'}.should raise_error(ActionView::MissingTemplate)
179
+ end
180
+
181
+ it 'should call authentication_failed when it gets a different HTTPServerException' do
182
+ @request_token.stub!(:get_access_token).and_raise(Net::HTTPServerException.new('404 "Not Found"', '404 "Not Found"'))
183
+ controller.should_receive(:authentication_failed).with('There was a problem trying to authenticate you. Please try again.')
184
+ lambda{get :oauth_callback, :oauth_token => 'faketoken'}.should raise_error(ActionView::MissingTemplate)
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ describe 'with Basic strategy' do
192
+ before do
193
+ stub_basic!
194
+ end
195
+
196
+ describe '#new' do
197
+ it 'should render the new action' do
198
+ get :new
199
+ response.should render_template('sessions/new')
200
+ end
201
+
202
+ it 'should render the login form' do
203
+ get :new
204
+ response.should have_tag('form[action=/session][id=login_form][method=post]')
205
+ end
206
+
207
+ describe '#create' do
208
+ before do
209
+ @user = Factory.create(:twitter_basic_user)
210
+ end
211
+
212
+ it 'should call logout_keeping_session! to remove session info' do
213
+ controller.should_receive(:logout_keeping_session!)
214
+ post :create
215
+ end
216
+
217
+ it 'should try to authenticate the user' do
218
+ User.should_receive(:authenticate)
219
+ post :create
220
+ end
221
+
222
+ it 'should call authentication_failed on authenticate failure' do
223
+ User.should_receive(:authenticate).and_return(nil)
224
+ post :create, :login => 'wrong', :password => 'false'
225
+ response.should redirect_to('/login')
226
+ end
227
+
228
+ it 'should call authentication_succeeded on authentication success' do
229
+ User.should_receive(:authenticate).and_return(@user)
230
+ post :create, :login => 'twitterman', :password => 'cool'
231
+ response.should redirect_to('/')
232
+ flash[:notice].should_not be_blank
233
+ end
234
+ end
235
+ end
236
+
237
+ end
238
+
239
+ describe '#destroy' do
240
+ it 'should call logout_keeping_session!' do
241
+ controller.should_receive(:logout_keeping_session!).once
242
+ get :destroy
243
+ end
244
+
245
+ it 'should redirect to the root' do
246
+ get :destroy
247
+ response.should redirect_to('/')
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,17 @@
1
+ development:
2
+ strategy: oauth
3
+ base_url: "https://twitter.com"
4
+ oauth_consumer_key: devkey
5
+ oauth_consumer_secret: devsecret
6
+ oauth_callback: "http://localhost:3000"
7
+ test:
8
+ strategy: oauth
9
+ base_url: "https://twitter.com"
10
+ oauth_consumer_key: testkey
11
+ oauth_consumer_secret: testsecret
12
+ production:
13
+ strategy: oauth
14
+ base_url: "https://twitter.com"
15
+ oauth_consumer_key: prodkey
16
+ oauth_consumer_secret: prodsecret
17
+
@@ -0,0 +1,18 @@
1
+ require 'factory_girl'
2
+
3
+ Factory.define(:twitter_oauth_user, :class => User) do |u|
4
+ u.login 'twitterman'
5
+ u.access_token 'fakeaccesstoken'
6
+ u.access_secret 'fakeaccesstokensecret'
7
+
8
+ u.name 'Twitter Man'
9
+ u.description 'Saving the world for all Twitter kind.'
10
+ end
11
+
12
+ Factory.define(:twitter_basic_user, :class => User) do |u|
13
+ u.login 'twitterman'
14
+ u.password 'test'
15
+
16
+ u.name 'Twitter Man'
17
+ u.description 'Saving the world for all Twitter kind.'
18
+ end