mbleigh-twitter-auth 0.0.2 → 0.1.1

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.
@@ -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