authlogic_rpx 1.1.1 → 1.2.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 +45 -38
  2. data/MIT-LICENSE +20 -20
  3. data/Manifest +37 -37
  4. data/README.rdoc +751 -747
  5. data/Rakefile +54 -47
  6. data/authlogic_rpx.gemspec +101 -38
  7. data/generators/add_authlogic_rpx_migration/USAGE +18 -18
  8. data/generators/add_authlogic_rpx_migration/add_authlogic_rpx_migration_generator.rb +44 -44
  9. data/generators/add_authlogic_rpx_migration/templates/migration_internal_mapping.rb +34 -34
  10. data/generators/add_authlogic_rpx_migration/templates/migration_no_mapping.rb +29 -29
  11. data/lib/authlogic_rpx.rb +8 -8
  12. data/lib/authlogic_rpx/acts_as_authentic.rb +297 -281
  13. data/lib/authlogic_rpx/helper.rb +53 -43
  14. data/lib/authlogic_rpx/rpx_identifier.rb +4 -5
  15. data/lib/authlogic_rpx/session.rb +224 -218
  16. data/lib/authlogic_rpx/version.rb +50 -50
  17. data/test/fixtures/rpxresponses.yml +20 -20
  18. data/test/fixtures/users.yml +19 -19
  19. data/test/integration/basic_authentication_and_registration_test.rb +52 -52
  20. data/test/integration/internal_mapping/basic_authentication_and_registration_test.rb +3 -3
  21. data/test/integration/internal_mapping/settings_test.rb +9 -9
  22. data/test/integration/no_mapping/basic_authentication_and_registration_test.rb +3 -3
  23. data/test/integration/no_mapping/settings_test.rb +9 -9
  24. data/test/libs/ext_test_unit.rb +30 -30
  25. data/test/libs/mock_rpx_now.rb +33 -33
  26. data/test/libs/rails_trickery.rb +40 -40
  27. data/test/libs/rpxresponse.rb +2 -2
  28. data/test/libs/user.rb +2 -2
  29. data/test/libs/user_session.rb +2 -2
  30. data/test/test_helper.rb +84 -86
  31. data/test/test_internal_mapping_helper.rb +93 -95
  32. data/test/unit/acts_as_authentic_settings_test.rb +41 -41
  33. data/test/unit/session_settings_test.rb +37 -37
  34. data/test/unit/session_validation_test.rb +15 -15
  35. data/test/unit/verify_rpx_mock_test.rb +28 -28
  36. metadata +66 -32
