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
data/Rakefile CHANGED
@@ -10,11 +10,39 @@ Echoe.new("authlogic_rpx") do |p|
10
10
  p.summary = "Authlogic plug-in for RPX support"
11
11
  p.description = "Authlogic extension/plugin that provides RPX (rpxnow.com) authentication support"
12
12
 
13
- p.runtime_dependencies = ["authlogic >=2.1.1", "rpx_now >=0.6.6" ]
13
+ p.runtime_dependencies = ["authlogic >=2.1.3", "rpx_now >=0.6.11" ]
14
14
  p.development_dependencies = []
15
15
 
16
16
  p.author = "Paul Gallagher / tardate"
17
17
  p.email = "gallagher.paul@gmail.com"
18
18
 
19
19
  p.install_message = ""
20
- end
20
+ end
21
+
22
+
23
+ Rake::Task[:test].clear
24
+
25
+ Rake::TestTask.new(:unit) do |t|
26
+ t.libs << "test/libs"
27
+ t.pattern = 'test/unit/*test.rb'
28
+ t.verbose = true
29
+ end
30
+
31
+ Rake::TestTask.new(:no_mapping) do |t|
32
+ t.libs << "test/libs"
33
+ t.test_files = FileList.new('test/unit/*test.rb', 'test/integration/no_mapping/*test.rb')
34
+ t.verbose = true
35
+ end
36
+
37
+ Rake::TestTask.new(:internal_mapping) do |t|
38
+ t.libs << "test/libs"
39
+ t.test_files = FileList.new('test/integration/internal_mapping/*test.rb')
40
+ t.verbose = true
41
+ end
42
+
43
+ task :test do
44
+ Rake::Task[:no_mapping].invoke
45
+ Rake::Task[:internal_mapping].invoke
46
+ end
47
+
48
+ task :default => :test
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{authlogic_rpx}
5
- s.version = "1.0.4"
5
+ s.version = "1.1.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Paul Gallagher / tardate"]
9
- s.date = %q{2009-10-15}
9
+ s.date = %q{2010-01-05}
10
10
  s.description = %q{Authlogic extension/plugin that provides RPX (rpxnow.com) authentication support}
11
11
  s.email = %q{gallagher.paul@gmail.com}
