Empact-authlogic_rpx 1.1.8 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,37 +1,37 @@
1
1
  module AuthlogicRpx
2
- module Helper
2
+ module Helper
3
3
 
4
- # helper to insert an embedded iframe RPX login
5
- # takes options hash:
6
- # * <tt>app_name:</tt> name of the application (will be prepended to RPX domain and used in RPX dialogues)
7
- # * <tt>return_url:</tt> url for the RPX callback (e.g. user_sessions_url)
8
- # * <tt>add_rpx:</tt> if true, requests RPX callback to add to current session. Else runs normal authentication process (default)
9
- #
10
- # The options hash may include other options as supported by rpx_now (see http://github.com/grosser/rpx_now)
11
- #
12
- def rpx_embed(options = {})
13
- app_name = options.delete( :app_name )
14
- token_url = build_token_url!( options )
15
- RPXNow.embed_code(app_name, token_url, options )
16
- end
4
+ # helper to insert an embedded iframe RPX login
5
+ # takes options hash:
6
+ # * <tt>app_name:</tt> name of the application (will be prepended to RPX domain and used in RPX dialogues)
7
+ # * <tt>return_url:</tt> url for the RPX callback (e.g. user_sessions_url)
8
+ # * <tt>add_rpx:</tt> if true, requests RPX callback to add to current session. Else runs normal authentication process (default)
9
+ #
10
+ # The options hash may include other options as supported by rpx_now (see http://github.com/grosser/rpx_now)
11
+ #
12
+ def rpx_embed(options = {})
13
+ app_name = options.delete( :app_name )
14
+ token_url = build_token_url!( options )
15
+ RPXNow.embed_code(app_name, token_url, options )
16
+ end
17
17
 
18
- # helper to insert a link to pop-up RPX login
19
- # takes options hash:
20
- # * <tt>link_text:</tt> text to use in the link
21
- # * <tt>app_name:</tt> name of the application (will be prepended to RPX domain and used in RPX dialogues)
22
- # * <tt>return_url:</tt> url for the RPX callback (e.g. user_sessions_url)
23
- # * <tt>add_rpx:</tt> if true, requests RPX callback to add to current session. Else runs normal authentication process (default)
24
- # * <tt>unobtrusive:</tt> true/false; sets javascript style for link. Default: true
25
- #
26
- # The options hash may include other options as supported by rpx_now (see http://github.com/grosser/rpx_now)
27
- #
28
- def rpx_popup(options = {})
29
- options = { :unobtrusive => true, :add_rpx => false }.merge( options )
30
- app_name = options.delete( :app_name )
31
- link_text = options.delete( :link_text )
32
- token_url = build_token_url!( options )
33
- RPXNow.popup_code( link_text, app_name, token_url, options )
34
- end
18
+ # helper to insert a link to pop-up RPX login
19
+ # takes options hash:
20
+ # * <tt>link_text:</tt> text to use in the link
21
+ # * <tt>app_name:</tt> name of the application (will be prepended to RPX domain and used in RPX dialogues)
22
+ # * <tt>return_url:</tt> url for the RPX callback (e.g. user_sessions_url)
23
+ # * <tt>add_rpx:</tt> if true, requests RPX callback to add to current session. Else runs normal authentication process (default)
24
+ # * <tt>unobtrusive:</tt> true/false; sets javascript style for link. Default: true
25
+ #
26
+ # The options hash may include other options as supported by rpx_now (see http://github.com/grosser/rpx_now)
27
+ #
28
+ def rpx_popup(options = {})
29
+ options = { :unobtrusive => true, :add_rpx => false }.merge( options )
30
+ app_name = options.delete( :app_name )
31
+ link_text = options.delete( :link_text )
32
+ token_url = build_token_url!( options )
33
+ RPXNow.popup_code( link_text, app_name, token_url, options )
34
+ end
35
35
 
36
36
  private
37
37
 
@@ -39,7 +39,7 @@ module AuthlogicRpx
39
39
  url = options.delete( :return_url )
