authlogic_rpx 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/CHANGELOG.rdoc +10 -0
  2. data/Manifest +19 -2
  3. data/README.rdoc +284 -72
  4. data/Rakefile +30 -2
  5. data/authlogic_rpx.gemspec +11 -11
  6. data/generators/add_authlogic_rpx_migration/USAGE +18 -0
  7. data/generators/add_authlogic_rpx_migration/add_authlogic_rpx_migration_generator.rb +44 -0
  8. data/generators/add_authlogic_rpx_migration/templates/migration_internal_mapping.rb +34 -0
  9. data/generators/add_authlogic_rpx_migration/templates/migration_no_mapping.rb +29 -0
  10. data/lib/authlogic_rpx.rb +1 -0
  11. data/lib/authlogic_rpx/acts_as_authentic.rb +199 -32
  12. data/lib/authlogic_rpx/helper.rb +21 -13
  13. data/lib/authlogic_rpx/rpx_identifier.rb +5 -0
  14. data/lib/authlogic_rpx/session.rb +23 -16
  15. data/lib/authlogic_rpx/version.rb +2 -2
  16. data/test/fixtures/rpxresponses.yml +20 -0
  17. data/test/fixtures/users.yml +20 -5
  18. data/test/integration/basic_authentication_and_registration_test.rb +53 -0
  19. data/test/integration/internal_mapping/basic_authentication_and_registration_test.rb +3 -0
  20. data/test/integration/internal_mapping/settings_test.rb +10 -0
  21. data/test/integration/no_mapping/basic_authentication_and_registration_test.rb +3 -0
  22. data/test/integration/no_mapping/settings_test.rb +10 -0
  23. data/test/libs/ext_test_unit.rb +30 -0
  24. data/test/libs/mock_rpx_now.rb +34 -0
  25. data/test/libs/rails_trickery.rb +2 -2
  26. data/test/libs/rpxresponse.rb +3 -0
  27. data/test/libs/user_session.rb +1 -1
  28. data/test/test_helper.rb +35 -21
  29. data/test/test_internal_mapping_helper.rb +95 -0
  30. data/test/unit/acts_as_authentic_settings_test.rb +42 -0
  31. data/test/unit/session_settings_test.rb +38 -0
  32. data/test/unit/session_validation_test.rb +16 -0
  33. data/test/unit/verify_rpx_mock_test.rb +29 -0
  34. metadata +34 -8
  35. data/test/acts_as_authentic_test.rb +0 -5
  36. data/test/session_test.rb +0 -10
@@ -22,20 +22,28 @@ module AuthlogicRpx
22
22
  # * <tt>add_rpx:</tt> if true, requests RPX callback to add to current session. Else runs normal authentication process (default)
23
23
  # * <tt>unobtrusive:</tt> true/false; sets javascript style for link. Default: true
24
24
  #
25
- # NB: i18n considerations? supports a :language parameter (not tested)
25
+ # The options hash may include other options as supported by rpx_now (see http://github.com/grosser/rpx_now)
26
+ #
26
27
  def rpx_popup(options = {})
27
- params = (
28
- { :authenticity_token => form_authenticity_token, :add_rpx => options[:add_rpx] }.collect { |n| "#{n[0]}=#{ u(n[1]) }" if n[1] }
29
- ).compact.join('&')
30
- unobtrusive = options[:unobtrusive].nil? ? true : options[:unobtrusive]
31
- return_url = options[:return_url] + '?' + params
32
- return_url = u( return_url ) if unobtrusive # double-encoding required only if unobtrusive mode used
33
- RPXNow.popup_code(
34
- options[:link_text],
35
- options[:app_name],
36
- return_url,
37
- :unobtrusive=>unobtrusive
38
- )
28
+ options = { :unobtrusive => true, :add_rpx => false }.merge( options )
29
+ unobtrusive = options[:unobtrusive]
30
+ add_rpx = options.delete( :add_rpx )
31
+ app_name = options.delete( :app_name )
32
+ link_text = options.delete( :link_text )
33
+ return_url = options.delete( :return_url ) + '?' + (
34
+ { :authenticity_token => form_authenticity_token, :add_rpx => add_rpx }.collect { |n| "#{n[0]}=#{ u(n[1]) }" if n[1] }
35
+ ).compact.join('&')
36
+
37
+ # as of rpx_now 0.6.11, there is still an issue with url-encoding of the return path containing additional parameters
38
+ # (as we are using here to get the form_authenticity_token returned.
39
+ # To get around this, we need to ensure hrefs are url-encoded,
40
+ # while the link provided to the rpx_now javascript popup should _not_ be url-encoded
41
+ if unobtrusive
42
+ RPXNow.popup_code( link_text, app_name, u( return_url ), options )
43
+ else
44
+ RPXNow.popup_code( link_text, app_name, u( return_url ), options.merge( :unobtrusive => true ) ) +
45
+ RPXNow.popup_source(app_name, return_url, options )
46
+ end
39
47
  end