12
- s.extra_rdoc_files = ["CHANGELOG.rdoc", "README.rdoc", "lib/authlogic_rpx.rb", "lib/authlogic_rpx/acts_as_authentic.rb", "lib/authlogic_rpx/helper.rb", "lib/authlogic_rpx/session.rb", "lib/authlogic_rpx/version.rb"]
13
- s.files = ["CHANGELOG.rdoc", "MIT-LICENSE", "Manifest", "README.rdoc", "Rakefile", "authlogic_rpx.gemspec", "init.rb", "lib/authlogic_rpx.rb", "lib/authlogic_rpx/acts_as_authentic.rb", "lib/authlogic_rpx/helper.rb", "lib/authlogic_rpx/session.rb", "lib/authlogic_rpx/version.rb", "rails/init.rb", "test/acts_as_authentic_test.rb", "test/fixtures/users.yml", "test/libs/rails_trickery.rb", "test/libs/user.rb", "test/libs/user_session.rb", "test/session_test.rb", "test/test_helper.rb"]
12
+ s.extra_rdoc_files = ["CHANGELOG.rdoc", "README.rdoc", "lib/authlogic_rpx.rb", "lib/authlogic_rpx/acts_as_authentic.rb", "lib/authlogic_rpx/helper.rb", "lib/authlogic_rpx/rpx_identifier.rb", "lib/authlogic_rpx/session.rb", "lib/authlogic_rpx/version.rb"]
13
+ s.files = ["CHANGELOG.rdoc", "MIT-LICENSE", "Manifest", "README.rdoc", "Rakefile", "authlogic_rpx.gemspec", "generators/add_authlogic_rpx_migration/USAGE", "generators/add_authlogic_rpx_migration/add_authlogic_rpx_migration_generator.rb", "generators/add_authlogic_rpx_migration/templates/migration_internal_mapping.rb", "generators/add_authlogic_rpx_migration/templates/migration_no_mapping.rb", "init.rb", "lib/authlogic_rpx.rb", "lib/authlogic_rpx/acts_as_authentic.rb", "lib/authlogic_rpx/helper.rb", "lib/authlogic_rpx/rpx_identifier.rb", "lib/authlogic_rpx/session.rb", "lib/authlogic_rpx/version.rb", "rails/init.rb", "test/fixtures/rpxresponses.yml", "test/fixtures/users.yml", "test/integration/basic_authentication_and_registration_test.rb", "test/integration/internal_mapping/basic_authentication_and_registration_test.rb", "test/integration/internal_mapping/settings_test.rb", "test/integration/no_mapping/basic_authentication_and_registration_test.rb", "test/integration/no_mapping/settings_test.rb", "test/libs/ext_test_unit.rb", "test/libs/mock_rpx_now.rb", "test/libs/rails_trickery.rb", "test/libs/rpxresponse.rb", "test/libs/user.rb", "test/libs/user_session.rb", "test/test_helper.rb", "test/test_internal_mapping_helper.rb", "test/unit/acts_as_authentic_settings_test.rb", "test/unit/session_settings_test.rb", "test/unit/session_validation_test.rb", "test/unit/verify_rpx_mock_test.rb"]
14
14
  s.homepage = %q{http://github.com/tardate/authlogic_rpx}
15
15
  s.post_install_message = %q{}
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Authlogic_rpx", "--main", "README.rdoc"]
@@ -18,21 +18,21 @@ Gem::Specification.new do |s|
18
18
  s.rubyforge_project = %q{authlogic_rpx}
19
19
  s.rubygems_version = %q{1.3.5}
20
20
  s.summary = %q{Authlogic plug-in for RPX support}
21
- s.test_files = ["test/acts_as_authentic_test.rb", "test/session_test.rb", "test/test_helper.rb"]
21
+ s.test_files = ["test/integration/basic_authentication_and_registration_test.rb", "test/integration/internal_mapping/basic_authentication_and_registration_test.rb", "test/integration/internal_mapping/settings_test.rb", "test/integration/no_mapping/basic_authentication_and_registration_test.rb", "test/integration/no_mapping/settings_test.rb", "test/test_helper.rb", "test/test_internal_mapping_helper.rb", "test/unit/acts_as_authentic_settings_test.rb", "test/unit/session_settings_test.rb", "test/unit/session_validation_test.rb", "test/unit/verify_rpx_mock_test.rb"]
22
22
 
23
23
  if s.respond_to? :specification_version then
24
24
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
25
  s.specification_version = 3
26
26
 
27
27
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
- s.add_runtime_dependency(%q<authlogic>, [">= 2.1.1"])
29
- s.add_runtime_dependency(%q<rpx_now>, [">= 0.6.6"])
28
+ s.add_runtime_dependency(%q<authlogic>, [">= 2.1.3"])
29
+ s.add_runtime_dependency(%q<rpx_now>, [">= 0.6.11"])
30
30
  else
31
- s.add_dependency(%q<authlogic>, [">= 2.1.1"])
32
- s.add_dependency(%q<rpx_now>, [">= 0.6.6"])
31
+ s.add_dependency(%q<authlogic>, [">= 2.1.3"])
32
+ s.add_dependency(%q<rpx_now>, [">= 0.6.11"])
33
33
  end
34
34
  else
35
- s.add_dependency(%q<authlogic>, [">= 2.1.1"])
36
- s.add_dependency(%q<rpx_now>, [">= 0.6.6"])
35
+ s.add_dependency(%q<authlogic>, [">= 2.1.3"])
36
+ s.add_dependency(%q<rpx_now>, [">= 0.6.11"])
37
37
  end
38
38
  end
@@ -0,0 +1,18 @@
1
+ Description:
2
+ ruby script/generate add_authlogic_rpx_migration [mapping:mapping_mode] [user_model:model_name]
3
+
4
+ Creates an add_authlogic_rpx_migration file in db/migrate.
5
+
6
+ The mapping_mode parameter indicates which style of Authlogic_RPX-supported identity
7
+ mapping should be used. Allowed values for mapping_mode are:
8
+ none
9
+ internal
10
+ Default mapping_mode is 'internal'
11
+
12
+ The user_model parameter specifies the name of the user/member model in your application.
13
+ Default model_name is 'User'
14
+
15
+ e.g. to generate the RPX migration where the user model is called 'Member' and you do not
16
+ want to support identity mapping:
17
+
18
+ ruby script/generate add_authlogic_rpx_migration mapping:none user_model:member
@@ -0,0 +1,44 @@
1
+ class AddAuthlogicRpxMigrationGenerator < Rails::Generator::Base
2
+ def manifest
3
+
4
+ record do |m|
5
+
6
+ m.migration_template template_name, 'db/migrate', :assigns => {
7
+ :user_model_base => user_model_base,
8
+ :user_model => user_model,
9
+ :user_model_collection => user_model_collection
10
+ }
11
+ end
12
+ end
13
+
14
+ def file_name
15
+ "add_authlogic_rpx_migration"
16
+ end
17
+
18
+ protected
19
+ # Override with your own usage banner.
20
+ def banner
21
+ "Usage: #{$0} #{spec.name} [options] [mapping:mapping_mode] [user_model:model_name]"
22
+ end
23
+
24
+ attr_writer :params
25
+ def params
26
+ @params ||= {"mapping" => "internal", "user_model" => "User"}.merge( Hash[*(@args.collect { |arg| arg.split(":") }.flatten)] )
27
+ end
28
+
29
+ def user_model_base
30
+ params['user_model'].singularize.downcase
31
+ end
32
+ def user_model
33
+ params['user_model'].singularize.capitalize
34
+ end
35
+ def user_model_collection
36
+ params['user_model'].pluralize.downcase
37
+ end
38
+ def mapping
39
+ params['mapping']
40
+ end
41
+ def template_name
42
+ mapping == 'none' ? 'migration_no_mapping.rb' : 'migration_internal_mapping.rb'
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ class AddAuthlogicRpxMigration < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :rpx_identifiers do |t|
4
+ t.string :identifier, :null => false
5
+ t.string :provider_name
6
+ t.integer :<%= user_model_base %>_id, :null => false
7
+ t.timestamps
8
+ end
9
+ add_index :rpx_identifiers, :identifier, :unique => true, :null => false
10
+ add_index :rpx_identifiers, :<%= user_model_base %>_id, :unique => false, :null => false
11
+
12
+ # == Customisation may be required here ==
13
+ # You may need to remove database constraints on other fields if they will be unused in the RPX case
14
+ # (e.g. crypted_password and password_salt to make password authentication optional).
15
+ # If you are using auto-registration, you must also remove any database constraints for fields that will be automatically mapped
16
+ # e.g.:
17
+ #change_column :<%= user_model_collection %>, :crypted_password, :string, :default => nil, :null => true
18
+ #change_column :<%= user_model_collection %>, :password_salt, :string, :default => nil, :null => true
19
+
20
+ end
21
+
22
+ def self.down
23
+ drop_table :rpx_identifiers
24
+
25
+ # == Customisation may be required here ==
26
+ # Restore user model database constraints as appropriate
27
+ # e.g.:
28
+ #[:crypted_password, :password_salt].each do |field|
29
+ # <%= user_model %>.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
30
+ # change_column :<%= user_model_collection %>, field, :string, :default => "", :null => false
31
+ #end
32
+
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ class AddAuthlogicRpxMigration < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ add_column :<%= user_model_collection %>, :rpx_identifier, :string
5
+ add_index :<%= user_model_collection %>, :rpx_identifier
6
+
7
+ # == Customisation may be required here ==
8
+ # You may need to remove database constraints on other fields if they will be unused in the RPX case
9
+ # (e.g. crypted_password and password_salt to make password authentication optional).
10
+ # If you are using auto-registration, you must also remove any database constraints for fields that will be automatically mapped
11
+ # e.g.:
12
+ #change_column :<%= user_model_collection %>, :crypted_password, :string, :default => nil, :null => true
13
+ #change_column :<%= user_model_collection %>, :password_salt, :string, :default => nil, :null => true
14
+
15
+ end
16
+
17
+ def self.down
18
+ remove_column :<%= user_model_collection %>, :rpx_identifier
19
+
20
+ # == Customisation may be required here ==
21
+ # Restore user model database constraints as appropriate
22
+ # e.g.:
23
+ #[:crypted_password, :password_salt].each do |field|
24
+ # <%= user_model %>.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
25
+ # change_column :<%= user_model_collection %>, field, :string, :default => "", :null => false
26
+ #end
27
+
28
+ end
29
+ end
@@ -2,6 +2,7 @@ require "authlogic_rpx/version"
2
2
  require "authlogic_rpx/acts_as_authentic"
3
3
  require "authlogic_rpx/session"
4
4
  require "authlogic_rpx/helper"
5
+ require "authlogic_rpx/rpx_identifier"
5
6
 
6
7
  ActiveRecord::Base.send(:include, AuthlogicRpx::ActsAsAuthentic)
7
8
  Authlogic::Session::Base.send(:include, AuthlogicRpx::Session)
@@ -7,24 +7,73 @@ module AuthlogicRpx
7
7
  # Adds in the neccesary modules for acts_as_authentic to include and also disabled password validation if
8
8
  # RPX is being used.
9
9
  def self.included(klass)
10
- klass.class_eval do
11
- extend Config
12
- add_acts_as_authentic_module(Methods, :prepend)
13
- end
10
+ klass.class_eval do
11
+ extend Config
12
+ add_acts_as_authentic_module(Methods, :prepend)
13
+ end
14
14
  end
15
15
 
16
+ class GeneralError < StandardError
17
+ end
18
+ class ConfigurationError < StandardError
19
+ end
20
+
16
21
  module Config
17
-
18
- # map_id is used to enable RPX identity mapping
19
- # experimental - a feature of RPX paid accounts and not properly developed/tested yet
22
+
23
+ # account_merge_enabled is used to enable merging of accounts.
20
24
  #
21
25
  # * <tt>Default:</tt> false
22
26
  # * <tt>Accepts:</tt> boolean
23
- def map_id(value = false)
24
- rw_config(:map_id, value, false)
27
+ def account_merge_enabled(value=false)
28
+ account_merge_enabled_value(value)
29
+ end
30
+ def account_merge_enabled_value(value=nil)
31
+ rw_config(:account_merge_enabled,value,false)
32
+ end
33
+ alias_method :account_merge_enabled=,:account_merge_enabled
34
+
35
+
36
+ # account_mapping_mode is used to explicitly set/override the mapping behaviour.
37
+ #
38
+ # * <tt>Default:</tt> :auto
39
+ # * <tt>Accepts:</tt> :auto, :none, :internal, :rpxnow
40
+ def account_mapping_mode(value=:auto)
41
+ account_mapping_mode_value(value)
25
42
  end
26
- alias_method :map_id=, :map_id
43
+ def account_mapping_mode_value(value=nil)
44
+ raise AuthlogicRpx::ActsAsAuthentic::ConfigurationError.new unless value.nil? || [:auto,:none,:internal].include?( value )
45
+ rw_config(:account_mapping_mode,value,:auto)
46
+ end
47
+ alias_method :account_mapping_mode=,:account_mapping_mode
48
+
49
+ # returns the actual account mapping mode in use - resolves :auto to actual mechanism
50
+ #
51
+ attr_writer :account_mapping_mode_used
52
+ def account_mapping_mode_used
53
+ @account_mapping_mode_used ||= (
54
+ account_mapping_mode_value == :auto ?
55
+ ( RPXIdentifier.table_exists? ?
56
+ :internal :
57
+ ( self.column_names.include?("rpx_identifier") ? :none : AuthlogicRpx::ActsAsAuthentic::ConfigurationError.new )
58
+ ) :
59
+ account_mapping_mode_value
60
+ )
61
+ end
62
+
27
63
 
64
+ # determines if no account mapping is supported (the only behaviour in authlogic_rpx v1.0.4)
65
+ def using_no_mapping?
66
+ account_mapping_mode_used == :none
67
+ end
68
+ # determines if internal account mapping is enabled (behaviour added in authlogic_rpx v1.1.0)
69
+ def using_internal_mapping?
70
+ account_mapping_mode_used == :internal
71
+ end
72
+ # determines if rpxnow account mapping is enabled (currently not implemented)
73
+ def using_rpx_mapping?
74
+ account_mapping_mode_used == :rpxnow
75
+ end
76
+
28
77
  end
29
78
 
30
79
  module Methods
@@ -32,12 +81,60 @@ module AuthlogicRpx
32
81
  # Set up some simple validations
33
82
  def self.included(klass)
34
83
  klass.class_eval do
35
- validates_uniqueness_of :rpx_identifier, :scope => validations_scope, :if => :using_rpx?
84
+
85
+ case
86
+ when using_no_mapping?
87
+ alias_method :using_rpx?, :using_rpx__nomap?
88
+ alias_method :add_rpx_identifier, :add_rpx_identifier__nomap
89
+ alias_method :identified_by?, :identified_by__nomap?
90
+ alias_method :merge_user_id, :merge_user_id__nomap
91
+
92
+ # Uses default find_by_rpx_identifier class method
93
+
94
+ # Add an rpx_identifier collection method
95
+ def rpx_identifiers
96
+ [{ :identifier => rpx_identifier, :provider_name => "Unknown" }]
97
+ end
98
+
99
+ when using_internal_mapping?
100
+ alias_method :using_rpx?, :using_rpx__internal?
101
+ alias_method :add_rpx_identifier, :add_rpx_identifier__internal
102
+ alias_method :identified_by?, :identified_by__internal?
103
+ alias_method :merge_user_id, :merge_user_id__internal
104
+ has_many :rpx_identifiers, :class_name => 'RPXIdentifier', :dependent => :destroy
105
+
106
+ # Add custom find_by_rpx_identifier class method
107
+ def self.find_by_rpx_identifier(id)
108
+ identifier = RPXIdentifier.find_by_identifier(id)
109
+ if identifier.nil?
110
+ if self.column_names.include? 'rpx_identifier'
111
+ # check for authentication using <=1.0.4, migrate identifier to rpx_identifiers table
112
+ user = self.find( :first, :conditions => [ "rpx_identifier = ?", id ] )
113
+ unless user.nil?
114
+ user.add_rpx_identifier( id, 'Unknown' )
115
+ end
116
+ return user
117
+ else
118
+ return nil
119
+ end
120
+ else
121
+ identifier.user
122
+ end
123
+ end
124
+
125
+ else
126
+ raise AuthlogicRpx::ActsAsAuthentic::ConfigurationError.new( "invalid or unsupported account_mapping_mode" )
127
+ end
128
+
36
129
  validates_length_of_password_field_options validates_length_of_password_field_options.merge(:if => :validate_password_with_rpx?)
37
130
  validates_confirmation_of_password_field_options validates_confirmation_of_password_field_options.merge(:if => :validate_password_with_rpx?)
38
131
  validates_length_of_password_confirmation_field_options validates_length_of_password_confirmation_field_options.merge(:if => :validate_password_with_rpx?)
132
+
39
133
  before_validation :adding_rpx_identifier
40
- after_create :map_rpx_identifier
134
+ end
135
+
136
+ RPXIdentifier.class_eval do
137
+ belongs_to klass.name.downcase.to_sym
41
138
  end
42
139
  end
43
140
 
@@ -49,65 +146,135 @@ module AuthlogicRpx
49
146
  end
50
147
 
51
148
  # test if account it using RPX authentication
52
- def using_rpx?
53
- !rpx_identifier.blank?
149
+ # aliased to using_rpx based on authlogic_rpx configuration mode
150
+ def using_rpx__nomap?
151
+ !rpx_identifier.blank?
54
152
  end
55
-
153
+ def using_rpx__internal?
154
+ !rpx_identifiers.empty?
155
+ end
156
+
56
157
  # test if account it using normal password authentication
57
158
  def using_password?
58
159
  !send(crypted_password_field).blank?
59
160
  end
60
161
 
162
+ # adds RPX identification to the instance.
163
+ # Abstracts how the RPX identifier is added to allow for multiplicity of underlying implementations
164
+ # aliased to add_rpx_identifier based on authlogic_rpx configuration mode
165
+ def add_rpx_identifier__nomap( rpx_id, rpx_provider_name )
166
+ self.rpx_identifier = rpx_id
167
+ #TODO: make rpx_provider_name a std param?
168
+ end
169
+ def add_rpx_identifier__internal( rpx_id, rpx_provider_name )
170
+ self.rpx_identifiers.build(:identifier => rpx_id, :provider_name => rpx_provider_name )
171
+ end
172
+
173
+ # Checks if given identifier is an identity for this account
174
+ # aliased to identified_by based on authlogic_rpx configuration mode
175
+ def identified_by__nomap?( id )
176
+ self.rpx_identifier == id
177
+ end
178
+ def identified_by__internal?( id )
179
+ self.rpx_identifiers.find_by_identifier( id )
180
+ end
181
+
61
182
  private
62
183
 
184
+ # tests if password authentication should be checked: if rpx is enabled (but not used by this user)
63
185
  def validate_password_with_rpx?
64
186
  !using_rpx? && require_password?
65
187
  end
188
+
189
+ # determines if account merging is enabled; delegates to class method
190
+ def account_merge_enabled?
191
+ self.class.account_merge_enabled_value
192
+ end
66
193
 
67
194
  # hook for adding RPX identifier to an existing account. This is invoked prior to model validation.
68
195
  # RPX information is plucked from the controller session object (where it was placed by the session model as a result
69
196
  # of the RPX callback)
70
- # The minimal action taken is to populate the rpx_identifier field in the user model.
197
+ # The minimal action taken is to add an RPXIdentifier object to the user.
71
198
  #
72
199
  # This procedure chains to the map_added_rpx_data, which may be over-ridden in your project to perform
73
200
  # additional mapping of RPX information to the user model as may be desired.
74
201
  #
75
202
  def adding_rpx_identifier
76
203
  return true unless session_class && session_class.controller
77
- added_rpx_data = session_class.controller.session['added_rpx_data']
204
+
205
+ added_rpx_data = session_class.controller.session['added_rpx_data']
78
206
  unless added_rpx_data.blank?
79
207
  session_class.controller.session['added_rpx_data'] = nil
208
+ rpx_id = added_rpx_data['profile']['identifier']
209
+ rpx_provider_name = added_rpx_data['profile']['providerName']
210
+
211
+ unless self.identified_by?( rpx_id )
212
+ # identifier not already set for this user..
213
+
214
+ another_user = self.class.find_by_rpx_identifier( rpx_id )
215
+ if another_user
216
+ return false unless account_merge_enabled?
217
+ # another user already has this id registered..
218
+
219
+ # merge all IDs from another_user to self, with application callbacks before/after
220
+ before_merge_rpx_data( another_user, self )
221
+ merge_user_id another_user
222
+ after_merge_rpx_data( another_user, self )
223
+
224
+ else
225
+ self.add_rpx_identifier( rpx_id, rpx_provider_name )
226
+ end
227
+ end
228
+
80
229
  map_added_rpx_data( added_rpx_data )
81
230
  end
231
+
82
232
  return true
233
+ end
234
+
235
+ # merge_user_id is an internal method used to merge the actual RPX identifiers
236
+ # aliased to merge_user_id based on authlogic_rpx configuration mode
237
+ def merge_user_id__nomap( from_user )
238
+ self.rpx_identifier = from_user.rpx_identifier
239
+ from_user.rpx_identifier = nil
240
+ from_user.save
241
+ from_user.reload
242
+ end
243
+ def merge_user_id__internal( from_user )
244
+ self.rpx_identifiers << from_user.rpx_identifiers
245
+ from_user.reload
83
246
  end
84
247
 
248
+
85
249
  # map_added_rpx_data maps additional fields from the RPX response into the user object during the "add RPX to existing account" process.
86
250
  # Override this in your user model to perform field mapping as may be desired
87
251
  # See https://rpxnow.com/docs#profile_data for the definition of available attributes
88
252
  #
89
- # By default, it only maps the rpx_identifier field.
253
+ # "self" at this point is the user model. Map details as appropriate from the rpx_data structure provided.
90
254
  #
91
255
  def map_added_rpx_data( rpx_data )
92
- self.rpx_identifier = rpx_data['profile']['identifier']
256
+
93
257
  end
258
+
259
+ # before_merge_rpx_data provides a hook for application developers to perform data migration prior to the merging of user accounts.
260
+ # This method is called just before authlogic_rpx merges the user registration for 'from_user' into 'to_user'
261
+ # Authlogic_RPX is responsible for merging registration data.
262
+ #
263
+ # By default, it does not merge any other details (e.g. application data ownership)
264
+ #
265
+ def before_merge_rpx_data( from_user, to_user )
94
266
 
95
-
96
-
97
- # experimental - a feature of RPX paid accounts and not properly developed/tested yet
98
- def map_id?
99
- self.class.map_id
100
- end
101
-
102
- # experimental - a feature of RPX paid accounts and not properly developed/tested yet
103
- def map_rpx_identifier
104
- RPXNow.map(rpx_identifier, id) if using_rpx? && map_id?
105
267
  end
106
268
 
107
- # experimental - a feature of RPX paid accounts and not properly developed/tested yet
108
- def unmap_rpx_identifer
109
- RPXNow.unmap(rpx_identifier, id) if using_rpx? && map_id?
269
+ # after_merge_rpx_data provides a hook for application developers to perform account clean-up after authlogic_rpx has
270
+ # migrated registration details.
271
+ #
272
+ # By default, does nothing. It could, for example, be used to delete or disable the 'from_user' account
273
+ #
274
+ def after_merge_rpx_data( from_user, to_user )
275
+
110
276
  end
277
+
111
278
 
112
279
  end
113
280
  end