40
40
  url + (url.include?('?') ? '&' : '?') + (
41
41
  { :authenticity_token => form_authenticity_token, :add_rpx => options.delete( :add_rpx ) }.collect { |n| "#{n[0]}=#{ u(n[1]) }" if n[1] }
42
- ).compact.join('&')
42
+ ).compact.join('&')
43
43
  end
44
- end
44
+ end
45
45
  end
@@ -0,0 +1,9 @@
1
+ module AuthlogicRpx
2
+ class Railtie < Rails::Railtie
3
+ initializer 'authlogic_rpx.load_model_extensions' do
4
+ ActiveSupport.on_load :active_record do
5
+ ActiveRecord::Base.send(:include, AuthlogicRpx::ActsAsAuthentic)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,4 +1,4 @@
1
1
  class RPXIdentifier < ActiveRecord::Base
2
- validates_presence_of :identifier
3
- validates_uniqueness_of :identifier
2
+ validates_presence_of :identifier
3
+ validates_uniqueness_of :identifier
4
4
  end
@@ -1,241 +1,241 @@
1
1
  module AuthlogicRpx
2
- # This module is responsible for adding all of the RPX goodness to the Authlogic::Session::Base class.
3
- module Session
4
- # Add a simple rpx_identifier attribute and some validations for the field.
5
- def self.included(klass)
6
- klass.class_eval do
7
- extend Config
8
- include Methods
9
- end
10
- end
11
-
12
- module Config
13
-
14
- def find_by_rpx_identifier_method(value = nil)
15
- rw_config(:find_by_rpx_identifier_method, value, :find_by_rpx_identifier)
16
- end
17
- alias_method :find_by_rpx_identifier_method=, :find_by_rpx_identifier_method
18
-
19
- # Auto Register is enabled by default.
20
- # Add this in your Session object if you need to disable auto-registration via rpx
21
- #
22
- def auto_register(value=true)
23
- auto_register_value(value)
24
- end
25
- def auto_register_value(value=nil)
26
- rw_config(:auto_register,value,true)
27
- end
28
- alias_method :auto_register=,:auto_register
29
-
30
- # Add this in your Session object to set the RPX API key
31
- # RPX won't work without the API key. Set it here if not already set in your app configuration.
32
- #
33
- def rpx_key(value=nil)
34
- rpx_key_value(value)
35
- end
36
- def rpx_key_value(value=nil)
37
- if !inheritable_attributes.include?(:rpx_key)
38
- RPXNow.api_key = value
39
- end
40
- rw_config(:rpx_key,value,false)
41
- end
42
- alias_method :rpx_key=,:rpx_key
43
-
44
- # Add this in your Session object to set whether RPX returns extended user info
45
- # By default, it will not, which is enough to get username, name, email and the rpx identified
46
- # if you want to map additional information into your user details, you can request extended
47
- # attributes (though not all providers give them - see the RPX docs)
48
- #
49
- def rpx_extended_info(value=true)
50
- rpx_extended_info_value(value)
51
- end
52
- def rpx_extended_info_value(value=nil)
53
- rw_config(:rpx_extended_info,value,false)
54
- end
55
- alias_method :rpx_extended_info=,:rpx_extended_info
56
-
57
- end
58
-
59
- module Methods
60
-
61
- def self.included(klass)
62
- klass.class_eval do
63
- attr_accessor :new_registration
64
- after_persisting :add_rpx_identifier, :if => :adding_rpx_identifier?
65
- validate :validate_by_rpx, :if => :authenticating_with_rpx?
66
- validate :validate_user
67
- end
68
- end
69
-
70
- # Determines if the authenticated user is also a new registration.
71
- # For use in the session controller to help direct the most appropriate action to follow.
72
- #
73
- def new_registration?
74
- new_registration || !new_registration.nil?
75
- end
76
-
77
- # True if the login was succeessful, but the logged-in user object is invalid.
78
- # For use in the session controller to help direct the most appropriate action to follow.
79
- #
80
- def registration_incomplete?
81
- valid? && attempted_record && !attempted_record.valid?
82
- end
83
-
84
- # Determines if the authenticated user has a complete registration (no validation errors)
85
- # For use in the session controller to help direct the most appropriate action to follow.
86
- #
87
- def registration_complete?
88
- attempted_record && attempted_record.valid?
89
- end
90
-
91
- private
92
- # Tests if current request is for RPX authentication
93
- #
94
- def authenticating_with_rpx?
95
- controller.params[:token] && !controller.params[:add_rpx]
96
- end
97
-
98
- # hook instance finder method to class
99
- #
100
- def find_by_rpx_identifier_method
101
- self.class.find_by_rpx_identifier_method
102
- end
103
-
104
- # Tests if auto_registration is enabled (on by default)
105
- #
106
- def auto_register?
107
- self.class.auto_register_value
108
- end
109
-
110
- # Tests if rpx_extended_info is enabled (off by default)
111
- #
112
- def rpx_extended_info?
113
- self.class.rpx_extended_info_value
114
- end
2
+ # This module is responsible for adding all of the RPX goodness to the Authlogic::Session::Base class.
3
+ module Session
4
+ # Add a simple rpx_identifier attribute and some validations for the field.
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ extend Config
8
+ include Methods
9
+ end
10
+ end
11
+
12
+ module Config
13
+
14
+ def find_by_rpx_identifier_method(value = nil)
15
+ rw_config(:find_by_rpx_identifier_method, value, :find_by_rpx_identifier)
16
+ end
17
+ alias_method :find_by_rpx_identifier_method=, :find_by_rpx_identifier_method
18
+
19
+ # Auto Register is enabled by default.
20
+ # Add this in your Session object if you need to disable auto-registration via rpx
21
+ #
22
+ def auto_register(value=true)
23
+ auto_register_value(value)
24
+ end
25
+ def auto_register_value(value=nil)
26
+ rw_config(:auto_register,value,true)
27
+ end
28
+ alias_method :auto_register=,:auto_register
29
+
30
+ # Add this in your Session object to set the RPX API key
31
+ # RPX won't work without the API key. Set it here if not already set in your app configuration.
32
+ #
33
+ def rpx_key(value=nil)
34
+ rpx_key_value(value)
35
+ end
36
+ def rpx_key_value(value=nil)
37
+ if !inheritable_attributes.include?(:rpx_key)
38
+ RPXNow.api_key = value
39
+ end
40
+ rw_config(:rpx_key,value,false)
41
+ end
42
+ alias_method :rpx_key=,:rpx_key
43
+
44
+ # Add this in your Session object to set whether RPX returns extended user info
45
+ # By default, it will not, which is enough to get username, name, email and the rpx identified
46
+ # if you want to map additional information into your user details, you can request extended
47
+ # attributes (though not all providers give them - see the RPX docs)
48
+ #
49
+ def rpx_extended_info(value=true)
50
+ rpx_extended_info_value(value)
51
+ end
52
+ def rpx_extended_info_value(value=nil)
53
+ rw_config(:rpx_extended_info,value,false)
54
+ end
55
+ alias_method :rpx_extended_info=,:rpx_extended_info
56
+
57
+ end
58
+
59
+ module Methods
60
+
61
+ def self.included(klass)
62
+ klass.class_eval do
63
+ attr_accessor :new_registration
64
+ after_persisting :add_rpx_identifier, :if => :adding_rpx_identifier?
65
+ validate :validate_by_rpx, :if => :authenticating_with_rpx?
66
+ validate :validate_user
67
+ end
68
+ end
69
+
70
+ # Determines if the authenticated user is also a new registration.
71
+ # For use in the session controller to help direct the most appropriate action to follow.
72
+ #
73
+ def new_registration?
74
+ new_registration || !new_registration.nil?
75
+ end
76
+
77
+ # True if the login was succeessful, but the logged-in user object is invalid.
78
+ # For use in the session controller to help direct the most appropriate action to follow.
79
+ #
80
+ def registration_incomplete?
81
+ valid? && attempted_record && !attempted_record.valid?
82
+ end
83
+
84
+ # Determines if the authenticated user has a complete registration (no validation errors)
85
+ # For use in the session controller to help direct the most appropriate action to follow.
86
+ #
87
+ def registration_complete?
88
+ attempted_record && attempted_record.valid?
89
+ end
90
+
91
+ private
92
+ # Tests if current request is for RPX authentication
93
+ #
94
+ def authenticating_with_rpx?
95
+ controller.params[:token] && !controller.params[:add_rpx]
96
+ end
97
+
98
+ # hook instance finder method to class
99
+ #
100
+ def find_by_rpx_identifier_method
101
+ self.class.find_by_rpx_identifier_method
102
+ end
103
+
104
+ # Tests if auto_registration is enabled (on by default)
105
+ #
106
+ def auto_register?
107
+ self.class.auto_register_value
108
+ end
109
+
110
+ # Tests if rpx_extended_info is enabled (off by default)
111
+ #
112
+ def rpx_extended_info?
113
+ self.class.rpx_extended_info_value
114
+ end
115
115
 
