pager-restful_open_id_authentication 1.0.20080507

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/README +63 -0
  2. data/Rakefile +22 -0
  3. data/generators/open_id_authenticated/USAGE +1 -0
  4. data/generators/open_id_authenticated/open_id_authenticated_generator.rb +215 -0
  5. data/generators/open_id_authenticated/templates/activation.rhtml +3 -0
  6. data/generators/open_id_authenticated/templates/authenticated_system.rb +120 -0
  7. data/generators/open_id_authenticated/templates/authenticated_test_helper.rb +113 -0
  8. data/generators/open_id_authenticated/templates/controller.rb +94 -0
  9. data/generators/open_id_authenticated/templates/fixtures.yml +17 -0
  10. data/generators/open_id_authenticated/templates/functional_test.rb +85 -0
  11. data/generators/open_id_authenticated/templates/helper.rb +2 -0
  12. data/generators/open_id_authenticated/templates/login.rhtml +20 -0
  13. data/generators/open_id_authenticated/templates/migration.rb +45 -0
  14. data/generators/open_id_authenticated/templates/model.rb +93 -0
  15. data/generators/open_id_authenticated/templates/model_controller.rb +30 -0
  16. data/generators/open_id_authenticated/templates/model_functional_test.rb +72 -0
  17. data/generators/open_id_authenticated/templates/model_helper.rb +2 -0
  18. data/generators/open_id_authenticated/templates/notifier.rb +25 -0
  19. data/generators/open_id_authenticated/templates/notifier_test.rb +31 -0
  20. data/generators/open_id_authenticated/templates/observer.rb +11 -0
  21. data/generators/open_id_authenticated/templates/open_id_form.rhtml +14 -0
  22. data/generators/open_id_authenticated/templates/signup.rhtml +22 -0
  23. data/generators/open_id_authenticated/templates/signup_notification.rhtml +8 -0
  24. data/generators/open_id_authenticated/templates/unit_test.rb +101 -0
  25. data/install.rb +1 -0
  26. data/lib/controller_methods.rb +137 -0
  27. data/lib/open_id_store.rb +69 -0
  28. data/rails/init.rb +15 -0
  29. metadata +81 -0
