mbleigh-twitter-auth 0.0.2 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,19 +1,30 @@
1
1
  module TwitterAuth
2
2
  module Cryptify
3
3
  class Error < StandardError; end
4
- mattr_accessor :crypt_password
5
- @@crypt_password = '--TwitterAuth-!##@--2ef'
6
4
 
7
- def self.encrypt(data, salt)
8
- EzCrypto::Key.encrypt_with_password(crypt_password, salt, data)
5
+ def self.encrypt(data)
6
+ salt = generate_salt
7
+ {:encrypted_data => EzCrypto::Key.encrypt_with_password(TwitterAuth.encryption_key, salt, data), :salt => salt}
9
8
  end
9
+
10
+ def self.decrypt(encrypted_data_or_hash, salt=nil)
11
+ case encrypted_data_or_hash
12
+ when String
13
+ encrypted_data = encrypted_data_or_hash
14
+ raise ArgumentError, 'Must provide a salt to decrypt.' unless salt
15
+ when Hash
16
+ encrypted_data = encrypted_data_or_hash[:encrypted_data]
17
+ salt = encrypted_data_or_hash[:salt]
18
+ else
19
+ raise ArgumentError, 'Must provide either an encrypted hash result or encrypted string and salt.'
20
+ end
10
21
 
11
- def self.decrypt(encrypted_data, salt)
12
- EzCrypto::Key.decrypt_with_password(crypt_password, salt, encrypted_data)
22
+ EzCrypto::Key.decrypt_with_password(TwitterAuth.encryption_key, salt, encrypted_data)
13
23
  end
14
24
 
15
25
  def self.generate_salt
16
26
  ActiveSupport::SecureRandom.hex(4)
17
27
  end
18
28
  end