40
48
 
41
49
  end
@@ -0,0 +1,5 @@
1
+ class RPXIdentifier < ActiveRecord::Base
2
+ validates_presence_of :identifier
3
+ validates_uniqueness_of :identifier
4
+ validates_presence_of :user_id
5
+ end
@@ -10,7 +10,7 @@ module AuthlogicRpx
10
10
  end
11
11
 
12
12
  module Config
13
-
13
+
14
14
  def find_by_rpx_identifier_method(value = nil)
15
15
  rw_config(:find_by_rpx_identifier_method, value, :find_by_rpx_identifier)
16
16
  end
@@ -34,7 +34,7 @@ module AuthlogicRpx
34
34
  rpx_key_value(value)
35
35
  end
36
36
  def rpx_key_value(value=nil)
37
- if ! inheritable_attributes.include?(:rpx_key)
37
+ if !inheritable_attributes.include?(:rpx_key)
38
38
  RPXNow.api_key = value
39
39
  end
40
40
  rw_config(:rpx_key,value,false)
@@ -61,7 +61,6 @@ module AuthlogicRpx
61
61
  def self.included(klass)
62
62
  klass.class_eval do
63
63
  attr_accessor :new_registration
64
- attr_accessor :rpx_identifier
65
64
  after_persisting :add_rpx_identifier, :if => :adding_rpx_identifier?
66
65
  validate :validate_by_rpx, :if => :authenticating_with_rpx?
67
66
  end
@@ -71,7 +70,7 @@ module AuthlogicRpx
71
70
  # For use in the session controller to help direct the most appropriate action to follow.
72
71
  #
73
72
  def new_registration?
74
- new_registration
73
+ new_registration || !new_registration.nil?
75
74
  end
76
75
 
77
76
  # Determines if the authenticated user has a complete registration (no validation errors)
@@ -88,8 +87,8 @@ module AuthlogicRpx
88
87
  controller.params[:token] && !controller.params[:add_rpx]
89
88
  end
90
89
 
91
- # hook instance finder method to class
92
- #
90
+ # hook instance finder method to class
91
+ #
93
92
  def find_by_rpx_identifier_method
94
93
  self.class.find_by_rpx_identifier_method
95
94
  end
@@ -134,35 +133,43 @@ module AuthlogicRpx
134
133
  # to determine the most appropriate action
135
134
  #
136
135
  def validate_by_rpx
137
- @rpx_data = RPXNow.user_data(controller.params[:token], :extended=> rpx_extended_info? ) {|raw| raw }
136
+ @rpx_data = RPXNow.user_data(
137
+ controller.params[:token],
138
+ :extended => rpx_extended_info?) { |raw| raw }
139
+
138
140
  # If we don't have a valid sign-in, give-up at this point
139
- if @rpx_data.nil?
141
+ if @rpx_data.nil? || @rpx_data['profile'].nil?
140
142
  errors.add_to_base("Authentication failed. Please try again.")
141
143
  return false
142
144
  end
145
+
143
146
  rpx_id = @rpx_data['profile']['identifier']
147
+ rpx_provider_name = @rpx_data['profile']['providerName']
144
148
  if rpx_id.blank?
145
149
  errors.add_to_base("Authentication failed. Please try again.")
146
150
  return false
147
- end
151
+ end
148
152
 
149
153
  self.attempted_record = klass.send(find_by_rpx_identifier_method, rpx_id)
150
154
 
151
- # so what do we do if we can't find an existing user matching the RPX authentication..
155
+ # so what do we do if we can't find an existing user matching the RPX authentication...
152
156
  if !attempted_record
153
- if auto_register?
154
- self.attempted_record = klass.new( :rpx_identifier=> rpx_id )
157
+ if auto_register?
158
+ self.attempted_record = klass.new()
155
159
  map_rpx_data