@@ -0,0 +1,2 @@
1
+ module <%= model_controller_class_name %>Helper
2
+ end
@@ -0,0 +1,25 @@
1
+ class <%= class_name %>Notifier < ActionMailer::Base
2
+ def signup_notification(<%= file_name %>)
3
+ setup_email(<%= file_name %>)
4
+ @subject += 'Please activate your new account'
5
+ <% if options[:include_activation] %>
6
+ @body[:url] = "http://YOURSITE/activate/#{<%= file_name %>.activation_code}"
7
+ <% else %>
8
+ @body[:url] = "http://YOURSITE/login/" <% end %>
9
+ end
10
+
11
+ def activation(<%= file_name %>)
12
+ setup_email(<%= file_name %>)
13
+ @subject += 'Your account has been activated!'
14
+ @body[:url] = "http://YOURSITE/"
15
+ end
16
+
17
+ protected
18
+ def setup_email(<%= file_name %>)
19
+ @recipients = "#{<%= file_name %>.email}"
20
+ @from = "ADMINEMAIL"
21
+ @subject = "[YOURSITE] "
22
+ @sent_on = Time.now
23
+ @body[:<%= file_name %>] = <%= file_name %>
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require '<%= file_name %>_notifier'
3
+
4
+ class <%= class_name %>NotifierTest < Test::Unit::TestCase
5
+ FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
6
+ CHARSET = "utf-8"
7
+
8
+ include ActionMailer::Quoting
9
+
10
+ def setup
11
+ ActionMailer::Base.delivery_method = :test
12
+ ActionMailer::Base.perform_deliveries = true
13
+ ActionMailer::Base.deliveries = []
14
+
15
+ @expected = TMail::Mail.new
16
+ @expected.set_content_type "text", "plain", { "charset" => CHARSET }
17
+ end
18
+
19
+ def test_dummy_test
20
+ #do nothing
21
+ end
22
+
23
+ private
24
+ def read_fixture(action)
25
+ IO.readlines("#{FIXTURES_PATH}/<%= file_name %>_notifier/#{action}")
26
+ end
27
+
28
+ def encode(subject)
29
+ quoted_printable(subject, CHARSET)
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ class <%= class_name %>Observer < ActiveRecord::Observer
2
+ def after_create(<%= file_name %>)
3
+ <%= class_name %>Notifier.deliver_signup_notification(<%= file_name %>)
4
+ end
5
+
6
+ def after_save(<%= file_name %>)
7
+ <% if options[:include_activation] %>
8
+ <%= class_name %>Notifier.deliver_activation(<%= file_name %>) if <%= file_name %>.recently_activated?
9
+ <% end %>
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ <%% form_tag begin_<%= controller_singular_name %>_path do -%>
2
+ <p>
3
+ <label>
4
+ Identity URL:
5
+ <%%= text_field_tag :open_id_url, nil, :style => 'width:250px' %>
6
+ </label>
7
+ <%%= submit_tag :Verify %>
8
+ </p>
9
+ <!-- Uncomment this if you want this functionality
10
+ <p><label for="remember_me">Remember me:</label>
11
+ <%%= check_box_tag 'remember_me' %></p>
12
+ -->
13
+
14
+ <%% end -%>
@@ -0,0 +1,22 @@
1
+ <h2>Signup with OpenID</h2>
2
+
3
+ <%%= render :partial => "<%= controller_file_name %>/open_id_form" %>
4
+
5
+ <h2>or create a <%= class_name %> Profile</h2>
6
+
7
+ <%%= error_messages_for :<%= file_name %> %>
8
+ <%% form_for @<%= file_name %> do |f| -%>
9
+ <p><label for="login">Login</label><br/>
10
+ <%%= f.text_field :login %></p>
11
+
12
+ <p><label for="email">Email</label><br/>
13
+ <%%= f.text_field :email %></p>
14
+
15
+ <p><label for="password">Password</label><br/>
16
+ <%%= f.password_field :password %></p>
17
+
18
+ <p><label for="password_confirmation">Confirm Password</label><br/>
19
+ <%%= f.password_field :password_confirmation %></p>
20
+
21
+ <p><%%= submit_tag 'Sign up' %></p>
22
+ <%% end -%>
@@ -0,0 +1,8 @@
1
+ Your account has been created.
2
+
3
+ Username: <%%= @<%= file_name %>.login %>
4
+ Password: <%%= @<%= file_name %>.password %>
5
+
6
+ Visit this url to activate your account:
7
+
8
+ <%%= @url %>
@@ -0,0 +1,101 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class <%= class_name %>Test < Test::Unit::TestCase
4
+ # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead.
5
+ # Then, you can remove it from this and the functional test.
6
+ include AuthenticatedTestHelper
7
+ fixtures :<%= table_name %>
8
+
9
+ def test_should_create_<%= file_name %>
10
+ assert_difference <%= class_name %>, :count do
11
+ <%= file_name %> = create_<%= file_name %>
12
+ assert !<%= file_name %>.new_record?, "#{<%= file_name %>.errors.full_messages.to_sentence}"
13
+ end
14
+ end
15
+
16
+ def test_should_require_login
17
+ assert_no_difference <%= class_name %>, :count do
18
+ u = create_<%= file_name %>(:login => nil)
19
+ assert u.errors.on(:login)
20
+ end
21
+ end
22
+
23
+ def test_should_require_password
24
+ assert_no_difference <%= class_name %>, :count do
25
+ u = create_<%= file_name %>(:password => nil)
26
+ assert u.errors.on(:password)
27
+ end
28
+ end
29
+
30
+ def test_should_require_password_confirmation
31
+ assert_no_difference <%= class_name %>, :count do
32
+ u = create_<%= file_name %>(:password_confirmation => nil)
33
+ assert u.errors.on(:password_confirmation)
34
+ end
35
+ end
36
+
37
+ def test_should_require_email
38
+ assert_no_difference <%= class_name %>, :count do
39
+ u = create_<%= file_name %>(:email => nil)
40
+ assert u.errors.on(:email)
41
+ end
42
+ end
43
+
44
+ def test_should_reset_password
45
+ <%= table_name %>(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password')
46
+ assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin', 'new password')
47
+ end
48
+
49
+ def test_should_not_rehash_password
50
+ <%= table_name %>(:quentin).update_attributes(:login => 'quentin2')
51
+ assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin2', 'test')
52
+ end
53
+
54
+ def test_should_authenticate_<%= file_name %>
55
+ assert_equal <%= table_name %>(:quentin), <%= class_name %>.authenticate('quentin', 'test')
56
+ end
57
+
58
+ def test_should_set_remember_token
59
+ <%= table_name %>(:quentin).remember_me
60
+ assert_not_nil <%= table_name %>(:quentin).remember_token
61
+ assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
62
+ end
63
+
64
+ def test_should_unset_remember_token
65
+ <%= table_name %>(:quentin).remember_me
66
+ assert_not_nil <%= table_name %>(:quentin).remember_token
67
+ <%= table_name %>(:quentin).forget_me
68
+ assert_nil <%= table_name %>(:quentin).remember_token
69
+ end
70
+
71
+ def test_should_remember_me_for_one_week
72
+ before = 1.week.from_now.utc
73
+ <%= table_name %>(:quentin).remember_me_for 1.week
74
+ after = 1.week.from_now.utc
75
+ assert_not_nil <%= table_name %>(:quentin).remember_token
76
+ assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
77
+ assert <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after)
78
+ end
79
+
80
+ def test_should_remember_me_until_one_week
81
+ time = 1.week.from_now.utc
82
+ <%= table_name %>(:quentin).remember_me_until time
83
+ assert_not_nil <%= table_name %>(:quentin).remember_token
84
+ assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
85
+ assert_equal <%= table_name %>(:quentin).remember_token_expires_at, time
86
+ end
87
+
88
+ def test_should_remember_me_default_two_weeks
89
+ before = 2.weeks.from_now.utc
90
+ <%= table_name %>(:quentin).remember_me
91
+ after = 2.weeks.from_now.utc
92
+ assert_not_nil <%= table_name %>(:quentin).remember_token
93
+ assert_not_nil <%= table_name %>(:quentin).remember_token_expires_at
94
+ assert <%= table_name %>(:quentin).remember_token_expires_at.between?(before, after)
95
+ end
96
+
97
+ protected
98
+ def create_<%= file_name %>(options = {})
99
+ <%= class_name %>.create({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options))
100
+ end
101
+ end
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ puts IO.read(File.join(File.dirname(__FILE__), 'README'))
@@ -0,0 +1,137 @@
1
+ module OpenIdConsumer
2
+ module ControllerMethods
3
+ def self.included(controller)
4
+ controller.class_eval do
5
+ verify :method => :post, :only => :begin, :params => :open_id_url, :redirect_to => { :action => 'index' },
6
+ :add_flash => { :error => "Enter an Identity URL to verify." }
7
+ verify :method => :get, :only => :complete, :redirect_to => { :action => 'index' }
8
+ before_filter :begin_open_id_auth, :only => :begin
9
+ before_filter :complete_open_id_auth, :only => :complete
10
+ attr_reader :open_id_response
11
+ attr_reader :open_id_fields
12
+ cattr_accessor :open_id_consumer_options
13
+ end
14
+ end
15
+
16
+ protected
17
+
18
+ def open_id_consumer
19
+ @open_id_consumer ||= OpenID::Consumer.new(
20
+ session[:open_id_session] ||= {},
21
+ ActiveRecordStore.new)
22
+ end
23
+
24
+ def begin_open_id_auth
25
+ @open_id_response = open_id_consumer.begin(params[:open_id_url])
26
+ def @open_id_response.status; OpenID::Consumer::SUCCESS end
27
+ add_sreg_params!(@open_id_response)# if @open_id_response.status == OpenID::SUCCESS
28
+ rescue OpenID::DiscoveryFailure
29
+ def @open_id_response.status; OpenID::Consumer::FAILURE end
30
+ end
31
+
32
+ def complete_open_id_auth
33
+ return_to = url_for :only_path => false, :action => 'complete'
34
+ parameters = params.reject{|k,v| request.path_parameters[k]}
35
+ @open_id_response = open_id_consumer.complete(parameters, return_to)
36
+ return unless open_id_response.status == OpenID::Consumer::SUCCESS
37
+
38
+ @open_id_fields = open_id_response.extension_response('sreg', true)
39
+ logger.debug "***************** sreg params ***************"
40
+ logger.debug @open_id_fields.inspect
41
+ logger.debug "***************** sreg params ***************"
42
+ end
43
+
44
+
45
+ def authenticate_with_open_id(identity_url)
46
+ @open_id_response = open_id_consumer.begin(identity_url)
47
+ yield(@open_id_response.status.to_sum)
48
+
49
+ # If the URL was unusable (either because of network conditions, a server error,
50
+ # or that the response returned was not an OpenID identity page), the library
51
+ # will return HTTP_FAILURE or PARSE_ERROR. Let the user know that the URL is unusable.
52
+ case open_id_response.status
53
+ when OpenID::Consumer::SUCCESS
54
+ add_sreg_params!(@open_id_response)
55
+ redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), complete_session_url)
56
+ else
57
+ flash[:error] = "Unable to find OpenID server for <q>#{params[:open_id_url]}</q>"
58
+ render :action => :new
59
+ end
60
+ end
61
+
62
+ def complete
63
+ case open_id_response.status
64
+ when OpenID::Consumer::FAILURE
65
+ # In the case of failure, if info is non-nil, it is the URL that we were verifying.
66
+ # We include it in the error message to help the user figure out what happened.
67
+ flash[:notice] = if open_id_response.identity_url
68
+ "Verification of #{open_id_response.identity_url} failed. "
69
+ else
70
+ "Verification failed. "
71
+ end
72
+ flash[:notice] += open_id_response.msg.to_s
73
+ when OpenID::Consumer::SUCCESS
74
+ # Success means that the transaction completed without error. If info is nil,
75
+ # it means that the user cancelled the verification.
76
+ flash[:notice] = "You have successfully verified #{open_id_response.identity_url} as your identity."
77
+ if open_id_fields.any?
78
+ @user = User.find_by_open_id_url(open_id_response.identity_url)
79
+ @user ||= User.new(:open_id_url => open_id_response.identity_url)
80
+ @user.login = open_id_fields['nickname'] if open_id_fields['nickname']
81
+ @user.email = open_id_fields['email'] if open_id_fields['email']
82
+ if @user.save
83
+ self.current_user = @user
84
+ if params[:remember_me] == "1"
85
+ self.current_user.remember_me
86
+ cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
87
+ end
88
+ flash[:notice] = "You have successfully verified #{open_id_response.identity_url} as your identity."
89
+ return redirect_back_or_default('/')
90
+ else
91
+ flash[:notice] = @user.errors.full_messages.join('<br />')
92
+ render :action => 'new' and return
93
+ end
94
+ end
95
+ when OpenID::CANCEL
96
+ flash[:notice] = "Verification cancelled."
97
+ else
98
+ flash[:notice] = "Unknown response status: #{open_id_response.status}"
99
+ end
100
+ redirect_to :action => 'new'
101
+ end
102
+
103
+
104
+ def authenticate_with_open_id(identity_url)
105
+
106
+
107
+ case status
108
+ when :missing
109
+ failed_authentication "Sorry, the OpenID server couldn't be found"
110
+
111
+ when :canceled
112
+ failed_authentication "OpenID verification was canceled"
113
+
114
+ when :failed
115
+ failed_authentication "Sorry, the OpenID verification failed"
116
+
117
+ when :successful
118
+ if @current_user =
119
+ @account.users.find_by_identity_url(identity_url)
120
+ successful_authentication
121
+ else
122
+ failed_authentication "Sorry, no user by that identity URL exists"
123
+ end
124
+ end
125
+ end
126
+
127
+
128
+
129
+ def add_sreg_params!(openid_response)
130
+ open_id_consumer_options.keys.inject({}) do |params, key|
131
+ value = open_id_consumer_options[key]
132
+ value = value.collect { |v| v.to_s.strip } * ',' if value.respond_to?(:collect)
133
+ openid_response.add_extension_arg('sreg', key.to_s, value.to_s)
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,69 @@
1
+ require 'openid/store/interface'
2
+
3
+ class ActiveRecordStore < OpenID::Store::Interface
4
+ def store_association(server_url, assoc)
5
+ remove_association(server_url, assoc.handle)
6
+ Association.create(:server_url => server_url,
7
+ :handle => assoc.handle,
8
+ :secret => assoc.secret,
9
+ :issued => assoc.issued,
10
+ :lifetime => assoc.lifetime,
11
+ :assoc_type => assoc.assoc_type)
12
+ end
13
+
14
+ def get_association(server_url, handle=nil)
15
+ assocs = if handle.blank?
16
+ Association.find_all_by_server_url(server_url)
17
+ else
18
+ Association.find_all_by_server_url_and_handle(server_url, handle)
19
+ end
20
+
21
+ assocs.reverse.each do |assoc|
22
+ a = assoc.from_record
23
+ if a.expires_in == 0
24
+ assoc.destroy
25
+ else
26
+ return a
27
+ end
28
+ end if assocs.any?
29
+
30
+ return nil
31
+ end
32
+
33
+ def remove_association(server_url, handle)
34
+ Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0
35
+ end
36
+
37
+ def use_nonce(server_url, timestamp, salt)
38
+ return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt)
39
+ return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew
40
+ Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt)
41
+ return true
42
+ end
43
+
44
+ def cleanup_nonces
45
+ now = Time.now.to_i
46
+ Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew])
47
+ end
48
+
49
+ def cleanup_associations
50
+ now = Time.now.to_i
51
+ Association.delete_all(['issued + lifetime > ?',now])
52
+ end
53
+ end
54
+
55
+ class Setting < ActiveRecord::Base
56
+ set_table_name 'open_id_settings'
57
+ validates_uniqueness_of :setting
58
+ end
59
+
60
+ class Nonce < ActiveRecord::Base
61
+ set_table_name 'open_id_nonces'
62
+ end
63
+
64
+ class Association < ActiveRecord::Base
65
+ set_table_name 'open_id_associations'
66
+ def from_record
67
+ OpenID::Association.new(handle, secret, issued, lifetime, assoc_type)
68
+ end
69
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,15 @@
1
+ begin
2
+ gem 'ruby-openid'
3
+ require 'openid'
4
+ rescue LoadError
5
+ puts "Install the ruby-openid gem to enable OpenID support"
6
+ end
7
+ require 'open_id_store'
8
+ require 'controller_methods'
9
+
10
+ class << ActionController::Base
11
+ def open_id_consumer(options = {})
12
+ include OpenIdConsumer::ControllerMethods
13
+ self.open_id_consumer_options = options
14
+ end
15
+ end