19
- end
29
+ end
30
+
@@ -0,0 +1,45 @@
1
+ require 'net/http'
2
+
3
+ module TwitterAuth
4
+ module Dispatcher
5
+ class Basic
6
+ attr_accessor :user
7
+
8
+ def initialize(user)
9
+ raise TwitterAuth::Error, 'Dispatcher must be initialized with a User.' unless user.is_a?(TwitterAuth::BasicUser)
10
+ self.user = user
11
+ end
12
+
13
+ def request(http_method, path, body=nil, *arguments)
14
+ path << '.json' unless path.match(/\.(:?xml|json)\z/i)
15
+
16
+ response = TwitterAuth.net.start{ |http|
17
+ req = "Net::HTTP::#{http_method.to_s.capitalize}".constantize.new(path, *arguments)
18
+ req.basic_auth user.login, user.password
19
+ req.set_form_data(body) unless body.nil?
20
+ http.request(req)
21
+ }
22
+
23
+ JSON.parse(response.body)
24
+ rescue JSON::ParserError
25
+ response.body
26
+ end
27
+
28
+ def get(path, *arguments)
29
+ request(:get, path, *arguments)
30
+ end
31
+
32
+ def post(path, body='', *arguments)
33
+ request(:post, path, body, *arguments)
34
+ end
35
+
36
+ def put(path, body='', *arguments)
37
+ request(:put, path, body, *arguments)
38
+ end
39
+
40
+ def delete(path, *arguments)
41
+ request(:delete, path, *arguments)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,23 @@
1
+ require 'oauth'
2
+
3
+ module TwitterAuth
4
+ module Dispatcher
5
+ class Oauth < OAuth::AccessToken
6
+ attr_accessor :user
7
+
8
+ def initialize(user)
9
+ raise TwitterAuth::Error, 'Dispatcher must be initialized with a User.' unless user.is_a?(TwitterAuth::OauthUser)
10
+ self.user = user
11
+ super(TwitterAuth.consumer, user.access_token, user.access_secret)
12
+ end
13
+
14
+ def request(http_method, path, *arguments)
15
+ path << '.json' unless path.match(/\.(:?xml|json)\z/i)
16
+ response = super
17
+ JSON.parse(response.body)
18
+ rescue JSON::ParserError
19
+ response.body
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,146 @@
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
+ end
39
+
40
+ describe TwitterAuthTestController do
41
+ %w(authentication_failed authentication_succeeded current_user authorized? login_required access_denied store_location redirect_back_or_default logout_keeping_session!).each do |m|
42
+ it "should respond to the extension method '#{m}'" do
43
+ controller.should respond_to(m)
44
+ end
45
+ end
46
+
47
+ describe "#authentication_failed" do
48
+ it 'should set the flash[:error] to the message passed in' do
49
+ get :fail_auth
50
+ flash[:error].should == 'Auth FAIL.'
51
+ end
52
+
53
+ it 'should redirect to the root' do
54
+ get :fail_auth
55
+ should redirect_to('/')
56
+ end
57
+ end
58
+
59
+ describe "#authentication_succeeded" do
60
+ it 'should set the flash[:notice] to a default success message' do
61
+ get :pass_auth
62
+ flash[:notice].should == 'You have logged in successfully.'
63
+ end
64
+
65
+ it 'should be able ot receive a custom message' do
66
+ get :pass_auth, :message => 'Eat at Joes.'
67
+ flash[:notice].should == 'Eat at Joes.'
68
+ end
69
+ end
70
+
71
+ describe '#current_user' do
72
+ it 'should find the user based on the session user_id' do
73
+ user = Factory.create(:twitter_oauth_user)
74
+ request.session[:user_id] = user.id
75
+ controller.send(:current_user).should == user
76
+ end
77
+
78
+ it 'should return nil if there is no user matching that id' do
79
+ request.session[:user_id] = 2345
80
+ controller.send(:current_user).should be_nil
81
+ end
82
+
83
+ it 'should memoize the result (and not do a double find)' do
84
+ user = Factory.create(:twitter_oauth_user)
85
+ User.should_receive(:find_by_id).once.and_return(user)
86
+ controller.send(:current_user).should == user
87
+ controller.send(:current_user).should == user
88
+ end
89
+ end
90
+
91
+ describe "#authorized?" do
92
+ it 'should be true if there is a current_user' do
93
+ user = Factory.create(:twitter_oauth_user)
94
+ controller.stub!(:current_user).and_return(user)
95
+ controller.send(:authorized?).should be_true
96
+ end
97
+
98
+ it 'should be false if there is not current_user' do
99
+ controller.stub!(:current_user).and_return(nil)
100
+ controller.send(:authorized?).should be_false
101
+ end
102
+ end
103
+
104
+ describe '#access_denied' do
105
+ it 'should redirect to the login path' do
106
+ get :access_denied_action
107
+ should redirect_to(login_path)
108
+ end
109
+
110
+ it 'should store the location first' do
111
+ controller.should_receive(:store_location).once
112
+ get :access_denied_action
113
+ end
114
+ end
115
+
116
+ describe '#redirect_back_or_default' do
117
+ it 'should redirect if there is a session[:return_to]' do
118
+ request.session[:return_to] = '/'
119
+ get :redirect_back_action, :to => '/notroot'
120
+ should redirect_to('/')
121
+ end
122
+
123
+ it 'should redirect to the default provided otherwise' do
124
+ get :redirect_back_action, :to => '/someurl'
125
+ should redirect_to('/someurl')
126
+ end
127
+ end
128
+
129
+ describe 'logout_keeping_session!' do
130
+ before do
131
+ @user = Factory.create(:twitter_oauth_user)
132
+ request.session[:user_id] = @user.id
133
+ end
134
+
135
+ it 'should unset session[:user_id]' do
136
+ get :logout_keeping_session_action
137
+ request.session[:user_id].should be_nil
138
+ end
139
+
140
+ it 'should unset current_user' do
141
+ controller.send(:current_user).should == @user
142
+ get :logout_keeping_session_action
143
+ controller.send(:current_user).should be_nil
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,206 @@
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' do
83
+ before do
84
+ @user = Factory.create(:twitter_oauth_user)
85
+ request.session[:request_token] = 'faketoken'
86
+ request.session[:request_token_secret] = 'faketokensecret'
87
+ get :oauth_callback, :oauth_token => 'faketoken'
88
+ end
89
+
90
+ describe 'building the access token' do
91
+ it 'should rebuild the request token' do
92
+ correct_token = OAuth::RequestToken.new(TwitterAuth.consumer,'faketoken','faketokensecret')
93
+
94
+ %w(token secret).each do |att|
95
+ assigns[:request_token].send(att).should == correct_token.send(att)
96
+ end
97
+ end
98
+
99
+ it 'should exchange the request token for an access token' do
100
+ assigns[:access_token].should be_a(OAuth::AccessToken)
101
+ assigns[:access_token].token.should == 'fakeaccesstoken'
102
+ assigns[:access_token].secret.should == 'fakeaccesstokensecret'
103
+ end
104
+
105
+ it 'should wipe the request token after exchange' do
106
+ session[:request_token].should be_nil
107
+ session[:request_token_secret].should be_nil
108
+ end
109
+ end
110
+
111
+ describe 'identifying the user' do
112
+ it "should find the user" do
113
+ assigns[:user].should == @user
114
+ end
115
+
116
+ it "should assign the user id to the session" do
117
+ session[:user_id].should == @user.id
118
+ end
119
+ end
120
+
121
+ describe "when OAuth doesn't work" do
122
+ before do
123
+ request.session[:request_token] = 'faketoken'
124
+ request.session[:request_token_secret] = 'faketokensecret'
125
+ @request_token = OAuth::RequestToken.new(TwitterAuth.consumer, session[:request_token], session[:request_token_secret])
126
+ OAuth::RequestToken.stub!(:new).and_return(@request_token)
127
+ end
128
+
129
+ it 'should call authentication_failed when it gets a 401 from OAuth' do
130
+ @request_token.stub!(:get_access_token).and_raise(Net::HTTPServerException.new('401 "Unauthorized"', '401 "Unauthorized"'))
131
+ controller.should_receive(:authentication_failed).with('This authentication request is no longer valid. Please try again.')
132
+ # the should raise_error is hacky because of the expectation
133
+ # stubbing the proper behavior :-(
134
+ lambda{get :oauth_callback, :oauth_token => 'faketoken'}.should raise_error(ActionView::MissingTemplate)
135
+ end
136
+
137
+ it 'should call authentication_failed when it gets a different HTTPServerException' do
138
+ @request_token.stub!(:get_access_token).and_raise(Net::HTTPServerException.new('404 "Not Found"', '404 "Not Found"'))
139
+ controller.should_receive(:authentication_failed).with('There was a problem trying to authenticate you. Please try again.')
140
+ lambda{get :oauth_callback, :oauth_token => 'faketoken'}.should raise_error(ActionView::MissingTemplate)
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ describe 'with Basic strategy' do
148
+ before do
149
+ stub_basic!
150
+ end
151
+
152
+ describe '#new' do
153
+ it 'should render the new action' do
154
+ get :new
155
+ response.should render_template('sessions/new')
156
+ end
157
+
158
+ it 'should render the login form' do
159
+ get :new
160
+ response.should have_tag('form[action=/session][id=login_form][method=post]')
161
+ end
162
+
163
+ describe '#create' do
164
+ before do
165
+ @user = Factory.create(:twitter_basic_user)
166
+ end
167
+
168
+ it 'should call logout_keeping_session! to remove session info' do
169
+ controller.should_receive(:logout_keeping_session!)
170
+ post :create
171
+ end
172
+
173
+ it 'should try to authenticate the user' do
174
+ User.should_receive(:authenticate)
175
+ post :create
176
+ end
177
+
178
+ it 'should call authentication_failed on authenticate failure' do
179
+ User.should_receive(:authenticate).and_return(nil)
180
+ post :create, :login => 'wrong', :password => 'false'
181
+ response.should redirect_to('/login')
182
+ end
183
+
184
+ it 'should call authentication_succeeded on authentication success' do
185
+ User.should_receive(:authenticate).and_return(@user)
186
+ post :create, :login => 'twitterman', :password => 'cool'
187
+ response.should redirect_to('/')
188
+ flash[:notice].should_not be_blank
189
+ end
190
+ end
191
+ end
192
+
193
+ end
194
+
195
+ describe '#destroy' do
196
+ it 'should call logout_keeping_session!' do
197
+ controller.should_receive(:logout_keeping_session!).once
198
+ get :destroy
199
+ end
200
+
201
+ it 'should redirect to the root' do
202
+ get :destroy
203
+ response.should redirect_to('/')
204
+ end
205
+ end
206
+ end