156
- # save the new user record - without session maintenance else we get caught in a self-referential hell,
157
- # since both session and user objects invoke each other upon save
158
- self.new_registration=true
160
+
161
+ # save the new user record - without session maintenance else we
162
+ # get caught in a self-referential hell, since both session and
163
+ # user objects invoke each other upon save
164
+ self.new_registration = true
165
+ self.attempted_record.add_rpx_identifier( rpx_id, rpx_provider_name)
159
166
  self.attempted_record.save_without_session_maintenance
160
167
  else
161
168
  errors.add_to_base("We did not find any accounts with that login. Enter your details and create an account.")
162
169
  return false
163
170
  end
164
171
  else
165
- map_rpx_data_each_login
172
+ map_rpx_data_each_login
166
173
  end
167
174
 
168
175
  end
@@ -40,8 +40,8 @@ module AuthlogicRpx
40
40
  end
41
41
 
42
42
  MAJOR = 1
43
- MINOR = 0
44
- TINY = 4
43
+ MINOR = 1
44
+ TINY = 0
45
45
 
46
46
  # The current version as a Version instance
47
47
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -0,0 +1,20 @@
1
+ valid_rpx_auth_user_one:
2
+ identifier : http://provider.one/valid_rpx_auth_user_one
3
+ provider_name: provider.one
4
+ username: valid_rpx_auth_user_one
5
+ verified_email: valid_rpx_auth_user_one@provider.one
6
+ display_name: valid rpx auth user one
7
+
8
+ valid_rpx_auth_user_two:
9
+ identifier : http://provider.one/valid_rpx_auth_user_two
10
+ provider_name: provider.one
11
+ username: valid_rpx_auth_user_two
12
+ verified_email: valid_rpx_auth_user_two@provider.one
13
+ display_name: valid rpx auth user two
14
+
15
+ unregistered_rpx_auth_user_one:
16
+ identifier : http://provider.one/unregistered_rpx_auth_user_one
17
+ provider_name: provider.one
18
+ username: unregistered_rpx_auth_user_one
19
+ verified_email: unregistered_rpx_auth_user_one@provider.one
20
+ display_name: unregistered rpx auth user one
@@ -1,5 +1,20 @@
1
- john:
2
- persistence_token: 6cde0674657a8a313ce952df979de2830309aa4c11ca65805dd00bfdc65dbcc2f5e36718660a1d2e68c1a08c276d996763985d2f06fd3d076eb7bc4d97b1e317
3
- single_access_token: <%= Authlogic::Random.friendly_token %>
4
- perishable_token: <%= Authlogic::Random.friendly_token %>
5
- rpx_identifier : johns_rpx_identifier
1
+ valid_rpx_auth_user_one:
2
+ login: valid_rpx_auth_user_one
3
+ email: valid_rpx_auth_user_one@provider.one
4
+ persistence_token: 6cde0674657a8a313ce952df979de2830309aa4c11ca65805dd00bfdc65dbcc2f5e36718660a1d2e68c1a08c276d996763985d2f06fd3d076eb7bc4d97b1e317
5
+ single_access_token: <%= Authlogic::Random.friendly_token %>
6
+ perishable_token: <%= Authlogic::Random.friendly_token %>
7
+ rpx_identifier : http://provider.one/valid_rpx_auth_user_one
8
+
9
+ valid_rpx_auth_user_two:
10
+ login: valid_rpx_auth_user_two
11
+ email: valid_rpx_auth_user_two@provider.one
12
+ persistence_token: 6cde0674657a8a313ce952df979de2830309aa4c11ca65805dd00bfdc65dbcc2f5e36718660a1d2e68c1a08c276d996763985d2f06fd3d076eb7bc4d97b1e317
13
+ single_access_token: <%= Authlogic::Random.friendly_token %>
14
+ perishable_token: <%= Authlogic::Random.friendly_token %>
15
+ rpx_identifier : http://provider.one/valid_rpx_auth_user_two
16
+
17
+ invalid_rpx_auth_user_one:
18
+ login: invalid_rpx_auth_user_one
19
+
20
+
@@ -0,0 +1,53 @@
1
+ # requires test_helper to be loaded first
2
+
3
+ class BasicAuthenticationAndRegistrationTest < ActiveSupport::TestCase
4
+
5
+ must "authenticate valid existing user" do
6
+ test_user = users(:valid_rpx_auth_user_one)
7
+ controller.params[:token] = test_user.login
8
+ session = UserSession.new
9
+ assert_true session.save, "should be a valid session"
10
+ assert_false session.new_registration?, "should not be a new registration"
11
+ assert_true session.registration_complete?, "registration should be complete"
12
+ assert_equal test_user, session.record
13
+ end
14
+
15
+ must "do not authenticate invalidate non-existent user" do
16
+ controller.params[:token] = ''
17
+ session = UserSession.new
18
+ assert_false session.save, "should not be a valid session"
19
+ end
20
+
21
+
22
+ must "auto-register an unregistered user" do
23
+ # enforce Authlogic settings required for test
24
+ UserSession.auto_register true
25
+ User.account_merge_enabled false
26
+ User.account_mapping_mode :none
27
+
28
+ # get response template. set the controller token (used by RPX mock to match mock response)
29
+ test_user = rpxresponses(:unregistered_rpx_auth_user_one)
30
+ controller.params[:token] = test_user.username
31
+
32
+ session = UserSession.new
33
+ assert_true session.save, "should be a valid session"
34
+ assert_true session.new_registration?, "should be a new registration"
35
+ assert_true session.registration_complete?, "registration should be complete"
36
+ end
37
+
38
+
39
+ must "auto-register disabled for an unregistered user" do
40
+ # enforce Authlogic settings required for test
41
+ UserSession.auto_register false
42
+ User.account_merge_enabled false
43
+ User.account_mapping_mode :none
44
+
45
+ # get response template. set the controller token (used by RPX mock to match mock response)
46
+ test_user = rpxresponses(:unregistered_rpx_auth_user_one)
47
+ controller.params[:token] = test_user.username
48
+
49
+ session = UserSession.new
50
+ assert_false session.save, "should not be a valid session"
51
+ end
52
+
53
+ end
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + '/../../test_internal_mapping_helper.rb'
2
+ require File.dirname(__FILE__) + '/../basic_authentication_and_registration_test.rb'
3
+
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../../test_internal_mapping_helper.rb'
2
+
3
+ class SettingsTest < ActiveSupport::TestCase
4
+
5
+ must "account_mapping_mode :auto should resolve to :internal" do
6
+ assert_equal :auto, User.account_mapping_mode
7
+ assert_equal :internal, User.account_mapping_mode_used
8
+ end
9
+
10
+ end
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper.rb'
2
+ require File.dirname(__FILE__) + '/../basic_authentication_and_registration_test.rb'
3
+
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper.rb'
2
+
3
+ class SettingsTest < ActiveSupport::TestCase
4
+
5
+ must "account_mapping_mode :auto should resolve to :none" do
6
+ assert_equal :auto, User.account_mapping_mode
7
+ assert_equal :none, User.account_mapping_mode_used
8
+ end
9
+
10
+ end
@@ -0,0 +1,30 @@
1
+ module Test::Unit
2
+
3
+ class TestCase
4
+
5
+ def self.must(name, &block)
6
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
7
+ defined = instance_method(test_name) rescue false
8
+ raise "#{test_name} is already defined in #{self}" if defined
9
+ if block_given?
10
+ define_method(test_name, &block)
11
+ else
12
+ define_method(test_name) do
13
+ flunk "No implementation provided for #{name}"
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+
21
+
22
+ module Test::Unit::Assertions
23
+ def assert_false(object, message="")
24
+ assert_equal(false, object, message)
25
+ end
26
+ def assert_true(object, message="")
27
+ assert_equal(true, object, message)
28
+ end
29
+ end
30
+
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/rpxresponse.rb'
2
+
3
+ module RPXNow
4
+
5
+ def self.user_data(token, options={})
6
+ data = get_test_data(token)
7
+ if block_given? then yield(data) else parse_user_data(data) end
8
+ end
9
+
10
+ def self.parse_user_data(data)
11
+ data
12
+ end
13
+
14
+ def self.get_test_data(token)
15
+
16
+ response = Rpxresponse.find_by_username(token)
17
+ if response
18
+ data = {}
19
+ data['profile'] = {}
20
+ data['profile']['identifier'] = response.identifier
21
+ data['profile']['providerName'] = response.provider_name
22
+ data['profile']['preferredUsername'] = response.username
23
+ data['profile']['email'] = response.verified_email
24
+
25
+ data[:identifier] = data['profile']['identifier']
26
+ data[:providerName] = data['profile']['providerName']
27
+ data[:email] = response.verified_email
28
+ data[:username] = data['profile']['preferredUsername']
29
+ data[:name] = response.display_name
30
+ end
31
+
32
+ data
33
+ end
34
+ end
@@ -2,9 +2,9 @@
2
2
  # these constants be present. The only other alternative is to use an entire rails application for testing
