mbleigh-twitter-auth 0.1.8 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +4 -0
- data/VERSION.yml +1 -1
- data/app/controllers/sessions_controller.rb +2 -0
- data/app/models/twitter_auth/generic_user.rb +23 -2
- data/generators/twitter_auth/templates/migration.rb +3 -0
- data/generators/twitter_auth/templates/twitter_auth.yml +12 -6
- data/lib/twitter_auth/controller_extensions.rb +2 -1
- data/lib/twitter_auth.rb +4 -0
- data/spec/controllers/controller_extensions_spec.rb +25 -9
- data/spec/controllers/sessions_controller_spec.rb +15 -0
- data/spec/models/twitter_auth/generic_user_spec.rb +86 -1
- data/spec/schema.rb +4 -0
- data/spec/twitter_auth_spec.rb +13 -1
- metadata +1 -1
data/README.markdown
CHANGED
@@ -76,6 +76,10 @@ TwitterAuth provides some default controller methods that may be overridden in y
|
|
76
76
|
* `authentication_succeeded(message=default)`: called when Twitter authorization has completed successfully. By default, simply redirects to the site root and sets the `flash[:notice]`.
|
77
77
|
* `access_denied`: what happens when the `login_required` before filter fails. By default it stores the current location to return to and redirects to the login process.
|
78
78
|
|
79
|
+
Resources
|
80
|
+
---------
|
81
|
+
|
82
|
+
* **Bug Reports:** See the [Lighthouse Project](http://mbleigh.lighthouseapp.com/projects/27783-twitterauth) to report any problems you have using TwitterAuth.
|
79
83
|
|
80
84
|
Copyright
|
81
85
|
---------
|
data/VERSION.yml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module TwitterAuth
|
2
2
|
class GenericUser < ActiveRecord::Base
|
3
|
-
attr_protected :login
|
4
|
-
|
3
|
+
attr_protected :login, :remember_token, :remember_token_expires_at
|
4
|
+
|
5
5
|
TWITTER_ATTRIBUTES = [
|
6
6
|
:name,
|
7
7
|
:location,
|
@@ -26,6 +26,7 @@ module TwitterAuth
|
|
26
26
|
validates_format_of :login, :with => /\A[a-z0-9_]+\z/i
|
27
27
|
validates_length_of :login, :in => 1..15
|
28
28
|
validates_uniqueness_of :login, :case_sensitive => false
|
29
|
+
validates_uniqueness_of :remember_token, :allow_blank => true
|
29
30
|
|
30
31
|
def self.table_name; 'users' end
|
31
32
|
|
@@ -41,6 +42,10 @@ module TwitterAuth
|
|
41
42
|
|
42
43
|
user
|
43
44
|
end
|
45
|
+
|
46
|
+
def self.from_remember_token(token)
|
47
|
+
first(:conditions => ["remember_token = ? AND remember_token_expires_at > ?", token, Time.now])
|
48
|
+
end
|
44
49
|
|
45
50
|
def assign_twitter_attributes(hash)
|
46
51
|
TWITTER_ATTRIBUTES.each do |att|
|
@@ -66,5 +71,21 @@ module TwitterAuth
|
|
66
71
|
TwitterAuth::Dispatcher::Basic.new(self)
|
67
72
|
end
|
68
73
|
end
|
74
|
+
|
75
|
+
def remember_me
|
76
|
+
return false unless respond_to?(:remember_token)
|
77
|
+
|
78
|
+
self.remember_token = ActiveSupport::SecureRandom.hex(10)
|
79
|
+
self.remember_token_expires_at = Time.now + TwitterAuth.remember_for.days
|
80
|
+
|
81
|
+
save
|
82
|
+
|
83
|
+
{:value => self.remember_token, :expires => self.remember_token_expires_at}
|
84
|
+
end
|
85
|
+
|
86
|
+
def forget_me
|
87
|
+
self.remember_token = self.remember_token_expires_at = nil
|
88
|
+
self.save
|
89
|
+
end
|
69
90
|
end
|
70
91
|
end
|
@@ -10,6 +10,9 @@ class TwitterAuthMigration < ActiveRecord::Migration
|
|
10
10
|
t.string :salt
|
11
11
|
<% end -%>
|
12
12
|
|
13
|
+
t.string :remember_token
|
14
|
+
t.datetime :remember_token_expires_at
|
15
|
+
|
13
16
|
# This information is automatically kept
|
14
17
|
# in-sync at each login of the user. You
|
15
18
|
# may remove any/all of these columns.
|
@@ -1,24 +1,27 @@
|
|
1
1
|
<% if options[:oauth] -%>
|
2
2
|
development:
|
3
3
|
strategy: oauth
|
4
|
-
base_url: "https://twitter.com"
|
5
|
-
api_timeout: 10
|
6
4
|
oauth_consumer_key: devkey
|
7
5
|
oauth_consumer_secret: devsecret
|
6
|
+
base_url: "https://twitter.com"
|
7
|
+
api_timeout: 10
|
8
|
+
remember_for: 14 # days
|
8
9
|
oauth_callback: "http://localhost:3000/oauth_callback"
|
9
10
|
test:
|
10
11
|
strategy: oauth
|
11
|
-
base_url: "https://twitter.com"
|
12
|
-
api_timeout: 10
|
13
12
|
oauth_consumer_key: testkey
|
14
13
|
oauth_consumer_secret: testsecret
|
14
|
+
base_url: "https://twitter.com"
|
15
|
+
api_timeout: 10
|
16
|
+
remember_for: 14 # days
|
15
17
|
oauth_callback: "http://localhost:3000/oauth_callback"
|
16
18
|
production:
|
17
19
|
strategy: oauth
|
18
|
-
api_timeout: 10
|
19
|
-
base_url: "https://twitter.com"
|
20
20
|
oauth_consumer_key: prodkey
|
21
21
|
oauth_consumer_secret: prodsecret
|
22
|
+
base_url: "https://twitter.com"
|
23
|
+
api_timeout: 10
|
24
|
+
remember_for: 14 # days
|
22
25
|
<% else -%>
|
23
26
|
development:
|
24
27
|
strategy: basic
|
@@ -26,13 +29,16 @@ development:
|
|
26
29
|
base_url: "https://twitter.com"
|
27
30
|
# randomly generated key for encrypting Twitter passwords
|
28
31
|
encryption_key: "<%= key = ActiveSupport::SecureRandom.hex(12) %>"
|
32
|
+
remember_for: 14 # days
|
29
33
|
test:
|
30
34
|
strategy: basic
|
31
35
|
api_timeout: 10
|
32
36
|
base_url: "https://twitter.com"
|
33
37
|
encryption_key: "<%= key %>"
|
38
|
+
remember_for: 14 # days
|
34
39
|
production:
|
35
40
|
strategy: basic
|
36
41
|
api_timeout: 10
|
37
42
|
encryption_key: "<%= key %>"
|
43
|
+
remember_for: 14 # days
|
38
44
|
<% end %>
|
@@ -20,7 +20,7 @@ module TwitterAuth
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def current_user
|
23
|
-
@current_user ||= User.find_by_id(session[:user_id])
|
23
|
+
@current_user ||= User.find_by_id(session[:user_id]) || User.from_remember_token(cookies[:remember_token])
|
24
24
|
end
|
25
25
|
|
26
26
|
def current_user=(new_user)
|
@@ -57,6 +57,7 @@ module TwitterAuth
|
|
57
57
|
def logout_keeping_session!
|
58
58
|
@current_user = nil
|
59
59
|
session[:user_id] = nil
|
60
|
+
cookies.delete(:remember_token)
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
data/lib/twitter_auth.rb
CHANGED
@@ -27,6 +27,10 @@ module TwitterAuth
|
|
27
27
|
config['oauth_callback']
|
28
28
|
end
|
29
29
|
|
30
|
+
def self.remember_for
|
31
|
+
(config['remember_for'] || 14).to_i
|
32
|
+
end
|
33
|
+
|
30
34
|
# The authentication strategy employed by this
|
31
35
|
# application. Set in +config/twitter.yml+ as
|
32
36
|
# strategy; valid options are oauth or basic.
|
@@ -35,9 +35,18 @@ class TwitterAuthTestController < ApplicationController
|
|
35
35
|
logout_keeping_session!
|
36
36
|
redirect_back_or_default('/')
|
37
37
|
end
|
38
|
+
|
39
|
+
def current_user_action
|
40
|
+
@user = current_user
|
41
|
+
render :nothing => true
|
42
|
+
end
|
38
43
|
end
|
39
44
|
|
40
45
|
describe TwitterAuthTestController do
|
46
|
+
before do
|
47
|
+
controller.stub!(:cookies).and_return({})
|
48
|
+
end
|
49
|
+
|
41
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|
|
42
51
|
it "should respond to the extension method '#{m}'" do
|
43
52
|
controller.should respond_to(m)
|
@@ -72,19 +81,21 @@ describe TwitterAuthTestController do
|
|
72
81
|
it 'should find the user based on the session user_id' do
|
73
82
|
user = Factory.create(:twitter_oauth_user)
|
74
83
|
request.session[:user_id] = user.id
|
75
|
-
|
84
|
+
get(:current_user_action)
|
85
|
+
assigns[:user].should == user
|
76
86
|
end
|
77
87
|
|
78
|
-
it 'should
|
79
|
-
|
80
|
-
controller.
|
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
|
81
93
|
end
|
82
94
|
|
83
|
-
it 'should
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
controller.send(:current_user).should == user
|
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
|
88
99
|
end
|
89
100
|
end
|
90
101
|
|
@@ -142,5 +153,10 @@ describe TwitterAuthTestController do
|
|
142
153
|
get :logout_keeping_session_action
|
143
154
|
controller.send(:current_user).should be_nil
|
144
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
|
145
161
|
end
|
146
162
|
end
|
@@ -82,6 +82,12 @@ describe SessionsController do
|
|
82
82
|
describe 'with proper info' do
|
83
83
|
before do
|
84
84
|
@user = Factory.create(:twitter_oauth_user)
|
85
|
+
@time = Time.now
|
86
|
+
@remember_token = ActiveSupport::SecureRandom.hex(10)
|
87
|
+
|
88
|
+
Time.stub!(:now).and_return(@time)
|
89
|
+
ActiveSupport::SecureRandom.stub!(:hex).and_return(@remember_token)
|
90
|
+
|
85
91
|
request.session[:request_token] = 'faketoken'
|
86
92
|
request.session[:request_token_secret] = 'faketokensecret'
|
87
93
|
get :oauth_callback, :oauth_token => 'faketoken'
|
@@ -116,6 +122,15 @@ describe SessionsController do
|
|
116
122
|
it "should assign the user id to the session" do
|
117
123
|
session[:user_id].should == @user.id
|
118
124
|
end
|
125
|
+
|
126
|
+
it "should call remember me" do
|
127
|
+
@user.reload
|
128
|
+
@user.remember_token.should == @remember_token
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should set a cookie" do
|
132
|
+
cookies[:remember_token].should == @remember_token
|
133
|
+
end
|
119
134
|
end
|
120
135
|
|
121
136
|
describe "when OAuth doesn't work" do
|
@@ -5,12 +5,17 @@ describe TwitterAuth::GenericUser do
|
|
5
5
|
should_validate_format_of :login, 'some_guy', 'awesome', 'cool_man'
|
6
6
|
should_not_validate_format_of :login, 'with-dashes', 'with.periods', 'with spaces'
|
7
7
|
should_validate_length_of :login, :in => 1..15
|
8
|
-
|
8
|
+
|
9
9
|
it 'should validate uniqueness of login' do
|
10
10
|
Factory.create(:twitter_oauth_user)
|
11
11
|
Factory.build(:twitter_oauth_user).should have_at_least(1).errors_on(:login)
|
12
12
|
end
|
13
13
|
|
14
|
+
it 'should validate uniqueness of remember_token' do
|
15
|
+
Factory.create(:twitter_oauth_user, :remember_token => 'abc')
|
16
|
+
Factory.build(:twitter_oauth_user, :remember_token => 'abc').should have_at_least(1).errors_on(:remember_token)
|
17
|
+
end
|
18
|
+
|
14
19
|
it 'should allow capital letters in the username' do
|
15
20
|
Factory.build(:twitter_oauth_user, :login => 'TwitterMan').should have(:no).errors_on(:login)
|
16
21
|
end
|
@@ -54,4 +59,84 @@ describe TwitterAuth::GenericUser do
|
|
54
59
|
lambda{user.update_twitter_attributes({'name' => 'Twitter Man', 'description' => 'Works.', 'whoopsy' => 'noworks.'})}.should_not raise_error
|
55
60
|
end
|
56
61
|
end
|
62
|
+
|
63
|
+
describe '#remember_me' do
|
64
|
+
before do
|
65
|
+
@user = Factory(:twitter_oauth_user)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should check for the remember_token column' do
|
69
|
+
@user.should_receive(:respond_to?).with(:remember_token).and_return(false)
|
70
|
+
@user.remember_me
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should return nil if there is no remember_token column' do
|
74
|
+
@user.should_receive(:respond_to?).with(:remember_token).and_return(false)
|
75
|
+
@user.remember_me.should be_false
|
76
|
+
end
|
77
|
+
|
78
|
+
describe ' with proper columns' do
|
79
|
+
it 'should generate a secure random token' do
|
80
|
+
ActiveSupport::SecureRandom.should_receive(:hex).with(10).and_return('abcdef')
|
81
|
+
@user.remember_me
|
82
|
+
@user.remember_token.should == 'abcdef'
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should set the expiration to the current time plus the remember_for period' do
|
86
|
+
TwitterAuth.stub!(:remember_for).and_return(10)
|
87
|
+
time = Time.now
|
88
|
+
Time.stub!(:now).and_return(time)
|
89
|
+
|
90
|
+
@user.remember_me
|
91
|
+
|
92
|
+
@user.remember_token_expires_at.should == Time.now + 10.days
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should return a hash with a :value and :expires key' do
|
96
|
+
result = @user.remember_me
|
97
|
+
result.should be_a(Hash)
|
98
|
+
result.key?(:value).should be_true
|
99
|
+
result.key?(:expires).should be_true
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should return a hash with appropriate values' do
|
103
|
+
TwitterAuth.stub!(:remember_for).and_return(10)
|
104
|
+
time = Time.now
|
105
|
+
Time.stub!(:now).and_return(time)
|
106
|
+
ActiveSupport::SecureRandom.stub!(:hex).and_return('abcdef')
|
107
|
+
|
108
|
+
@user.remember_me.should == {:value => 'abcdef', :expires => (Time.now + 10.days)}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#forget_me' do
|
114
|
+
it 'should reset remember_token and remember_token_expires_at' do
|
115
|
+
@user = Factory(:twitter_oauth_user, :remember_token => "abcdef", :remember_token_expires_at => Time.now + 10.days)
|
116
|
+
@user.forget_me
|
117
|
+
@user.reload
|
118
|
+
@user.remember_token.should be_nil
|
119
|
+
@user.remember_token_expires_at.should be_nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '.from_remember_token' do
|
124
|
+
before do
|
125
|
+
@user = Factory(:twitter_oauth_user, :remember_token => 'abcdef', :remember_token_expires_at => (Time.now + 10.days))
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should find the user with the specified remember_token' do
|
129
|
+
User.from_remember_token('abcdef').should == @user
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should not find a user with an expired token' do
|
133
|
+
user2 = Factory(:twitter_oauth_user, :login => 'walker', :remember_token => 'ghijkl', :remember_token_expires_at => (Time.now - 10.days))
|
134
|
+
User.from_remember_token('ghijkl').should be_nil
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'should not find a user with a nil token and an expiration' do
|
138
|
+
user = Factory(:twitter_oauth_user, :login => 'stranger', :remember_token => nil, :remember_token_expires_at => (Time.now + 10.days))
|
139
|
+
User.from_remember_token(nil).should be_nil
|
140
|
+
end
|
141
|
+
end
|
57
142
|
end
|
data/spec/schema.rb
CHANGED
@@ -10,6 +10,10 @@ ActiveRecord::Schema.define :version => 0 do
|
|
10
10
|
t.binary :crypted_password
|
11
11
|
t.string :salt
|
12
12
|
|
13
|
+
# Remember token fields
|
14
|
+
t.string :remember_token
|
15
|
+
t.datetime :remember_token_expires_at
|
16
|
+
|
13
17
|
# This information is automatically kept
|
14
18
|
# in-sync at each login of the user. You
|
15
19
|
# may remove any/all of these columns.
|
data/spec/twitter_auth_spec.rb
CHANGED
@@ -13,7 +13,7 @@ describe TwitterAuth do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
describe '
|
16
|
+
describe '.api_timeout' do
|
17
17
|
it 'should default to 10' do
|
18
18
|
TwitterAuth.stub!(:config).and_return({})
|
19
19
|
TwitterAuth.api_timeout.should == 10
|
@@ -25,6 +25,18 @@ describe TwitterAuth do
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
describe '.remember_for' do
|
29
|
+
it 'should default to 14' do
|
30
|
+
TwitterAuth.stub!(:config).and_return({})
|
31
|
+
TwitterAuth.remember_for.should == 14
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should be settable via config' do
|
35
|
+
TwitterAuth.stub!(:config).and_return({'remember_for' => '7'})
|
36
|
+
TwitterAuth.remember_for.should == 7
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
28
40
|
describe '.net' do
|
29
41
|
before do
|
30
42
|
stub_basic!
|