@@ -1,39 +1,46 @@
1
- == 1.1.1 released 2010-01-17
2
-
3
- * updated gem support to rpx_now 0.6.12 (includes url encoding fix)
4
-
5
- == 1.1.0 released 2010-01-05
6
-
7
- * added identity mapping and merging support [GH#10,GH#13]
8
- * new configuration parameters: account_mapping_mode; account_merge_enabled.
9
- * new callbacks: before_merge_rpx_data; after_merge_rpx_data.
10
- * updated gem support to authlogic 2.1.3 and rpx_now 0.6.11
11
- * support all rpx_now options in popup/embed code [GH#6]
12
- * automated tests are now working [GH#7]
13
- * documentation updates
14
-
15
- == 1.0.4 released 2009-10-10
16
-
17
- * added new hooks for profile mapping (Session.map_rpx_data_each_login, ActsAsAuthentic.map_added_rpx_data) based on suggestion by trosser (github issue #5)
18
- * now supporting obtrusive (javascript pop-over) and unobtrusive (link) RPX pop-up sign-in forms. See rpx_popup method. (github issue #4)
19
- * updated support for rpx_now gem version 0.6.6
20
- * documentation updates
21
-
22
- == 1.0.3 released 2009-10-07
23
-
24
- * added general error handler for session validation to give clean 'failure' when underlying errors encountered (e.g. user model database constraint violation)
25
- * updated documentation
26
-
27
- == 1.0.2 released 2009-09-27
28
-
29
- * Fixed issue with rpx_popup that was causing an error on some webkit-based browsers (incl chrome)
30
-
31
- == 1.0.1 released 2009-09-26
32
-
33
- * Initial public release
34
- * RPX profile mappings switched to use indirect Authlogic field naming
35
- * Documentation updated
36
-
37
- == 1.0.0 released 2009-09-25
38
-
1
+ == 1.2.0 released 2010-09-29
2
+
3
+ * added rails 3 compatibility (GH#24)
4
+ * updated gem support to authlogic 2.1.6 and rpx_now 0.6.23
5
+ * fix GH#21 internal mapping fails if user model is not called "User"
6
+ * fix GH#18 Add methods to retrieve "all rpx users" and "all non-rpx users"
7
+
8
+ == 1.1.1 released 2010-01-17
9
+
10
+ * updated gem support to rpx_now 0.6.12 (includes url encoding fix)
11
+
12
+ == 1.1.0 released 2010-01-05
13
+
14
+ * added identity mapping and merging support [GH#10,GH#13]
15
+ * new configuration parameters: account_mapping_mode; account_merge_enabled.
16
+ * new callbacks: before_merge_rpx_data; after_merge_rpx_data.
17
+ * updated gem support to authlogic 2.1.3 and rpx_now 0.6.11
18
+ * support all rpx_now options in popup/embed code [GH#6]
19
+ * automated tests are now working [GH#7]
20
+ * documentation updates
21
+
22
+ == 1.0.4 released 2009-10-10
23
+
24
+ * added new hooks for profile mapping (Session.map_rpx_data_each_login, ActsAsAuthentic.map_added_rpx_data) based on suggestion by trosser (github issue #5)
25
+ * now supporting obtrusive (javascript pop-over) and unobtrusive (link) RPX pop-up sign-in forms. See rpx_popup method. (github issue #4)
26
+ * updated support for rpx_now gem version 0.6.6
27
+ * documentation updates
28
+
29
+ == 1.0.3 released 2009-10-07
30
+
31
+ * added general error handler for session validation to give clean 'failure' when underlying errors encountered (e.g. user model database constraint violation)
32
+ * updated documentation
33
+
34
+ == 1.0.2 released 2009-09-27
35
+
36
+ * Fixed issue with rpx_popup that was causing an error on some webkit-based browsers (incl chrome)
37
+
38
+ == 1.0.1 released 2009-09-26
39
+
40
+ * Initial public release
41
+ * RPX profile mappings switched to use indirect Authlogic field naming
42
+ * Documentation updated
43
+
44
+ == 1.0.0 released 2009-09-25
45
+
39
46
  * Initial release
@@ -1,20 +1,20 @@
1
- Copyright (c) 2009 Paul Gallagher (tardate.com)
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2009 Paul Gallagher (tardate.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest CHANGED
@@ -1,37 +1,37 @@
1
- CHANGELOG.rdoc
2
- MIT-LICENSE
3
- Manifest
4
- README.rdoc
5
- Rakefile
6
- authlogic_rpx.gemspec
7
- generators/add_authlogic_rpx_migration/USAGE
8
- generators/add_authlogic_rpx_migration/add_authlogic_rpx_migration_generator.rb
9
- generators/add_authlogic_rpx_migration/templates/migration_internal_mapping.rb
10
- generators/add_authlogic_rpx_migration/templates/migration_no_mapping.rb
11
- init.rb
12
- lib/authlogic_rpx.rb
13
- lib/authlogic_rpx/acts_as_authentic.rb
14
- lib/authlogic_rpx/helper.rb
15
- lib/authlogic_rpx/rpx_identifier.rb
16
- lib/authlogic_rpx/session.rb
17
- lib/authlogic_rpx/version.rb
18
- rails/init.rb
19
- test/fixtures/rpxresponses.yml
20
- test/fixtures/users.yml
21
- test/integration/basic_authentication_and_registration_test.rb
22
- test/integration/internal_mapping/basic_authentication_and_registration_test.rb
23
- test/integration/internal_mapping/settings_test.rb
24
- test/integration/no_mapping/basic_authentication_and_registration_test.rb
25
- test/integration/no_mapping/settings_test.rb
26
- test/libs/ext_test_unit.rb
27
- test/libs/mock_rpx_now.rb
28
- test/libs/rails_trickery.rb
29
- test/libs/rpxresponse.rb
30
- test/libs/user.rb
31
- test/libs/user_session.rb
32
- test/test_helper.rb
33
- test/test_internal_mapping_helper.rb
34
- test/unit/acts_as_authentic_settings_test.rb
35
- test/unit/session_settings_test.rb
36
- test/unit/session_validation_test.rb
37
- test/unit/verify_rpx_mock_test.rb
1
+ CHANGELOG.rdoc
2
+ MIT-LICENSE
3
+ Manifest
4
+ README.rdoc
5
+ Rakefile
6
+ authlogic_rpx.gemspec
7
+ generators/add_authlogic_rpx_migration/USAGE
8
+ generators/add_authlogic_rpx_migration/add_authlogic_rpx_migration_generator.rb
9
+ generators/add_authlogic_rpx_migration/templates/migration_internal_mapping.rb
10
+ generators/add_authlogic_rpx_migration/templates/migration_no_mapping.rb
11
+ init.rb
12
+ lib/authlogic_rpx.rb
13
+ lib/authlogic_rpx/acts_as_authentic.rb
14
+ lib/authlogic_rpx/helper.rb
15
+ lib/authlogic_rpx/rpx_identifier.rb
16
+ lib/authlogic_rpx/session.rb
17
+ lib/authlogic_rpx/version.rb
18
+ rails/init.rb
19
+ test/fixtures/rpxresponses.yml
20
+ test/fixtures/users.yml
21
+ test/integration/basic_authentication_and_registration_test.rb
22
+ test/integration/internal_mapping/basic_authentication_and_registration_test.rb
23
+ test/integration/internal_mapping/settings_test.rb
24
+ test/integration/no_mapping/basic_authentication_and_registration_test.rb
25
+ test/integration/no_mapping/settings_test.rb
26
+ test/libs/ext_test_unit.rb
27
+ test/libs/mock_rpx_now.rb
28
+ test/libs/rails_trickery.rb
29
+ test/libs/rpxresponse.rb
30
+ test/libs/user.rb
31
+ test/libs/user_session.rb
32
+ test/test_helper.rb
33
+ test/test_internal_mapping_helper.rb
34
+ test/unit/acts_as_authentic_settings_test.rb
35
+ test/unit/session_settings_test.rb
36
+ test/unit/session_validation_test.rb
37
+ test/unit/verify_rpx_mock_test.rb
@@ -1,747 +1,751 @@
1
- = Authlogic_RPX
2
-
3
- == Purpose
4
-
5
- Authlogic_RPX is an Authlogic extension library that provides support for authentication using the RPX multi-authentication service offered by JanRain. To use RPX, you must first register your application at {RPX}[http://rpxnow.com/]. A free "Basic" account is available, in addition to paid enhanced versions. All work with Authlogic_RPX.
6
-
7
- Key features and capabilities:
8
- * Auto-registration by default following RPX authentication (can be disabled if required)
9
- * Can allow users to enable RPX authentication for their existing password-enabled accounts
10
- * View helpers to assist with inserting login fragments in pages
11
- * Can co-exist with standard password authentication
12
- * Supports identity mapping and merging (allowing users to have multiple logins associated with one member record on your site)
13
-
14
-
15
- == Authlogic_RPX References
16
-
17
- * <b>Authlogic_RPX gem repo:</b> [http://github.com/tardate/authlogic_rpx]
18
- * <b>Authlogic_RPX issues and feedback:</b> [http://github.com/tardate/authlogic_rpx/issues]
19
-
20
- The demonstration Rails application is where you can see Authlogic_RPX in action:
21
-
22
- * <b>Live Demonstration Site:</b> [http://rails-authlogic-rpx-sample.heroku.com]
23
- * <b>Demonstration site source repository:</b> [http://github.com/tardate/rails-authlogic-rpx-sample]
24
-
25
- == Authlogic and RPX References
26
-
27
- * <b>Authlogic documentation:</b> [http://rdoc.info/projects/binarylogic/authlogic]
28
- * <b>Authlogic repo:</b> [http://github.com/binarylogic/authlogic]
29
- * <b>RPX documentation:</b> [https://rpxnow.com/docs]
30
- * <b>RPX_now gem repo:</b> [http://github.com/grosser/rpx_now]
31
-
32
-
33
- == Installing Authlogic_RPX gem
34
-
35
- Three gems are required: authlogic, rpx_now, and authlogic_rpx. Install these as appropriate to your environment and preferences.
36
-
37
- Currently tested versions:
38
- * authlogic 2.1.3,2.1.2,2.1.1
39
- * rpx_now 0.6.12 (0.6.11,0.6.6 support is deprecated)
40
- * authlogic_rpx 1.1.1
41
-
42
-
43
- === 1. Direct gem installation
44
-
45
- sudo gem install authlogic
46
- sudo gem install rpx_now --source http://gemcutter.org
47
- sudo gem install authlogic_rpx --source http://gemcutter.org
48
-
49
-
50
- === 2. Using Rails config.gems
51
-
52
- Include in config/environment.rb:
53
-
54
- config.gem 'authlogic', :version => '>= 2.1.3'
55
- config.gem 'rpx_now', :version => '>= 0.6.12', :source => 'http://gemcutter.org'
56
- config.gem 'authlogic_rpx', :version => '>= 1.1.1', :source => 'http://gemcutter.org'
57
-
58
- Then to install, run from the command line:
59
-
60
- sudo rake gems:install
61
-
62
-
63
- === 3. Using .gems file (e.g for heroku.com deployments)
64
-
65
- Include in RAILS_ROOT/.gems:
66
-
67
- authlogic --version '>= 2.1.3'
68
- rpx_now --version '>= 0.6.12' --source gemcutter.org
69
- authlogic_rpx --version '>= 1.1.1' --source gemcutter.org
70
-
71
-
72
- == About Authlogic_RPX
73
-
74
- Using Authlogic_RPX is very similar to using standard authlogic, with the addition of just a few configuration options. So if you already have a project setup with authlogic, adding RPX support will be trivial.
75
-
76
- An important capability to be aware of is "auto registration". This means that when a user has logged in with RPX, if an account does not already exist in your application, it will be automatically created. That is, there is no separate/special "register" step for users to go through before just signing in. You can disable this if you need, but for most sites that use RPX as a primary authentication mechanism, this is probably what you want to happen.
77
-
78
- One of the main limitations of Authlogic_RPX versions up to 1.0.4 was that it did not include any specific support for identity mapping. This means that if a user signs in with twitter one day, and facebook the next, then your application would see these as tow distinct users (NB: RPX provides some protection for this by trying to remember the last authentication method your users used. It's not always perfect however).
79
-
80
- From Authlogic_RPX version 1.1.0 we have added built-in identity mapping and merging support. This is what we call 'internal' mapping. The legacy approach from 1.0.4 and earlier is still supported as an option. This mapping mode is called 'none'.
81
-
82
- The JanRain RPXnow service has its own identity mapping implementation, but only available for paid accounts. This is still not supported directly by Authlogic_RPX, but is something we'd like to get into a future version.
83
-
84
- === Chosing Your Mapping Mode
85
-
86
- When you configure Authlogic_RPX, you will need to decide which mapping mode to use.
87
-
88
- The options are:
89
- * :none - will use legacy/1.0.4 identity management with no mapping support. RPX identifiers are stored as a new attribute of your User model
90
- * :internal - uses Authlogic_RPX-based mapping. RPX identifiers are stored in a new model called RPXIdentifier. This model is completely private to Authlogic_RPX and you will not need to code anything specifically for it.
91
- * :rpxnow - currently not implemented; reserved for future use
92
-
93
-
94
- ==== Upgrading from Authlogic_RPX 1.0.4 or earlier
95
-
96
- In Authlogic_RPX v1.0.4 and earlier, the rpx_identifier was stored in the user model, and identity mapping was not supported.
97
-
98
- If you are upgrading to 1.1.0 or later and wish to start using internal mapping:
99
- * Use the add_authlogic_rpx_migration generator to create the migration to support the new RPXIdentifiers model
100
- * It is NOT necessary to migrate the rpx_identifiers.
101
- * DO NOT remove the legacy rpx_identifier column from your existing user model. The Authlogic_RPX code will migrate users to the new database structure as and when they login.
102
- * You may wish to explicitly set account_mapping_mode to :internal in the User model (it saves a few cycles over the default :auto).
103
-
104
- e.g.
105
-
106
- class User < ActiveRecord::Base
107
- acts_as_authentic do |c|
108
- c.account_mapping_mode :internal
109
- end
110
- end
111
-
112
- If you are upgrading to 1.1.0 or later and wish to continue using the legacy/1.0.4 approach (i.e. no mapping):
113
- * You will already have the rpx_identifier in your user model. DO NOT create any new migrations.
114
- * Just upgrade the gem and all should continue to work as before
115
- * You may wish to explicitly set account_mapping_mode to :none in the User model (it saves a few cycles over the default :auto).
116
-
117
- e.g.
118
-
119
- class User < ActiveRecord::Base
120
- acts_as_authentic do |c|
121
- c.account_mapping_mode :none
122
- end
123
- end
124
-
125
- == The Step-by-Step Guide to Using Authlogic_RPX
126
-
127
- <i>Note: in what follows, the user model is called User and the session controller takes the name UserSession (the authlogic convention). You are not restricted to these names - could be Member and MemberSession for example - but for simplicity, this documentation will stick to using the "User" convention.</i>
128
-
129
- The main steps for enabling Authlogic_RPX:
130
- * 1. Enable RPX for your user model
131
- * 2. Add RPX configuration for the Authlogic session model
132
- * 3. Add custom user profile mapping (optional)
133
- * 4. Add application controller helpers: current_user, current_user_session
134
- * 5. Setup the Authlogic session controller
135
- * 6. Setup the Authlogic user controller
136
- * 7. Use view helpers to provide login links
137
- * 8. Allow users to "Add RPX" to existing accounts (optional)
138
- * 9. Customise Account Merge Behaviour (optional)
139
-
140
-
141
- === 1. Enable RPX for your user model
142
-
143
- The user model will have a has_many relationship with a new model, called RPXIdentifier.
144
- A generator is provider to create the necessary migration:
145
-
146
- ruby script/generate add_authlogic_rpx_migration [mapping:mapping_mode] [user_model:model_name]
147
-
148
- The generator takes two optional parameters: mapping and user_model.
149
-
150
- The mapping_mode parameter indicates which style of Authlogic_RPX-supported identity mapping should be used. The default mapping_mode is 'internal' Allowed values for mapping_mode are:
151
- * none (disables authlogic_rpx identity mapping. This is the same behaviour as in authlogic_rpx version 1.0.4 and earlier)
152
- * internal (enables authlogic_rpx internal identity mapping. This behaviour was introduced in version 1.1.0)
153
-
154
- The user_model parameter specifies the name of the user/member model in your application. The default model_name is 'User'. e.g. to generate the RPX migration where the user model is called 'Member' and you do not want to support identity mapping:
155
-
156
- ruby script/generate add_authlogic_rpx_migration mapping:none user_model:member
157
-
158
- You may need to customise the migration file to remove database constraints on other fields if they will be unused in the RPX case
159
- (e.g. crypted_password and password_salt to make password authentication optional).
160
-
161
- If you are using auto-registration, you must also remove any database constraints for fields that will be automatically mapped
162
- (see notes in "3. Add custom user profile mapping during auto-registration")
163
-
164
- ==== Sample Migration Generated Script (using internal mapping)
165
-
166
- The following command will generate a migration for the case where you want to use authlogic_rpx internal mapping and your user model is called 'User':
167
-
168
- ruby script/generate add_authlogic_rpx_migration mapping:internal user_model:user
169
-
170
- The migration script will appear like this:
171
-
172
- class AddAuthlogicRpxMigration < ActiveRecord::Migration
173
- def self.up
174
- create_table :rpx_identifiers do |t|
175
- t.string :identifier, :null => false
176
- t.string :provider_name
177
- t.integer :user_id, :null => false
178
- t.timestamps
179
- end
180
- add_index :rpx_identifiers, :identifier, :unique => true, :null => false
181
- add_index :rpx_identifiers, :user_id, :unique => false, :null => false
182
-
183
- # == Customisation may be required here ==
184
- # You may need to remove database constraints on other fields if they will be unused in the RPX case
185
- # (e.g. crypted_password and password_salt to make password authentication optional).
186
- # If you are using auto-registration, you must also remove any database constraints for fields that will be automatically mapped
187
- # e.g.:
188
- #change_column :users, :crypted_password, :string, :default => nil, :null => true
189
- #change_column :users, :password_salt, :string, :default => nil, :null => true
190
-
191
- end
192
-
193
- def self.down
194
- drop_table :rpx_identifiers
195
-
196
- # == Customisation may be required here ==
197
- # Restore user model database constraints as appropriate
198
- # e.g.:
199
- #[:crypted_password, :password_salt].each do |field|
200
- # User.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
201
- # change_column :users, field, :string, :default => "", :null => false
202
- #end
203
-
204
- end
205
- end
206
-
207
- {See the source for the sample 20091227051253_add_authlogic_rpx_migration.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/db/migrate/20091227051253_add_authlogic_rpx_migration.rb].
208
-
209
- ==== Sample Migration Generated Script (using no mapping)
210
-
211
- The following command will generate a migration for the case where you don't want to use authlogic_rpx mapping and your user model is called 'Member':
212
-
213
- ruby script/generate add_authlogic_rpx_migration mapping:none user_model:member
214
-
215
- The migration script will appear like this:
216
-
217
- class AddAuthlogicRpxMigration < ActiveRecord::Migration
218
-
219
- def self.up
220
- add_column :members, :rpx_identifier, :string
221
- add_index :members, :rpx_identifier
222
-
223
- # == Customisation may be required here ==
224
- # You may need to remove database constraints on other fields if they will be unused in the RPX case
225
- # (e.g. crypted_password and password_salt to make password authentication optional).
226
- # If you are using auto-registration, you must also remove any database constraints for fields that will be automatically mapped
227
-
228
- # e.g.:
229
- #change_column :members, :crypted_password, :string, :default => nil, :null => true
230
- #change_column :members, :password_salt, :string, :default => nil, :null => true
231
-
232
- end
233
-
234
- def self.down
235
- remove_column :members, :rpx_identifier
236
-
237
- # == Customisation may be required here ==
238
- # Restore user model database constraints as appropriate
239
- # e.g.:
240
- #[:crypted_password, :password_salt].each do |field|
241
- # Member.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
242
- # change_column :members, field, :string, :default => "", :null => false
243
- #end
244
-
245
- end
246
- end
247
-
248
- ==== Configuring the User model
249
-
250
- The user model then needs to be tagged with "acts_as_authentic". This is the minimal configuration:
251
-
252
- class User < ActiveRecord::Base
253
- acts_as_authentic
254
- end
255
-
256
- Two RPX-specific user configuration options are available.
257
- * account_merge_enabled: true/false. Enables/disables user auto-registration (disabled by default)
258
- * account_mapping_mode: :auto/:none/:internal. Sets the Authlogic_RPX identity mapping mode (:auto by default)
259
-
260
- The account_mapping_mode options are defined as follows:
261
- * :auto - will select the correct mapping mode based on the table structures you have provisioned in the application
262
- * :none - will use legacy/1.0.4 identity management with no mapping support. RPX identifiers are stored as a new attribute of your User model
263
- * :internal - uses Authlogic_RPX-based mapping. RPX identifiers are stored in a new model called RPXIdentifier. This model is completely private to Authlogic_RPX and you will not need to code anything specifically for it.
264
- * :rpxnow - currently not implemented; reserved for future use.
265
-
266
- For example, the following shows how to set standard Authlogic configurations (validations_scope), enables RPX account merging, and specifies :internal account mapping:
267
-
268
- class User < ActiveRecord::Base
269
- acts_as_authentic do |c|
270
- c.validations_scope = :company_id # for available Authlogic options see documentation in the various Config modules of Authlogic::ActsAsAuthentic
271
-
272
- # enable Authlogic_RPX account merging (false by default, if this statement is not present)
273
- c.account_merge_enabled true
274
-
275
- # set Authlogic_RPX account mapping mode
276
- c.account_mapping_mode :internal
277
-
278
- end # block optional
279
-
280
- end
281
-
282
- {See the source for the sample user.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user.rb].
283
-
284
- NB: The RPXIdentifier model is included in the authlogic_rpx gem and does not need to be added to your project.
285
-
286
- === 2. Add RPX configuration for the Authlogic session model
287
-
288
- Authlogic provides a helper to create the session model:
289
-
290
- script/generate session user_session
291
-
292
- The minimum configuration required is to add your RPX_API_KEY:
293
-
294
- class UserSession < Authlogic::Session::Base
295
- rpx_key RPX_API_KEY
296
- end
297
-
298
- Get an API key by registering your application at {RPX}[http://rpxnow.com/]. A free "Basic" account is available, in addition to paid enhanced versions. All work with Authlogic_RPX.
299
-
300
- You probably don't want to put your API key in directly. A recommended approach is to set the key as an environment variable, and then set it as a constant in config/environment.rb:
301
-
302
- RPX_API_KEY = ENV['RPX_API_KEY']
303
-
304
- Two additional RPX-specific session configuration options are available.
305
- * auto_register: enable/disable user auto-registration (enabled by default)
306
- * rpx_extended_info: enable/disable extended profile information in the RPX authentication (disabled by default)
307
-
308
- For example, to disable auto-registration and enable extended info:
309
-
310
- class UserSession < Authlogic::Session::Base
311
- rpx_key RPX_API_KEY
312
- auto_register false
313
- rpx_extended_info
314
- end
315
-
316
- {See the source for the sample user_session.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user_session.rb].
317
-
318
- === 3. Add custom user profile mapping (optional)
319
-
320
- Authlogic_rpx provides three hooks for mapping information from the RPX profile into your application's user model:
321
-
322
- * map_rpx_data: user profile mapping during auto-registration
323
- * map_rpx_data_each_login: user profile mapping during login
324
- * map_added_rpx_data: user profile mapping when adding RPX to an existing account
325
-
326
- See https://rpxnow.com/docs#profile_data for the definition of available attributes in the RPX profile.
327
-
328
- ==== 3a. map_rpx_data: user profile mapping during auto-registration
329
-
330
- When users auto-register, profile data from RPX is available to be inserted in the user's record on your site. By default, authlogic_rpx will map the username and email fields.
331
-
332
- If you have other fields you want to map, you can provide your own implementation of the map_rpx_data method in the UserSession model. In that method, you will be updating the "self.attempted_record" object, with information from the "@rpx_data" object. See the {RPX documentation}[https://rpxnow.com/docs#profile_data] to find out about the set of information that is available.
333
-
334
- class UserSession < Authlogic::Session::Base
335
- rpx_key RPX_API_KEY
336
- rpx_extended_info
337
-
338
- private
339
-
340
- # map_rpx_data maps additional fields from the RPX response into the user object
341
- # override this in your session controller to change the field mapping
342
- # see https://rpxnow.com/docs#profile_data for the definition of available attributes
343
- #
344
- def map_rpx_data
345
- # map core profile data using authlogic indirect column names
346
- self.attempted_record.send("#{klass.login_field}=", @rpx_data['profile']['preferredUsername'] ) if attempted_record.send(klass.login_field).blank?
347
- self.attempted_record.send("#{klass.email_field}=", @rpx_data['profile']['email'] ) if attempted_record.send(klass.email_field).blank?
348
-
349
- # map some other columns explicitly
350
- self.attempted_record.fullname = @rpx_data['profile']['displayName'] if attempted_record.fullname.blank?
351
-
352
- if rpx_extended_info?
353
- # map some extended attributes
354
- end
355
- end
356
-
357
- end
358
-
359
-
360
- WARNING: if you are using auto-registration, any fields you map should NOT have constraints enforced at the database level.
361
- Authlogic_rpx will optimistically attempt to save the user record during registration, and violating a database constraint will cause the authentication/registration to fail.
362
-
363
- You can/should enforce any required validations at the model level e.g.
364
-
365
- validates_uniqueness_of :username, :case_sensitive => false
366
-
367
- This will allow the auto-registration to proceed, and the user can be given a chance to rectify the validation errors on your user profile page.
368
-
369
- If it is not acceptable in your application to have user records created with potential validation errors in auto-populated fields, you will need to override map_rpx_data and implement whatever special handling makes sense in your case. For example:
370
-
371
- * directly check for uniqueness and other validation requirements
372
- * automatically "uniquify" certain fields like username
373
- * save conflicting profile information to "pending user review" columns or a seperate table
374
-
375
- {See the source for the sample user_session.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user_session.rb].
376
-
377
- ==== 3b. map_rpx_data_each_login: user profile mapping during login
378
-
379
- map_rpx_data_each_login provides a hook to allow you to map RPX profile information every time the user logs in.
380
-
381
- By default, nothing is mapped. If you have other fields you want to map, you can provide your own implementation of the map_rpx_data_each_login method in the UserSession model.
382
-
383
- This would mainly be used to update relatively volatile information that you are maintaining in the user model (such as profile image url)
384
-
385
- In the map_rpx_data_each_login procedure, you will be writing to fields of the "self.attempted_record" object, pulling data from the @rpx_data object. For example:
386
-
387
- def map_rpx_data_each_login
388
- # we'll always update photo_url
389
- self.attempted_record.photo_url = @rpx_data['profile']['photo']
390
- end
391
-
392
- {See the source for the sample user_session.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user_session.rb].
393
-
394
-
395
- ==== 3c. map_added_rpx_data: user profile mapping when adding RPX to an existing account
396
-
397
- map_added_rpx_data maps additional fields from the RPX response into the user object during the "add RPX to existing account" process.
398
-
399
- Override this in your user model to perform field mapping as may be desired.
400
- Provide your own implementation of the map_added_rpx_data method in the User model (NOT UserSession, unlike for map_rpx_data and map_rpx_data_each_login).
401
-
402
- In the map_added_rpx_data procedure, you will be writing to fields of the "self" object, pulling data from the rpx_data parameter. For example:
403
-
404
- def map_added_rpx_data( rpx_data )
405
- # map some additional fields, e.g. photo_url
406
- self.photo_url = rpx_data['profile']['photo'] if photo_url.blank?
407
- end
408
-
409
- {See the source for the sample user.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user.rb].
410
-
411
-
412
- === 4. Add application controller helpers: current_user, current_user_session
413
-
414
- We'll add current_user and current_user_session helpers. These can then be used in controllers and views to get a handle on the "current" logged in user.
415
-
416
- class ApplicationController < ActionController::Base
417
- helper :all # include all helpers, all the time
418
- protect_from_forgery # See ActionController::RequestForgeryProtection for details
419
-
420
- # Scrub sensitive parameters from your log
421
- filter_parameter_logging :password, :password_confirmation
422
-
423
- helper_method :current_user, :current_user_session
424
-
425
- private
426
-
427
- def current_user_session
428
- return @current_user_session if defined?(@current_user_session)
429
- @current_user_session = UserSession.find
430
- end
431
-
432
- def current_user
433
- return @current_user if defined?(@current_user)
434
- @current_user = current_user_session && current_user_session.record
435
- end
436
- end
437
-
438
- {See the source for the sample user_session_controller.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/controllers/application_controller.rb].
439
-
440
-
441
- === 5. Setup the Authlogic session controller
442
-
443
- If you don't already have a user session controller, create one. There are four actions of significance for authlogic_rpx:
444
-
445
- $ script/generate controller user_sessions index new create destroy
446
-
447
- {See the source for the sample user_session_controller.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/controllers/user_sessions_controller.rb].
448
-
449
- In config/routes.rb we can define the standard routes for this controller and two named routes for the main login/out (or singin/out if you prefer that terminology):
450
-
451
- map.signin "signin", :controller => "user_sessions", :action => "new"
452
- map.signout "signout", :controller => "user_sessions", :action => "destroy"
453
- map.resources :user_sessions
454
-
455
- ==== index
456
- This is where RPX will return to if the user cancelled the login process, so it needs to be handled. You probably just want to redirect the user to an appropriate alternative:
457
-
458
- def index
459
- redirect_to current_user ? root_url : new_user_session_url
460
- end
461
-
462
- ==== new
463
- Typically used to render a login form
464
-
465
- def new
466
- @user_session = UserSession.new
467
- end
468
-
469
- ==== create
470
- This is where the magic happens for authentication. Authlogic hides all the underlying wiring, and you just need to "save" the session!
471
-
472
- Authlogic_rpx provides two additional methods that you might want to use to tailor you application behaviour:
473
- * new_registration? - if a new registration, e.g. force them to go via a registration follow-up page
474
- * registration_complete? - if registration details not complete, e.g. bounce the user over the profile editing page
475
-
476
- def create
477
- @user_session = UserSession.new(params[:user_session])
478
- if @user_session.save
479
- if @user_session.new_registration?
480
- flash[:notice] = "Welcome! As a new user, please review your registration details before continuing.."
481
- redirect_to edit_user_path( :current )
482
- else
483
- if @user_session.registration_complete?
484
- flash[:notice] = "Successfully signed in."
485
- redirect_back_or_default articles_path
486
- else
487
- flash[:notice] = "Welcome back! Please complete required registration details before continuing.."
488
- redirect_to edit_user_path( :current )
489
- end
490
- end
491
- else
492
- flash[:error] = "Failed to login or register."
493
- redirect_to new_user_session_path
494
- end
495
- end
496
-
497
- ==== destroy
498
- The logout action..
499
-
500
- def destroy
501
- @user_session = current_user_session
502
- @user_session.destroy if @user_session
503
- flash[:notice] = "Successfully signed out."
504
- redirect_to articles_path
505
- end
506
-
507
-
508
- === 6. Setup the Authlogic user controller
509
-
510
- The users controller handles the actual user creation and editing actions. In it's standard form, it looks like any other controller with an underlying ActiveRecord model.
511
-
512
- There are five basic actions to consider. If you don't already have a controller, create it:
513
-
514
- $ script/generate controller users new create edit show update
515
-
516
- {See the source for the sample users_controller.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/controllers/users_controller.rb].
517
-
518
- The users controller just needs standard routes defined in config/routes.rb:
519
-
520
- map.resources :users
521
-
522
- ==== new
523
- Stock standard form for a user to register on the site. Only required if you will allow users to register without using RPX auto-registration (using standard password authentication).
524
-
525
- def new
526
- @user = User.new
527
- end
528
-
529
- ==== create
530
- As for new, stock standard and only required if you will allow users to register without using RPX auto-registration.
531
-
532
- def create
533
- @user = User.new(params[:user])
534
- if @user.save
535
- flash[:notice] = "Successfully registered user."
536
- redirect_to articles_path
537
- else
538
- render :action => 'new'
539
- end
540
- end
541
-
542
- ==== show
543
- Display's the user's profile. Uses the current_user helper that we'll include in the application controller.
544
-
545
- def show
546
- @user = current_user
547
- end
548
-
549
- ==== edit
550
- Allows the user to edit their profile. Calling valid? will ensure any validation errors are highlighted. This can be relevant with RPX since auto-registration may not include all the profile data you want to make "mandatory" for normal users.
551
-
552
- def edit
553
- @user = current_user
554
- @user.valid?
555
- end
556
-
557
- ==== update
558
- Handles the submission of the edit form. Again, uses the current_user helper that we'll include in the application controller.
559
-
560
- def update
561
- @user = current_user
562
- @user.attributes = params[:user]
563
- if @user.save
564
- flash[:notice] = "Successfully updated user."
565
- redirect_back_or_default articles_path
566
- else
567
- render :action => 'edit'
568
- end
569
- end
570
-
571
-
572
- === 7. Use view helpers to provide login links
573
-
574
- So how to put a "login" link on your page? Two helper methods are provided:
575
- * <b>rpx_popup</b> helper to insert a link to pop-up RPX login
576
- * <b>rpx_embed</b> helper to insert an embedded iframe RPX login form
577
-
578
- Each takes an options hash:
579
- * <tt>link_text:</tt> text to use in the link (only used by rpx_popup)
580
- * <tt>app_name:</tt> name of the application you set when registering your service at rpxnow.com (will be prepended to RPX domain and used in RPX dialogues)
581
- * <tt>return_url:</tt> url for the RPX callback (e.g. user_sessions_url)
582
- * <tt>add_rpx:</tt> Optional. If true, requests RPX callback to add to current session. Else runs normal authentication process (default). See "7. Allow users to "Add RPX" to existing accounts"
583
- * <tt>unobtrusive:</tt> true/false; sets javascript style for link. unobtrusive=true links directly to rpxnow site, whereas unobtrusive=false does a javascript pop-over. Default: true (only used by rpx_popup)
584
-
585
- For example, to insert a login link in a navigation bar is as simple as this:
586
-
587
- <div id="user_nav">
588
- <%= link_to "Home", root_path %> |
589
- <% if current_user %>
590
- <%= link_to "Profile", user_path(:current) %> |
591
- <%= link_to "Sign out", signout_path %>
592
- <% else %>
593
- <%= rpx_popup( :link_text => "Register/Sign in with RPX..", :app_name => "rails-authlogic-rpx-sample", :return_url => user_sessions_url, :unobtrusive => false ) %>>
594
- <% end %>
595
- </div>
596
-
597
- === 8. Allow users to "Add RPX" to existing accounts (optional)
598
-
599
- If you got this far and have a working application, you are ready to go, especially if you only plan to support RPX authentication.
600
-
601
- However, if you support other authentication methods (e.g. by password), you probably want the ability to let user's add RPX to an existing account. This is not possible by default, however adding it is simply a matter of providing another method on your user controller.
602
-
603
- The route may be called anything you like. Let's use "addrpxauth" for example.
604
-
605
- # This action has the special purpose of receiving an update of the RPX identity information
606
- # for current user - to add RPX authentication to an existing non-RPX account.
607
- # RPX only supports :post, so this cannot simply go to update method (:put)
608
- def addrpxauth
609
- @user = current_user
610
- if @user.save
611
- flash[:notice] = "Successfully added RPX authentication for this account."
612
- render :action => 'show'
613
- else
614
- render :action => 'edit'
615
- end
616
- end
617
-
618
- {This is demonstrated in the sample users_controller.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/controllers/users_controller.rb].
619
-
620
- You'll note this is almost identical to the "update". The main difference is that it needs to be enabled for :post by RPX. In config/routes.rb:
621
-
622
- map.addrpxauth "addrpxauth", :controller => "users", :action => "addrpxauth", :method => :post
623
-
624
- To make an "Add RPX authentication for this account.." link, use rpx_popup as for normal RPX login, but set the return_url to the "addrpxauth" callback you have provided, and set the option :add_rpx to tru:
625
-
626
- <%= rpx_popup( :link_text => "Add RPX authentication for this account..", :app_name => RPX_APP_NAME, :return_url => addrpxauth_url, :add_rpx => true, :unobtrusive => false ) %>
627
-
628
-
629
- === 9. Customise Account Merge Behaviour (optional)
630
-
631
- Account merging is disabled by default. It is enabled by setting account_merge_enabled to true in the User model:
632
-
633
- class User < ActiveRecord::Base
634
- acts_as_authentic do |c|
635
- c.account_merge_enabled true
636
- end
637
- end
638
-
639
-
640
- Account merging is applicable if you have allowed users to add RPX to an existing accounts (see 8. Allow users to "Add RPX" to existing accounts). When merging is enabled, Authlogic_RPX will migrate the RPX login identifier(s) from other users who had previously claimed the identifiers now being used.
641
-
642
- For example, take the following scenario:
643
- * Joe registers and creates an account using RPX identifier A (say, a twitter account)
644
- * Joseph registers and creates an account using RPX identifier B (say, an OpenID account)
645
- * It so happens that Joe and Joseph are the same person...
646
- * Joseph signs in with RPX identifier B, and uses the "Add RPX" feature to attempt to add RPX identifier A to his account
647
- * At this point, if you have account_merge_enabled disabled (the default), it will fail since the id is already used by Joe
648
- * If you have account_merge_enabled enabled, Authlogic_RPX will transfer the RPX identifier A to Joseph's account
649
- * If you are using account mapping = :none, RPX identifier A will just replace RPX identifier B for Joseph
650
- * If you are using account mapping = :internal, RPX identifier A will be added to Joseph's account (he can now login with both A and B)
651
- * The default behaviour of account mapping will leave Joe's account in place (but with no way to login via RPX). Authlogic_RPX does not merge any other details (e.g. application data ownership)
652
-
653
- Authlogic_rpx provides two hooks for customising the account merge behaviour to handle things like migration of application objects and cleaning up old accounts:
654
-
655
- * before_merge_rpx_data: called before the RPX identifiers are transfered. It provides a hook for application developers to perform data migration prior to the merging of user accounts.
656
- * after_merge_rpx_data: called after the RPX identifiers are transfered. It provides a hook for application developers to perform account clean-up after (perhaps delete or disable to account merged from)
657
-
658
-
659
- The Authlogic_RPX sample application provides an example of migrating application objects and cleaning up obsolete accounts. From the user model:
660
-
661
- # before_merge_rpx_data provides a hook for application developers to perform data migration prior to the merging of user accounts.
662
- # This method is called just before authlogic_rpx merges the user registration for 'from_user' into 'to_user'
663
- # Authlogic_RPX is responsible for merging registration data.
664
- #
665
- # By default, it does not merge any other details (e.g. application data ownership)
666
- #
667
- def before_merge_rpx_data( from_user, to_user )
668
- RAILS_DEFAULT_LOGGER.info "in before_merge_rpx_data: migrate articles and comments from #{from_user.username} to #{to_user.username}"
669
- to_user.articles << from_user.articles
670
- to_user.comments << from_user.comments
671
- end
672
-
673
- # after_merge_rpx_data provides a hook for application developers to perform account clean-up after authlogic_rpx has
674
- # migrated registration details.
675
- #
676
- # By default, does nothing. It could, for example, be used to delete or disable the 'from_user' account
677
- #
678
- def after_merge_rpx_data( from_user, to_user )
679
- RAILS_DEFAULT_LOGGER.info "in after_merge_rpx_data: destroy #{from_user.inspect}"
680
- from_user.destroy
681
- end
682
-
683
- {See the sample user.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user.rb].
684
-
685
- === Ready to try it?
686
-
687
- That's all there is. To see Authlogic_RPX in action, check out the demonstration Rails application:
688
- * <b>Live Demonstration Site:</b> [http://rails-authlogic-rpx-sample.heroku.com]
689
- * <b>Demonstration site source repository:</b> [http://github.com/tardate/rails-authlogic-rpx-sample]
690
-
691
-
692
- == Improving Authlogic_RPX: next steps; how to help
693
-
694
- Authlogic_RPX is open source and hosted on {github}[http://github.com/tardate/authlogic_rpx]. Developer's are welcome to fork and play - if you have improvements or bug fixes, just send a request to pull from your fork.
695
-
696
- If you have issues or feedback, please log them in the {issues list on github}[http://github.com/tardate/authlogic_rpx/issues]
697
-
698
- Some of the improvements currently on the radar:
699
- * Implement/verify support for RPX "paid" service features of their "Plus" and "Pro" accounts (to date, only tested with free RPX "Basic" account)
700
-
701
-
702
- == Note on programmatically grabbing an authenticated session
703
-
704
- If you need to programmatically perform proxy authentication as a specific user (e.g. to run a batch process on behalf of the user), authlogic provides the necessary capability and this can be used with RPX-authenticated users too:
705
-
706
- app.get "/" # force Authlogic::Session::Base.controller activation
707
- user = User.find(:first)
708
- session = UserSession.create(user, true) # skip authentication and log the user in directly, the true means "remember me"
709
- session.valid?
710
- => true
711
-
712
-
713
- == Internals
714
-
715
- Some design principles:
716
- * Attempted to stay as close to binarylogic's "unobtrusive authentication" sensibility in Authlogic design
717
- * All direct RPX processing is handled in the AuthlogicRpx::Session class (not in the ActiveRecord model)
718
- * It uses the plug-in architecture introduced in Authlogic v2.0.
719
-
720
- ==== building the gem
721
-
722
- * increment the version in lib/authlogic_rpx/version.rb
723
- * update gem version refs in README.rdoc
724
- * update CHANGELOG.rdoc
725
-
726
- Build and distribute (the gemcutter way):
727
-
728
- # update manifest file
729
- $ rake manifest
730
- # update gemspec
731
- $ rake build_gemspec
732
- # build the gem
733
- gem build authlogic_rpx.gemspec
734
- # push the gem to gemcutter (e.g. for version 1.0.3)
735
- gem push authlogic_rpx-1.0.3.gem
736
-
737
-
738
- == Kudos and Kopywrite
739
-
740
- Thanks to {binarylogic}[http://github.com/binarylogic] for cleaning up authentication in rails by creating Authlogic in the first place and offering it to the community.
741
-
742
- The idea of adding RPX support to authlogic is not new. Some early ideas were found in the following projects, although it was decided not to base this implementation on a fork of these, since the approaches varied considerably:
743
- * <b>http://github.com/hunter/authlogic_rpx</b> an initial start, based on authlogic_openid and using rpx_now
744
- * <b>http://github.com/gampleman/authlogic_rpx/</b> similar, but including an implementation of the RPX api
745
-
746
- authlogic_rpx was created by Paul Gallagher (tardate.com) and released under the MIT license.
747
- Big thanks for contributions from {John}[http://gitub.com/jjb] and {Damir}[http://gitub.com/sidonath]
1
+ = Authlogic_RPX
2
+
3
+ == Purpose
4
+
5
+ Authlogic_RPX is an Authlogic extension library that provides support for authentication using the Janrain Engage (formerly RPX) multi-authentication service offered by JanRain. To use RPX, you must first register your application at {Janrain Engage}[http://rpxnow.com/]. A free "Basic" account is available, in addition to paid enhanced versions. All work with Authlogic_RPX.
6
+
7
+ Key features and capabilities:
8
+ * You can offer your users all the authentication methods supported by RPX (OpenID, Facebook, twitter, Google, Yahoo!, LinkedIn etc)
9
+ * Auto-registration by default following RPX authentication (can be disabled if required)
10
+ * View helpers to assist with inserting login fragments in pages
11
+ * Can co-exist with standard password authentication
12
+ * Allow users to enable RPX authentication for any existing password-enabled accounts
13
+ * Supports identity mapping and merging (allowing users to have multiple logins associated with one member record on your site)
14
+ * Supports Rails 2.3.x and 3.0.x
15
+
16
+
17
+ == Authlogic_RPX References
18
+
19
+ * <b>Authlogic_RPX gem repo:</b> [http://github.com/tardate/authlogic_rpx]
20
+ * <b>Authlogic_RPX issues and feedback:</b> [http://github.com/tardate/authlogic_rpx/issues]
21
+
22
+ The demonstration Rails application is where you can see Authlogic_RPX in action:
23
+
24
+ * <b>Live Demonstration Site:</b> [http://rails-authlogic-rpx-sample.heroku.com]
25
+ * <b>Demonstration site source repository (rails2 branch):</b> [http://github.com/tardate/rails-authlogic-rpx-sample]
26
+ * <b>Demonstration site source repository (rails3 branch):</b> [http://github.com/tardate/rails-authlogic-rpx-sample/tree/rails3]
27
+
28
+ == Authlogic and RPX References
29
+
30
+ * <b>Authlogic documentation:</b> [http://rdoc.info/projects/binarylogic/authlogic]
31
+ * <b>Authlogic repo:</b> [http://github.com/binarylogic/authlogic]
32
+ * <b>RPX documentation:</b> [https://rpxnow.com/docs]
33
+ * <b>RPX_now gem repo:</b> [http://github.com/grosser/rpx_now]
34
+
35
+
36
+ == Installing Authlogic_RPX gem
37
+
38
+ Three gems are required: authlogic, rpx_now, and authlogic_rpx. Install these as appropriate to your environment and preferences.
39
+
40
+ Currently tested versions:
41
+ * authlogic 2.1.6
42
+ * rpx_now 0.6.23
43
+ * authlogic_rpx 1.2.0
44
+
45
+
46
+ === 1. Direct gem installation
47
+
48
+ # installs authlogic and rpx_now gem dependencies
49
+ sudo gem install authlogic_rpx
50
+
51
+ === 2. Using Rails 2.3.x config.gems
52
+
53
+ Include in config/environment.rb:
54
+
55
+ config.gem 'authlogic_rpx', :version => '>= 1.2.0'
56
+
57
+ Then to install, run from the command line:
58
+
59
+ sudo rake gems:install
60
+
61
+
62
+ === 3. Using .gems file (e.g for heroku.com deployments)
63
+
64
+ Include in RAILS_ROOT/.gems:
65
+
66
+ authlogic_rpx --version '>= 1.2.0'
67
+
68
+
69
+ === 4. Using Bundler for Rails 3
70
+
71
+ Include in RAILS_ROOT/Gemfile
72
+
73
+ gem "authlogic_rpx", :version => '>= 1.2.0'
74
+
75
+
76
+ == About Authlogic_RPX
77
+
78
+ Using Authlogic_RPX is very similar to using standard authlogic, with the addition of just a few configuration options. So if you already have a project setup with authlogic, adding RPX support will be trivial.
79
+
80
+ An important capability to be aware of is "auto registration". This means that when a user has logged in with RPX, if an account does not already exist in your application, it will be automatically created. That is, there is no separate/special "register" step for users to go through before just signing in. You can disable this if you need, but for most sites that use RPX as a primary authentication mechanism, this is probably what you want to happen.
81
+
82
+ One of the main limitations of Authlogic_RPX versions up to 1.0.4 was that it did not include any specific support for identity mapping. This means that if a user signs in with twitter one day, and facebook the next, then your application would see these as tow distinct users (NB: RPX provides some protection for this by trying to remember the last authentication method your users used. It's not always perfect however).
83
+
84
+ From Authlogic_RPX version 1.1.0 we have added built-in identity mapping and merging support. This is what we call 'internal' mapping. The legacy approach from 1.0.4 and earlier is still supported as an option. This mapping mode is called 'none'.
85
+
86
+ The JanRain RPXnow service has its own identity mapping implementation, but only available for paid accounts. This is still not supported directly by Authlogic_RPX, but is something we'd like to get into a future version.
87
+
88
+ === Chosing Your Mapping Mode
89
+
90
+ When you configure Authlogic_RPX, you will need to decide which mapping mode to use.
91
+
92
+ The options are:
93
+ * :none - will use legacy/1.0.4 identity management with no mapping support. RPX identifiers are stored as a new attribute of your User model
94
+ * :internal - uses Authlogic_RPX-based mapping. RPX identifiers are stored in a new model called RPXIdentifier. This model is completely private to Authlogic_RPX and you will not need to code anything specifically for it.
95
+ * :rpxnow - currently not implemented; reserved for future use
96
+
97
+
98
+ ==== Upgrading from Authlogic_RPX 1.0.4 or earlier
99
+
100
+ In Authlogic_RPX v1.0.4 and earlier, the rpx_identifier was stored in the user model, and identity mapping was not supported.
101
+
102
+ If you are upgrading to 1.1.0 or later and wish to start using internal mapping:
103
+ * Use the add_authlogic_rpx_migration generator to create the migration to support the new RPXIdentifiers model
104
+ * It is NOT necessary to migrate the rpx_identifiers.
105
+ * DO NOT remove the legacy rpx_identifier column from your existing user model. The Authlogic_RPX code will migrate users to the new database structure as and when they login.
106
+ * You may wish to explicitly set account_mapping_mode to :internal in the User model (it saves a few cycles over the default :auto).
107
+
108
+ e.g.
109
+
110
+ class User < ActiveRecord::Base
111
+ acts_as_authentic do |c|
112
+ c.account_mapping_mode :internal
113
+ end
114
+ end
115
+
116
+ If you are upgrading to 1.1.0 or later and wish to continue using the legacy/1.0.4 approach (i.e. no mapping):
117
+ * You will already have the rpx_identifier in your user model. DO NOT create any new migrations.
118
+ * Just upgrade the gem and all should continue to work as before
119
+ * You may wish to explicitly set account_mapping_mode to :none in the User model (it saves a few cycles over the default :auto).
120
+
121
+ e.g.
122
+
123
+ class User < ActiveRecord::Base
124
+ acts_as_authentic do |c|
125
+ c.account_mapping_mode :none
126
+ end
127
+ end
128
+
129
+ == The Step-by-Step Guide to Using Authlogic_RPX
130
+
131
+ <i>Note: in what follows, the user model is called User and the session controller takes the name UserSession (the authlogic convention). You are not restricted to these names - could be Member and MemberSession for example - but for simplicity, this documentation will stick to using the "User" convention.</i>
132
+
133
+ The main steps for enabling Authlogic_RPX:
134
+ * 1. Enable RPX for your user model
135
+ * 2. Add RPX configuration for the Authlogic session model
136
+ * 3. Add custom user profile mapping (optional)
137
+ * 4. Add application controller helpers: current_user, current_user_session
138
+ * 5. Setup the Authlogic session controller
139
+ * 6. Setup the Authlogic user controller
140
+ * 7. Use view helpers to provide login links
141
+ * 8. Allow users to "Add RPX" to existing accounts (optional)
142
+ * 9. Customise Account Merge Behaviour (optional)
143
+
144
+
145
+ === 1. Enable RPX for your user model
146
+
147
+ The user model will have a has_many relationship with a new model, called RPXIdentifier.
148
+ A generator is provider to create the necessary migration:
149
+
150
+ ruby script/generate add_authlogic_rpx_migration [mapping:mapping_mode] [user_model:model_name]
151
+
152
+ The generator takes two optional parameters: mapping and user_model.
153
+
154
+ The mapping_mode parameter indicates which style of Authlogic_RPX-supported identity mapping should be used. The default mapping_mode is 'internal' Allowed values for mapping_mode are:
155
+ * none (disables authlogic_rpx identity mapping. This is the same behaviour as in authlogic_rpx version 1.0.4 and earlier)
156
+ * internal (enables authlogic_rpx internal identity mapping. This behaviour was introduced in version 1.1.0)
157
+
158
+ The user_model parameter specifies the name of the user/member model in your application. The default model_name is 'User'. e.g. to generate the RPX migration where the user model is called 'Member' and you do not want to support identity mapping:
159
+
160
+ ruby script/generate add_authlogic_rpx_migration mapping:none user_model:member
161
+
162
+ You may need to customise the migration file to remove database constraints on other fields if they will be unused in the RPX case
163
+ (e.g. crypted_password and password_salt to make password authentication optional).
164
+
165
+ If you are using auto-registration, you must also remove any database constraints for fields that will be automatically mapped
166
+ (see notes in "3. Add custom user profile mapping during auto-registration")
167
+
168
+ ==== Sample Migration Generated Script (using internal mapping)
169
+
170
+ The following command will generate a migration for the case where you want to use authlogic_rpx internal mapping and your user model is called 'User':
171
+
172
+ ruby script/generate add_authlogic_rpx_migration mapping:internal user_model:user
173
+
174
+ The migration script will appear like this:
175
+
176
+ class AddAuthlogicRpxMigration < ActiveRecord::Migration
177
+ def self.up
178
+ create_table :rpx_identifiers do |t|
179
+ t.string :identifier, :null => false
180
+ t.string :provider_name
181
+ t.integer :user_id, :null => false
182
+ t.timestamps
183
+ end
184
+ add_index :rpx_identifiers, :identifier, :unique => true, :null => false
185
+ add_index :rpx_identifiers, :user_id, :unique => false, :null => false
186
+
187
+ # == Customisation may be required here ==
188
+ # You may need to remove database constraints on other fields if they will be unused in the RPX case
189
+ # (e.g. crypted_password and password_salt to make password authentication optional).
190
+ # If you are using auto-registration, you must also remove any database constraints for fields that will be automatically mapped
191
+ # e.g.:
192
+ #change_column :users, :crypted_password, :string, :default => nil, :null => true
193
+ #change_column :users, :password_salt, :string, :default => nil, :null => true
194
+
195
+ end
196
+
197
+ def self.down
198
+ drop_table :rpx_identifiers
199
+
200
+ # == Customisation may be required here ==
201
+ # Restore user model database constraints as appropriate
202
+ # e.g.:
203
+ #[:crypted_password, :password_salt].each do |field|
204
+ # User.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
205
+ # change_column :users, field, :string, :default => "", :null => false
206
+ #end
207
+
208
+ end
209
+ end
210
+
211
+ {See the source for the sample 20091227051253_add_authlogic_rpx_migration.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/db/migrate/20091227051253_add_authlogic_rpx_migration.rb].
212
+
213
+ ==== Sample Migration Generated Script (using no mapping)
214
+
215
+ The following command will generate a migration for the case where you don't want to use authlogic_rpx mapping and your user model is called 'Member':
216
+
217
+ ruby script/generate add_authlogic_rpx_migration mapping:none user_model:member
218
+
219
+ The migration script will appear like this:
220
+
221
+ class AddAuthlogicRpxMigration < ActiveRecord::Migration
222
+
223
+ def self.up
224
+ add_column :members, :rpx_identifier, :string
225
+ add_index :members, :rpx_identifier
226
+
227
+ # == Customisation may be required here ==
228
+ # You may need to remove database constraints on other fields if they will be unused in the RPX case
229
+ # (e.g. crypted_password and password_salt to make password authentication optional).
230
+ # If you are using auto-registration, you must also remove any database constraints for fields that will be automatically mapped
231
+
232
+ # e.g.:
233
+ #change_column :members, :crypted_password, :string, :default => nil, :null => true
234
+ #change_column :members, :password_salt, :string, :default => nil, :null => true
235
+
236
+ end
237
+
238
+ def self.down
239
+ remove_column :members, :rpx_identifier
240
+
241
+ # == Customisation may be required here ==
242
+ # Restore user model database constraints as appropriate
243
+ # e.g.:
244
+ #[:crypted_password, :password_salt].each do |field|
245
+ # Member.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
246
+ # change_column :members, field, :string, :default => "", :null => false
247
+ #end
248
+
249
+ end
250
+ end
251
+
252
+ ==== Configuring the User model
253
+
254
+ The user model then needs to be tagged with "acts_as_authentic". This is the minimal configuration:
255
+
256
+ class User < ActiveRecord::Base
257
+ acts_as_authentic
258
+ end
259
+
260
+ Two RPX-specific user configuration options are available.
261
+ * account_merge_enabled: true/false. Enables/disables user auto-registration (disabled by default)
262
+ * account_mapping_mode: :auto/:none/:internal. Sets the Authlogic_RPX identity mapping mode (:auto by default)
263
+
264
+ The account_mapping_mode options are defined as follows:
265
+ * :auto - will select the correct mapping mode based on the table structures you have provisioned in the application
266
+ * :none - will use legacy/1.0.4 identity management with no mapping support. RPX identifiers are stored as a new attribute of your User model
267
+ * :internal - uses Authlogic_RPX-based mapping. RPX identifiers are stored in a new model called RPXIdentifier. This model is completely private to Authlogic_RPX and you will not need to code anything specifically for it.
268
+ * :rpxnow - currently not implemented; reserved for future use.
269
+
270
+ For example, the following shows how to set standard Authlogic configurations (validations_scope), enables RPX account merging, and specifies :internal account mapping:
271
+
272
+ class User < ActiveRecord::Base
273
+ acts_as_authentic do |c|
274
+ c.validations_scope = :company_id # for available Authlogic options see documentation in the various Config modules of Authlogic::ActsAsAuthentic
275
+
276
+ # enable Authlogic_RPX account merging (false by default, if this statement is not present)
277
+ c.account_merge_enabled true
278
+
279
+ # set Authlogic_RPX account mapping mode
280
+ c.account_mapping_mode :internal
281
+
282
+ end # block optional
283
+
284
+ end
285
+
286
+ {See the source for the sample user.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user.rb].
287
+
288
+ NB: The RPXIdentifier model is included in the authlogic_rpx gem and does not need to be added to your project.
289
+
290
+ === 2. Add RPX configuration for the Authlogic session model
291
+
292
+ Authlogic provides a helper to create the session model:
293
+
294
+ script/generate session user_session
295
+
296
+ The minimum configuration required is to add your RPX_API_KEY:
297
+
298
+ class UserSession < Authlogic::Session::Base
299
+ rpx_key RPX_API_KEY
300
+ end
301
+
302
+ Get an API key by registering your application at {RPX}[http://rpxnow.com/]. A free "Basic" account is available, in addition to paid enhanced versions. All work with Authlogic_RPX.
303
+
304
+ You probably don't want to put your API key in directly. A recommended approach is to set the key as an environment variable, and then set it as a constant in config/environment.rb:
305
+
306
+ RPX_API_KEY = ENV['RPX_API_KEY']
307
+
308
+ Two additional RPX-specific session configuration options are available.
309
+ * auto_register: enable/disable user auto-registration (enabled by default)
310
+ * rpx_extended_info: enable/disable extended profile information in the RPX authentication (disabled by default)
311
+
312
+ For example, to disable auto-registration and enable extended info:
313
+
314
+ class UserSession < Authlogic::Session::Base
315
+ rpx_key RPX_API_KEY
316
+ auto_register false
317
+ rpx_extended_info
318
+ end
319
+
320
+ {See the source for the sample user_session.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user_session.rb].
321
+
322
+ === 3. Add custom user profile mapping (optional)
323
+
324
+ Authlogic_rpx provides three hooks for mapping information from the RPX profile into your application's user model:
325
+
326
+ * map_rpx_data: user profile mapping during auto-registration
327
+ * map_rpx_data_each_login: user profile mapping during login
328
+ * map_added_rpx_data: user profile mapping when adding RPX to an existing account
329
+
330
+ See https://rpxnow.com/docs#profile_data for the definition of available attributes in the RPX profile.
331
+
332
+ ==== 3a. map_rpx_data: user profile mapping during auto-registration
333
+
334
+ When users auto-register, profile data from RPX is available to be inserted in the user's record on your site. By default, authlogic_rpx will map the username and email fields.
335
+
336
+ If you have other fields you want to map, you can provide your own implementation of the map_rpx_data method in the UserSession model. In that method, you will be updating the "self.attempted_record" object, with information from the "@rpx_data" object. See the {RPX documentation}[https://rpxnow.com/docs#profile_data] to find out about the set of information that is available.
337
+
338
+ class UserSession < Authlogic::Session::Base
339
+ rpx_key RPX_API_KEY
340
+ rpx_extended_info
341
+
342
+ private
343
+
344
+ # map_rpx_data maps additional fields from the RPX response into the user object
345
+ # override this in your session controller to change the field mapping
346
+ # see https://rpxnow.com/docs#profile_data for the definition of available attributes
347
+ #
348
+ def map_rpx_data
349
+ # map core profile data using authlogic indirect column names
350
+ self.attempted_record.send("#{klass.login_field}=", @rpx_data['profile']['preferredUsername'] ) if attempted_record.send(klass.login_field).blank?
351
+ self.attempted_record.send("#{klass.email_field}=", @rpx_data['profile']['email'] ) if attempted_record.send(klass.email_field).blank?
352
+
353
+ # map some other columns explicitly
354
+ self.attempted_record.fullname = @rpx_data['profile']['displayName'] if attempted_record.fullname.blank?
355
+
356
+ if rpx_extended_info?
357
+ # map some extended attributes
358
+ end
359
+ end
360
+
361
+ end
362
+
363
+
364
+ WARNING: if you are using auto-registration, any fields you map should NOT have constraints enforced at the database level.
365
+ Authlogic_rpx will optimistically attempt to save the user record during registration, and violating a database constraint will cause the authentication/registration to fail.
366
+
367
+ You can/should enforce any required validations at the model level e.g.
368
+
369
+ validates_uniqueness_of :username, :case_sensitive => false
370
+
371
+ This will allow the auto-registration to proceed, and the user can be given a chance to rectify the validation errors on your user profile page.
372
+
373
+ If it is not acceptable in your application to have user records created with potential validation errors in auto-populated fields, you will need to override map_rpx_data and implement whatever special handling makes sense in your case. For example:
374
+
375
+ * directly check for uniqueness and other validation requirements
376
+ * automatically "uniquify" certain fields like username
377
+ * save conflicting profile information to "pending user review" columns or a seperate table
378
+
379
+ {See the source for the sample user_session.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user_session.rb].
380
+
381
+ ==== 3b. map_rpx_data_each_login: user profile mapping during login
382
+
383
+ map_rpx_data_each_login provides a hook to allow you to map RPX profile information every time the user logs in.
384
+
385
+ By default, nothing is mapped. If you have other fields you want to map, you can provide your own implementation of the map_rpx_data_each_login method in the UserSession model.
386
+
387
+ This would mainly be used to update relatively volatile information that you are maintaining in the user model (such as profile image url)
388
+
389
+ In the map_rpx_data_each_login procedure, you will be writing to fields of the "self.attempted_record" object, pulling data from the @rpx_data object. For example:
390
+
391
+ def map_rpx_data_each_login
392
+ # we'll always update photo_url
393
+ self.attempted_record.photo_url = @rpx_data['profile']['photo']
394
+ end
395
+
396
+ {See the source for the sample user_session.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user_session.rb].
397
+
398
+
399
+ ==== 3c. map_added_rpx_data: user profile mapping when adding RPX to an existing account
400
+
401
+ map_added_rpx_data maps additional fields from the RPX response into the user object during the "add RPX to existing account" process.
402
+
403
+ Override this in your user model to perform field mapping as may be desired.
404
+ Provide your own implementation of the map_added_rpx_data method in the User model (NOT UserSession, unlike for map_rpx_data and map_rpx_data_each_login).
405
+
406
+ In the map_added_rpx_data procedure, you will be writing to fields of the "self" object, pulling data from the rpx_data parameter. For example:
407
+
408
+ def map_added_rpx_data( rpx_data )
409
+ # map some additional fields, e.g. photo_url
410
+ self.photo_url = rpx_data['profile']['photo'] if photo_url.blank?
411
+ end
412
+
413
+ {See the source for the sample user.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user.rb].
414
+
415
+
416
+ === 4. Add application controller helpers: current_user, current_user_session
417
+
418
+ We'll add current_user and current_user_session helpers. These can then be used in controllers and views to get a handle on the "current" logged in user.
419
+
420
+ class ApplicationController < ActionController::Base
421
+ helper :all # include all helpers, all the time
422
+ protect_from_forgery # See ActionController::RequestForgeryProtection for details
423
+
424
+ # Scrub sensitive parameters from your log
425
+ filter_parameter_logging :password, :password_confirmation
426
+
427
+ helper_method :current_user, :current_user_session
428
+
429
+ private
430
+
431
+ def current_user_session
432
+ return @current_user_session if defined?(@current_user_session)
433
+ @current_user_session = UserSession.find
434
+ end
435
+
436
+ def current_user
437
+ return @current_user if defined?(@current_user)
438
+ @current_user = current_user_session && current_user_session.record
439
+ end
440
+ end
441
+
442
+ {See the source for the sample user_session_controller.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/controllers/application_controller.rb].
443
+
444
+
445
+ === 5. Setup the Authlogic session controller
446
+
447
+ If you don't already have a user session controller, create one. There are four actions of significance for authlogic_rpx:
448
+
449
+ $ script/generate controller user_sessions index new create destroy
450
+
451
+ {See the source for the sample user_session_controller.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/controllers/user_sessions_controller.rb].
452
+
453
+ In config/routes.rb we can define the standard routes for this controller and two named routes for the main login/out (or singin/out if you prefer that terminology):
454
+
455
+ map.signin "signin", :controller => "user_sessions", :action => "new"
456
+ map.signout "signout", :controller => "user_sessions", :action => "destroy"
457
+ map.resources :user_sessions
458
+
459
+ ==== index
460
+ This is where RPX will return to if the user cancelled the login process, so it needs to be handled. You probably just want to redirect the user to an appropriate alternative:
461
+
462
+ def index
463
+ redirect_to current_user ? root_url : new_user_session_url
464
+ end
465
+
466
+ ==== new
467
+ Typically used to render a login form
468
+
469
+ def new
470
+ @user_session = UserSession.new
471
+ end
472
+
473
+ ==== create
474
+ This is where the magic happens for authentication. Authlogic hides all the underlying wiring, and you just need to "save" the session!
475
+
476
+ Authlogic_rpx provides two additional methods that you might want to use to tailor you application behaviour:
477
+ * new_registration? - if a new registration, e.g. force them to go via a registration follow-up page
478
+ * registration_complete? - if registration details not complete, e.g. bounce the user over the profile editing page
479
+
480
+ def create
481
+ @user_session = UserSession.new(params[:user_session])
482
+ if @user_session.save
483
+ if @user_session.new_registration?
484
+ flash[:notice] = "Welcome! As a new user, please review your registration details before continuing.."
485
+ redirect_to edit_user_path( :current )
486
+ else
487
+ if @user_session.registration_complete?
488
+ flash[:notice] = "Successfully signed in."
489
+ redirect_back_or_default articles_path
490
+ else
491
+ flash[:notice] = "Welcome back! Please complete required registration details before continuing.."
492
+ redirect_to edit_user_path( :current )
493
+ end
494
+ end
495
+ else
496
+ flash[:error] = "Failed to login or register."
497
+ redirect_to new_user_session_path
498
+ end
499
+ end
500
+
501
+ ==== destroy
502
+ The logout action..
503
+
504
+ def destroy
505
+ @user_session = current_user_session
506
+ @user_session.destroy if @user_session
507
+ flash[:notice] = "Successfully signed out."
508
+ redirect_to articles_path
509
+ end
510
+
511
+
512
+ === 6. Setup the Authlogic user controller
513
+
514
+ The users controller handles the actual user creation and editing actions. In it's standard form, it looks like any other controller with an underlying ActiveRecord model.
515
+
516
+ There are five basic actions to consider. If you don't already have a controller, create it:
517
+
518
+ $ script/generate controller users new create edit show update
519
+
520
+ {See the source for the sample users_controller.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/controllers/users_controller.rb].
521
+
522
+ The users controller just needs standard routes defined in config/routes.rb:
523
+
524
+ map.resources :users
525
+
526
+ ==== new
527
+ Stock standard form for a user to register on the site. Only required if you will allow users to register without using RPX auto-registration (using standard password authentication).
528
+
529
+ def new
530
+ @user = User.new
531
+ end
532
+
533
+ ==== create
534
+ As for new, stock standard and only required if you will allow users to register without using RPX auto-registration.
535
+
536
+ def create
537
+ @user = User.new(params[:user])
538
+ if @user.save
539
+ flash[:notice] = "Successfully registered user."
540
+ redirect_to articles_path
541
+ else
542
+ render :action => 'new'
543
+ end
544
+ end
545
+
546
+ ==== show
547
+ Display's the user's profile. Uses the current_user helper that we'll include in the application controller.
548
+
549
+ def show
550
+ @user = current_user
551
+ end
552
+
553
+ ==== edit
554
+ Allows the user to edit their profile. Calling valid? will ensure any validation errors are highlighted. This can be relevant with RPX since auto-registration may not include all the profile data you want to make "mandatory" for normal users.
555
+
556
+ def edit
557
+ @user = current_user
558
+ @user.valid?
559
+ end
560
+
561
+ ==== update
562
+ Handles the submission of the edit form. Again, uses the current_user helper that we'll include in the application controller.
563
+
564
+ def update
565
+ @user = current_user
566
+ @user.attributes = params[:user]
567
+ if @user.save
568
+ flash[:notice] = "Successfully updated user."
569
+ redirect_back_or_default articles_path
570
+ else
571
+ render :action => 'edit'
572
+ end
573
+ end
574
+
575
+
576
+ === 7. Use view helpers to provide login links
577
+
578
+ So how to put a "login" link on your page? Two helper methods are provided:
579
+ * <b>rpx_popup</b> helper to insert a link to pop-up RPX login
580
+ * <b>rpx_embed</b> helper to insert an embedded iframe RPX login form
581
+
582
+ Each takes an options hash:
583
+ * <tt>link_text:</tt> text to use in the link (only used by rpx_popup)
584
+ * <tt>app_name:</tt> name of the application you set when registering your service at rpxnow.com (will be prepended to RPX domain and used in RPX dialogues)
585
+ * <tt>return_url:</tt> url for the RPX callback (e.g. user_sessions_url)
586
+ * <tt>add_rpx:</tt> Optional. If true, requests RPX callback to add to current session. Else runs normal authentication process (default). See "7. Allow users to "Add RPX" to existing accounts"
587
+ * <tt>unobtrusive:</tt> true/false; sets javascript style for link. unobtrusive=true links directly to rpxnow site, whereas unobtrusive=false does a javascript pop-over. Default: true (only used by rpx_popup)
588
+
589
+ For example, to insert a login link in a navigation bar is as simple as this:
590
+
591
+ <div id="user_nav">
592
+ <%= link_to "Home", root_path %> |
593
+ <% if current_user %>
594
+ <%= link_to "Profile", user_path(:current) %> |
595
+ <%= link_to "Sign out", signout_path %>
596
+ <% else %>
597
+ <%= rpx_popup( :link_text => "Register/Sign in with RPX..", :app_name => RPX_APP_NAME, :return_url => user_sessions_url, :unobtrusive => false ) %>>
598
+ <% end %>
599
+ </div>
600
+
601
+ <b>NOTE:</b> One of the most common problems people encounter in testing out authlogic_rpx is to <b>not set the correct :app_name</b>.
602
+
603
+ <b>NOTE2:</b> Make sure the application name is entered all in lowercase. If you do not, it can cause SSL certificate errors to be displayed when logging in with certain browsers (notably Android 2.1 webkit).
604
+
605
+ === 8. Allow users to "Add RPX" to existing accounts (optional)
606
+
607
+ If you got this far and have a working application, you are ready to go, especially if you only plan to support RPX authentication.
608
+
609
+ However, if you support other authentication methods (e.g. by password), you probably want the ability to let user's add RPX to an existing account. This is not possible by default, however adding it is simply a matter of providing another method on your user controller.
610
+
611
+ The route may be called anything you like. Let's use "addrpxauth" for example.
612
+
613
+ # This action has the special purpose of receiving an update of the RPX identity information
614
+ # for current user - to add RPX authentication to an existing non-RPX account.
615
+ # RPX only supports :post, so this cannot simply go to update method (:put)
616
+ def addrpxauth
617
+ @user = current_user
618
+ if @user.save
619
+ flash[:notice] = "Successfully added RPX authentication for this account."
620
+ render :action => 'show'
621
+ else
622
+ render :action => 'edit'
623
+ end
624
+ end
625
+
626
+ {This is demonstrated in the sample users_controller.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/controllers/users_controller.rb].
627
+
628
+ You'll note this is almost identical to the "update". The main difference is that it needs to be enabled for :post by RPX. In config/routes.rb:
629
+
630
+ map.addrpxauth "addrpxauth", :controller => "users", :action => "addrpxauth", :method => :post
631
+
632
+ To make an "Add RPX authentication for this account.." link, use rpx_popup as for normal RPX login, but set the return_url to the "addrpxauth" callback you have provided, and set the option :add_rpx to tru:
633
+
634
+ <%= rpx_popup( :link_text => "Add RPX authentication for this account..", :app_name => RPX_APP_NAME, :return_url => addrpxauth_url, :add_rpx => true, :unobtrusive => false ) %>
635
+
636
+
637
+ === 9. Customise Account Merge Behaviour (optional)
638
+
639
+ Account merging is disabled by default. It is enabled by setting account_merge_enabled to true in the User model:
640
+
641
+ class User < ActiveRecord::Base
642
+ acts_as_authentic do |c|
643
+ c.account_merge_enabled true
644
+ end
645
+ end
646
+
647
+
648
+ Account merging is applicable if you have allowed users to add RPX to an existing accounts (see 8. Allow users to "Add RPX" to existing accounts). When merging is enabled, Authlogic_RPX will migrate the RPX login identifier(s) from other users who had previously claimed the identifiers now being used.
649
+
650
+ For example, take the following scenario:
651
+ * Joe registers and creates an account using RPX identifier A (say, a twitter account)
652
+ * Joseph registers and creates an account using RPX identifier B (say, an OpenID account)
653
+ * It so happens that Joe and Joseph are the same person...
654
+ * Joseph signs in with RPX identifier B, and uses the "Add RPX" feature to attempt to add RPX identifier A to his account
655
+ * At this point, if you have account_merge_enabled disabled (the default), it will fail since the id is already used by Joe
656
+ * If you have account_merge_enabled enabled, Authlogic_RPX will transfer the RPX identifier A to Joseph's account
657
+ * If you are using account mapping = :none, RPX identifier A will just replace RPX identifier B for Joseph
658
+ * If you are using account mapping = :internal, RPX identifier A will be added to Joseph's account (he can now login with both A and B)
659
+ * The default behaviour of account mapping will leave Joe's account in place (but with no way to login via RPX). Authlogic_RPX does not merge any other details (e.g. application data ownership)
660
+
661
+ Authlogic_rpx provides two hooks for customising the account merge behaviour to handle things like migration of application objects and cleaning up old accounts:
662
+
663
+ * before_merge_rpx_data: called before the RPX identifiers are transfered. It provides a hook for application developers to perform data migration prior to the merging of user accounts.
664
+ * after_merge_rpx_data: called after the RPX identifiers are transfered. It provides a hook for application developers to perform account clean-up after (perhaps delete or disable to account merged from)
665
+
666
+
667
+ The Authlogic_RPX sample application provides an example of migrating application objects and cleaning up obsolete accounts. From the user model:
668
+
669
+ # before_merge_rpx_data provides a hook for application developers to perform data migration prior to the merging of user accounts.
670
+ # This method is called just before authlogic_rpx merges the user registration for 'from_user' into 'to_user'
671
+ # Authlogic_RPX is responsible for merging registration data.
672
+ #
673
+ # By default, it does not merge any other details (e.g. application data ownership)
674
+ #
675
+ def before_merge_rpx_data( from_user, to_user )
676
+ to_user.articles << from_user.articles
677
+ to_user.comments << from_user.comments
678
+ end
679
+
680
+ # after_merge_rpx_data provides a hook for application developers to perform account clean-up after authlogic_rpx has
681
+ # migrated registration details.
682
+ #
683
+ # By default, does nothing. It could, for example, be used to delete or disable the 'from_user' account
684
+ #
685
+ def after_merge_rpx_data( from_user, to_user )
686
+ from_user.destroy
687
+ end
688
+
689
+ {See the sample user.rb}[http://github.com/tardate/rails-authlogic-rpx-sample/blob/master/app/models/user.rb].
690
+
691
+ === Ready to try it?
692
+
693
+ That's all there is. To see Authlogic_RPX in action, check out the demonstration Rails application:
694
+ * <b>Live Demonstration Site:</b> [http://rails-authlogic-rpx-sample.heroku.com]
695
+ * <b>Demonstration site source repository:</b> [http://github.com/tardate/rails-authlogic-rpx-sample]
696
+
697
+
698
+ == Improving Authlogic_RPX: next steps; how to help
699
+
700
+ Authlogic_RPX is open source and hosted on {github}[http://github.com/tardate/authlogic_rpx]. Developer's are welcome to fork and play - if you have improvements or bug fixes, just send a request to pull from your fork.
701
+
702
+ If you have issues or feedback, please log them in the {issues list on github}[http://github.com/tardate/authlogic_rpx/issues]
703
+
704
+ Some of the improvements currently on the radar:
705
+ * Implement/verify support for RPX "paid" service features of their "Plus" and "Pro" accounts (to date, only tested with free RPX "Basic" account)
706
+
707
+
708
+ == Note on programmatically grabbing an authenticated session
709
+
710
+ If you need to programmatically perform proxy authentication as a specific user (e.g. to run a batch process on behalf of the user), authlogic provides the necessary capability and this can be used with RPX-authenticated users too:
711
+
712
+ app.get "/" # force Authlogic::Session::Base.controller activation
713
+ user = User.find(:first)
714
+ session = UserSession.create(user, true) # skip authentication and log the user in directly, the true means "remember me"
715
+ session.valid?
716
+ => true
717
+
718
+
719
+ == Internals
720
+
721
+ Some design principles:
722
+ * Attempted to stay as close to binarylogic's "unobtrusive authentication" sensibility in Authlogic design
723
+ * All direct RPX processing is handled in the AuthlogicRpx::Session class (not in the ActiveRecord model)
724
+ * It uses the plug-in architecture introduced in Authlogic v2.0.
725
+
726
+ ==== building the gem
727
+
728
+ * increment the version in lib/authlogic_rpx/version.rb
729
+ * update gem version refs in README.rdoc
730
+ * update CHANGELOG.rdoc
731
+
732
+ Build and distribute (the gemcutter way):
733
+
734
+ # update gemspec
735
+ $ rake gemspec
736
+ # build the gem
737
+ $ rake build
738
+ # push the gem to gemcutter (e.g. for version 1.0.3)
739
+ gem push authlogic_rpx-1.0.3.gem
740
+
741
+
742
+ == Kudos and Kopywrite
743
+
744
+ Thanks to {binarylogic}[http://github.com/binarylogic] for cleaning up authentication in rails by creating Authlogic in the first place and offering it to the community.
745
+
746
+ The idea of adding RPX support to authlogic is not new. Some early ideas were found in the following projects, although it was decided not to base this implementation on a fork of these, since the approaches varied considerably:
747
+ * <b>http://github.com/hunter/authlogic_rpx</b> an initial start, based on authlogic_openid and using rpx_now
748
+ * <b>http://github.com/gampleman/authlogic_rpx/</b> similar, but including an implementation of the RPX api
749
+
750
+ authlogic_rpx was created by Paul Gallagher (tardate.com) and released under the MIT license.
751
+ Big thanks for contributions from {Joris}[http://github.com/trooster], {John}[http://gitub.com/jjb], {Damir}[http://gitub.com/sidonath], {Ben}[http://github.com/Empact]