3
3
  # which is a little too overboard for this, I think.
4
4
 
5
- RAILS_ROOT = ''
5
+ #RAILS_ROOT = ''
6
6
 
7
- class ActionController < Authlogic::TestCase::MockController
7
+ class ActionControllerEx < Authlogic::TestCase::MockController
8
8
  class Request < Authlogic::TestCase::MockRequest
9
9
  def request_method
10
10
  ""
@@ -0,0 +1,3 @@
1
+ class Rpxresponse < ActiveRecord::Base
2
+
3
+ end
@@ -1,3 +1,3 @@
1
1
  class UserSession < Authlogic::Session::Base
2
-
2
+ rpx_key RPX_API_KEY
3
3
  end
@@ -1,14 +1,37 @@
1
- require "test/unit"
2
1
  require "rubygems"
2
+ begin
3
+ gem 'test-unit'
4
+ require "test/unit"
5
+ require File.dirname(__FILE__) + "/libs/ext_test_unit"
6
+ rescue Gem::LoadError
7
+ # assume using stdlib Test:Unit
8
+ require "test/unit"
9
+ require File.dirname(__FILE__) + "/libs/ext_test_unit"
10
+ end
11
+
3
12
  require "ruby-debug"
4
13
  require "active_record"
5
14
  require "action_controller"