116
116
  # Tests if current request is the special case of adding RPX to an existing account
117
117
  #
118
- def adding_rpx_identifier?
119
- controller.params[:token] && controller.params[:add_rpx]
120
- end
121
-
122
- # Handles the special case of RPX being added to an existing account.
123
- # At this point, a session has been established as a result of a "save" on the user model (which indirectly triggers user session validation).
124
- # We do not directly add the RPX details to the user record here in order to avoid getting
125
- # into a recursive dance between the session and user models.
126
- # Rather, it uses the trick of adding the necessary RPX information to the session object,
127
- # and the user model will pluck these values out before completing its validation step.
128
- #
129
- def add_rpx_identifier
130
- data = RPXNow.user_data(controller.params[:token], :extended=> rpx_extended_info? ) {|raw| raw }
131
- controller.session['added_rpx_data'] = data if data
132
- end
133
-
134
- # the main RPX magic. At this point, a session is being validated and we know RPX identifier
135
- # has been provided. We'll callback to RPX to verify the token, and authenticate the matching
136
- # user.
137
- # If no user is found, and we have auto_register enabled (default) this method will also
138
- # create the user registration stub.
139
- #
140
- # On return to the controller, you can test for new_registration? and registration_complete?
141
- # to determine the most appropriate action
142
- #
143
- def validate_by_rpx
144
- @rpx_data = RPXNow.user_data(
145
- controller.params[:token],
146
- :extended => rpx_extended_info?) { |raw| raw }
147
-
148
- # If we don't have a valid sign-in, give-up at this point
149
- if @rpx_data.nil? || @rpx_data['profile'].nil?
150
- errors.add_to_base("Authentication failed. Please try again.")
151
- return false
152
- end
153
-
154
- rpx_id = @rpx_data['profile']['identifier']
155
- rpx_provider_name = @rpx_data['profile']['providerName']
156
- if rpx_id.blank?
157
- errors.add_to_base("Authentication failed. Please try again.")
158
- return false
159
- end
160
-
161
- self.attempted_record = klass.send(find_by_rpx_identifier_method, rpx_id)
162
-
163
- # so what do we do if we can't find an existing user matching the RPX authentication...
164
- if !attempted_record
165
- if auto_register?
166
- self.attempted_record = new_rpx_user(controller.params)
167
- map_rpx_data
168
-
169
- # save the new user record - without session maintenance else we
170
- # get caught in a self-referential hell, since both session and
171
- # user objects invoke each other upon save
172
- self.new_registration = true
173
- self.attempted_record.add_rpx_identifier( rpx_id, rpx_provider_name)
174
- self.attempted_record.save_without_session_maintenance
175
- else
176
- errors.add_to_base("We did not find any accounts with that login. Enter your details and create an account.")
177
- return false
178
- end
179
- else
180
- map_rpx_data_each_login
181
- end
182
-
183
- end
184
-
185
- def validate_user
186
- errors.add(:user, "is invalid") if attempted_record && !attempted_record.valid?
187
- end
188
-
189
- # map_rpx_data maps additional fields from the RPX response into the user object during auto-registration.
190
- # Override this in your session model to change the field mapping
191
- # See https://rpxnow.com/docs#profile_data for the definition of available attributes
192
- #
193
- # In this procedure, you will be writing to fields of the "self.attempted_record" object, pulling data from the @rpx_data object.
194
- #
195
- # WARNING: if you are using auto-registration, any fields you map should NOT have constraints enforced at the database level.
196
- # authlogic_rpx will optimistically attempt to save the user record during registration, and
197
- # violating a database constraint will cause the authentication/registration to fail.
198
- #
199
- # You can/should enforce any required validations at the model level e.g.
200
- # validates_uniqueness_of :username, :case_sensitive => false
201
- # This will allow the auto-registration to proceed, and the user can be given a chance to rectify the validation errors
202
- # on your user profile page.
203
- #
204
- # If it is not acceptable in your application to have user records created with potential validation errors in auto-populated fields, you
205
- # will need to override map_rpx_data and implement whatever special handling makes sense in your case. For example:
206
- # - directly check for uniqueness and other validation requirements
207
- # - automatically "uniquify" fields like username
208
- # - save conflicting profile information to "pending user review" columns or a seperate table
209
- #
210
- def map_rpx_data
211
- self.attempted_record.send("#{klass.login_field}=", @rpx_data['profile']['preferredUsername'] ) if attempted_record.send(klass.login_field).blank?
212
- self.attempted_record.send("#{klass.email_field}=", @rpx_data['profile']['email'] ) if attempted_record.send(klass.email_field).blank?
213
- end
214
-
215
- # new_rpx_user creates a fresh user in the case of auto-registration, prior to mapping in
216
- # the rpx data via map_rpx_data. You are passed the current controller params,
217
- # which you can use to initialize the user.
218
- #
219
- # Override this in your session model to change the initialization of auto-registered users.
220
- #
221
- def new_rpx_user(params)
222
- klass.new()
223
- end
224
-
225
- # map_rpx_data_each_login provides a hook to allow you to map RPX profile information every time the user
226
- # logs in.
227
- # By default, nothing is mapped.
228
- #
229
- # This would mainly be used to update relatively volatile information that you are maintaining in the user model (such as profile image url)
230
- #
231
- # In this procedure, you will be writing to fields of the "self.attempted_record" object, pulling data from the @rpx_data object.
232
- #
233
- #
234
- def map_rpx_data_each_login
235
-
236
- end
237
-
238
- end
239
-
240
- end
118
+ def adding_rpx_identifier?
119
+ controller.params[:token] && controller.params[:add_rpx]
120
+ end
121
+
122
+ # Handles the special case of RPX being added to an existing account.
123
+ # At this point, a session has been established as a result of a "save" on the user model (which indirectly triggers user session validation).
124
+ # We do not directly add the RPX details to the user record here in order to avoid getting
125
+ # into a recursive dance between the session and user models.
126
+ # Rather, it uses the trick of adding the necessary RPX information to the session object,
127
+ # and the user model will pluck these values out before completing its validation step.
128
+ #
129
+ def add_rpx_identifier
130
+ data = RPXNow.user_data(controller.params[:token], :extended=> rpx_extended_info? ) {|raw| raw }
131
+ controller.session['added_rpx_data'] = data if data
132
+ end
133
+
134
+ # the main RPX magic. At this point, a session is being validated and we know RPX identifier
135
+ # has been provided. We'll callback to RPX to verify the token, and authenticate the matching
136
+ # user.
137
+ # If no user is found, and we have auto_register enabled (default) this method will also
138
+ # create the user registration stub.
139
+ #
140
+ # On return to the controller, you can test for new_registration? and registration_complete?
141
+ # to determine the most appropriate action
142
+ #
143
+ def validate_by_rpx
144
+ @rpx_data = RPXNow.user_data(
145
+ controller.params[:token],
146
+ :extended => rpx_extended_info?) { |raw| raw }
147
+
148
+ # If we don't have a valid sign-in, give-up at this point
149
+ if @rpx_data.nil? || @rpx_data['profile'].nil?
150
+ errors.add_to_base("Authentication failed. Please try again.")
151
+ return false
152
+ end
153
+
154
+ rpx_id = @rpx_data['profile']['identifier']
155
+ rpx_provider_name = @rpx_data['profile']['providerName']
156
+ if rpx_id.blank?
157
+ errors.add_to_base("Authentication failed. Please try again.")
158
+ return false
159
+ end
160
+
161
+ self.attempted_record = klass.send(find_by_rpx_identifier_method, rpx_id)
162
+
163
+ # so what do we do if we can't find an existing user matching the RPX authentication...
164
+ if !attempted_record
165
+ if auto_register?
166
+ self.attempted_record = new_rpx_user(controller.params)
167
+ map_rpx_data
168
+
169
+ # save the new user record - without session maintenance else we
170
+ # get caught in a self-referential hell, since both session and
171
+ # user objects invoke each other upon save
172
+ self.new_registration = true
173
+ self.attempted_record.add_rpx_identifier( rpx_id, rpx_provider_name)
174
+ self.attempted_record.save_without_session_maintenance
175
+ else
176
+ errors.add_to_base("We did not find any accounts with that login. Enter your details and create an account.")
177
+ return false
178
+ end
179
+ else
180
+ map_rpx_data_each_login
181
+ end
182
+
183
+ end
184
+
185
+ def validate_user
186
+ errors.add(:user, "is invalid") if attempted_record && !attempted_record.valid?
187
+ end
188
+
189
+ # map_rpx_data maps additional fields from the RPX response into the user object during auto-registration.
190
+ # Override this in your session model to change the field mapping
191
+ # See https://rpxnow.com/docs#profile_data for the definition of available attributes
192
+ #
193
+ # In this procedure, you will be writing to fields of the "self.attempted_record" object, pulling data from the @rpx_data object.
194
+ #
195
+ # WARNING: if you are using auto-registration, any fields you map should NOT have constraints enforced at the database level.
196
+ # authlogic_rpx will optimistically attempt to save the user record during registration, and
197
+ # violating a database constraint will cause the authentication/registration to fail.
198
+ #
199
+ # You can/should enforce any required validations at the model level e.g.
200
+ # validates_uniqueness_of :username, :case_sensitive => false
201
+ # This will allow the auto-registration to proceed, and the user can be given a chance to rectify the validation errors
202
+ # on your user profile page.
203
+ #
204
+ # If it is not acceptable in your application to have user records created with potential validation errors in auto-populated fields, you
205
+ # will need to override map_rpx_data and implement whatever special handling makes sense in your case. For example:
206
+ # - directly check for uniqueness and other validation requirements
207
+ # - automatically "uniquify" fields like username
208
+ # - save conflicting profile information to "pending user review" columns or a seperate table
209
+ #
210
+ def map_rpx_data
211
+ self.attempted_record.send("#{klass.login_field}=", @rpx_data['profile']['preferredUsername'] ) if attempted_record.send(klass.login_field).blank?
212
+ self.attempted_record.send("#{klass.email_field}=", @rpx_data['profile']['email'] ) if attempted_record.send(klass.email_field).blank?
213
+ end
214
+
215
+ # new_rpx_user creates a fresh user in the case of auto-registration, prior to mapping in
216
+ # the rpx data via map_rpx_data. You are passed the current controller params,
217
+ # which you can use to initialize the user.
218
+ #
219
+ # Override this in your session model to change the initialization of auto-registered users.
220
+ #
221
+ def new_rpx_user(params)
222
+ klass.new()
223
+ end
224
+
225
+ # map_rpx_data_each_login provides a hook to allow you to map RPX profile information every time the user
226
+ # logs in.
227
+ # By default, nothing is mapped.
228
+ #
229
+ # This would mainly be used to update relatively volatile information that you are maintaining in the user model (such as profile image url)
230
+ #
231
+ # In this procedure, you will be writing to fields of the "self.attempted_record" object, pulling data from the @rpx_data object.
232
+ #
233
+ #
234
+ def map_rpx_data_each_login
235
+
236
+ end
237
+
238
+ end
239
+
240
+ end
241
241
  end