6
15
 
7
16
  ActiveRecord::Schema.verbose = false
8
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
17
+
18
+ begin
19
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
20
+ rescue ArgumentError
21
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
22
+ end
23
+
9
24
  ActiveRecord::Base.configurations = true
10
25
  ActiveRecord::Schema.define(:version => 1) do
11
-
26
+
27
+ create_table :rpxresponses do |t|
28
+ t.string :identifier
29
+ t.string :provider_name
30
+ t.string :username
31
+ t.string :verified_email
32
+ t.string :display_name
33
+ end
34
+
12
35
  create_table :users do |t|
13
36
  t.datetime :created_at
14
37
  t.datetime :updated_at
@@ -31,24 +54,24 @@ ActiveRecord::Schema.define(:version => 1) do
31
54
  t.string :current_login_ip
32
55
  t.string :last_login_ip
33
56
  end
57
+
34
58
  end
35
59
 
36
60
  require "active_record/fixtures"
37
- Rails = true
38
-
61
+ require "authlogic"
39
62
  require "authlogic/test_case"
40
63
 
41
- include Authlogic::TestCase
64
+ require "rpx_now"
65
+ RPX_API_KEY = 'abcdefghijklmnopqrstuvwxyz' unless defined? RPX_API_KEY
42
66
 
67
+ require File.dirname(__FILE__) + "/../lib/authlogic_rpx"
43
68
 
44
- #require File.dirname(__FILE__) + "/../../authlogic/lib/authlogic"
45
- #require File.dirname(__FILE__) + "/../../authlogic/lib/authlogic/test_case"
46
- #require File.dirname(__FILE__) + "/libs/rails_trickery"
69
+ require File.dirname(__FILE__) + "/libs/rails_trickery"
70
+ require File.dirname(__FILE__) + '/libs/rpxresponse'
71
+ require File.dirname(__FILE__) + '/libs/mock_rpx_now'
47
72
  require File.dirname(__FILE__) + '/libs/user'
48
73
  require File.dirname(__FILE__) + '/libs/user_session'
49
74
 
50
- require File.dirname(__FILE__) + "./../rails/init.rb"
51
-
52
75
  class ActiveSupport::TestCase
53
76
  include ActiveRecord::TestFixtures
54
77
  self.fixture_path = File.dirname(__FILE__) + "/fixtures"
@@ -59,15 +82,6 @@ class ActiveSupport::TestCase
59
82
  setup :activate_authlogic
60
83
 
61
84
  private
62
- def activate_authlogic
63
- Authlogic::Session::Base.controller = controller
64
- end
65
-
66
- def controller
67
- @controller ||= Authlogic::TestCase::ControllerAdapter.new(ActionController.new)
68
- end
69
85
 
70
- def redirecting_to_rpx?
71
- controller.redirecting_to.to_s =~ /^http:\/\/rpxnow.com/
72
- end
86
+
73
87
  end