lsdr-authlogic-connect 0.0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.markdown +240 -0
  3. data/Rakefile +71 -0
  4. data/init.rb +1 -0
  5. data/lib/authlogic-connect.rb +27 -0
  6. data/lib/authlogic_connect/authlogic_connect.rb +46 -0
  7. data/lib/authlogic_connect/callback_filter.rb +19 -0
  8. data/lib/authlogic_connect/common.rb +10 -0
  9. data/lib/authlogic_connect/common/session.rb +27 -0
  10. data/lib/authlogic_connect/common/state.rb +16 -0
  11. data/lib/authlogic_connect/common/user.rb +115 -0
  12. data/lib/authlogic_connect/common/variables.rb +77 -0
  13. data/lib/authlogic_connect/engine.rb +14 -0
  14. data/lib/authlogic_connect/ext.rb +56 -0
  15. data/lib/authlogic_connect/oauth.rb +14 -0
  16. data/lib/authlogic_connect/oauth/helper.rb +20 -0
  17. data/lib/authlogic_connect/oauth/process.rb +68 -0
  18. data/lib/authlogic_connect/oauth/session.rb +58 -0
  19. data/lib/authlogic_connect/oauth/state.rb +54 -0
  20. data/lib/authlogic_connect/oauth/tokens/facebook_token.rb +11 -0
  21. data/lib/authlogic_connect/oauth/tokens/get_satisfaction_token.rb +9 -0
  22. data/lib/authlogic_connect/oauth/tokens/google_token.rb +41 -0
  23. data/lib/authlogic_connect/oauth/tokens/linked_in_token.rb +19 -0
  24. data/lib/authlogic_connect/oauth/tokens/myspace_token.rb +26 -0
  25. data/lib/authlogic_connect/oauth/tokens/oauth_token.rb +131 -0
  26. data/lib/authlogic_connect/oauth/tokens/opensocial_token.rb +0 -0
  27. data/lib/authlogic_connect/oauth/tokens/twitter_token.rb +8 -0
  28. data/lib/authlogic_connect/oauth/tokens/vimeo_token.rb +18 -0
  29. data/lib/authlogic_connect/oauth/tokens/yahoo_token.rb +19 -0
  30. data/lib/authlogic_connect/oauth/user.rb +68 -0
  31. data/lib/authlogic_connect/oauth/variables.rb +55 -0
  32. data/lib/authlogic_connect/openid.rb +11 -0
  33. data/lib/authlogic_connect/openid/process.rb +30 -0
  34. data/lib/authlogic_connect/openid/session.rb +78 -0
  35. data/lib/authlogic_connect/openid/state.rb +47 -0
  36. data/lib/authlogic_connect/openid/tokens/aol_token.rb +0 -0
  37. data/lib/authlogic_connect/openid/tokens/blogger_token.rb +0 -0
  38. data/lib/authlogic_connect/openid/tokens/flickr_token.rb +0 -0
  39. data/lib/authlogic_connect/openid/tokens/my_openid_token.rb +3 -0
  40. data/lib/authlogic_connect/openid/tokens/openid_token.rb +9 -0
  41. data/lib/authlogic_connect/openid/user.rb +62 -0
  42. data/lib/authlogic_connect/openid/variables.rb +19 -0
  43. data/lib/authlogic_connect/token.rb +53 -0
  44. data/lib/open_id_authentication.rb +128 -0
  45. data/rails/init.rb +19 -0
  46. data/test/controllers/test_users_controller.rb +21 -0
  47. data/test/libs/database.rb +48 -0
  48. data/test/libs/user.rb +3 -0
  49. data/test/libs/user_session.rb +2 -0
  50. data/test/old.rb +53 -0
  51. data/test/test_authlogic_connect.rb +13 -0
  52. data/test/test_helper.rb +153 -0
  53. data/test/test_user.rb +255 -0
  54. metadata +247 -0
@@ -0,0 +1,16 @@
1
+ # This class holds query/state variables common to oauth and openid
2
+ module AuthlogicConnect::Common::State
3
+
4
+ def auth_session?
5
+ !auth_session.blank?
6
+ end
7
+
8
+ def auth_params?
9
+ !auth_params.blank?
10
+ end
11
+
12
+ def is_auth_session?
13
+ self.is_a?(Authlogic::Session::Base)
14
+ end
15
+
16
+ end
@@ -0,0 +1,115 @@
1
+ # This class is the main api for the user.
2
+ # It is also required to properly sequence the save methods
3
+ # for the different authentication types (oauth and openid)
4
+ module AuthlogicConnect::Common::User
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+ add_acts_as_authentic_module(InstanceMethods, :append)
9
+ add_acts_as_authentic_module(AuthlogicConnect::Common::Variables, :prepend)
10
+ end
11
+ end
12
+
13
+ module InstanceMethods
14
+
15
+ def self.included(base)
16
+ base.class_eval do
17
+ has_many :tokens, :class_name => "Token", :dependent => :destroy
18
+ belongs_to :active_token, :class_name => "Token", :dependent => :destroy
19
+ accepts_nested_attributes_for :tokens, :active_token
20
+ end
21
+ end
22
+
23
+ def authenticated_with
24
+ @authenticated_with ||= self.tokens.collect{|t| t.service_name.to_s}
25
+ end
26
+
27
+ def authenticated_with?(service)
28
+ self.tokens.detect{|t| t.service_name.to_s == service.to_s}
29
+ end
30
+
31
+ def update_attributes(attributes, &block)
32
+ self.attributes = attributes
33
+ save(:validate => true, &block)
34
+ end
35
+
36
+ def has_token?(service_name)
37
+ !get_token(service_name).nil?
38
+ end
39
+
40
+ def get_token(service_name)
41
+ self.tokens.detect {|i| i.service_name.to_s == service_name.to_s}
42
+ end
43
+
44
+ # core save method coordinating how to save the user.
45
+ # we dont' want to ru validations based on the
46
+ # authentication mission we are trying to accomplish.
47
+ # instead, we just return save as false.
48
+ # the next time around, when we recieve the callback,
49
+ # we will run the validations
50
+ def save(options = {}, &block)
51
+ # debug_user_save_pre(options, &block)
52
+ options = {} if options == false
53
+ unless options[:skip_redirect] == true
54
+ return false if remotely_authenticating?(&block)
55
+ end
56
+ # forces you to validate, maybe get rid of if needed,
57
+ # but everything depends on this
58
+ if ActiveRecord::VERSION::MAJOR < 3
59
+ result = super(true) # validate!
60
+ else
61
+ result = super(options.merge(:validate => true))
62
+ end
63
+ # debug_user_save_post
64
+ yield(result) if block_given? # give back to controller
65
+
66
+ cleanup_auth_session if result && !(options.has_key?(:keep_session) && options[:keep_session])
67
+
68
+ result
69
+ end
70
+
71
+ def remotely_authenticating?(&block)
72
+ return redirecting_to_oauth_server? if using_oauth? && block_given?
73
+ return redirecting_to_openid_server? if using_openid?
74
+ return false
75
+ end
76
+
77
+ # it only reaches this point once it has returned, or you
78
+ # have manually skipped the redirect and save was called directly.
79
+ def cleanup_auth_session
80
+ cleanup_oauth_session
81
+ cleanup_openid_session
82
+ end
83
+
84
+ def validate_password_with_oauth?
85
+ !using_openid? && super
86
+ end
87
+
88
+ def validate_password_with_openid?
89
+ !using_oauth? && super
90
+ end
91
+
92
+ # test methods for dev/debugging, commented out by default
93
+ def debug_user_save_pre(options = {}, &block)
94
+ puts "USER SAVE "
95
+ puts "block_given? #{block_given?.to_s}"
96
+ puts "using_oauth? #{using_oauth?.to_s}"
97
+ puts "using_openid? #{using_openid?.to_s}"
98
+ puts "authenticating_with_oauth? #{authenticating_with_oauth?.to_s}"
99
+ puts "authenticating_with_openid? #{authenticating_with_openid?.to_s}"
100
+ puts "validate_password_with_oauth? #{validate_password_with_oauth?.to_s}"
101
+ puts "validate_password_with_openid? #{validate_password_with_openid?.to_s}"
102
+ puts "!using_openid? && require_password? #{(!using_openid? && require_password?).to_s}"
103
+ end
104
+
105
+ def debug_user_save_post
106
+ puts "ERRORS: #{errors.full_messages}"
107
+ puts "using_oauth? #{using_oauth?.to_s}"
108
+ puts "using_openid? #{using_openid?.to_s}"
109
+ puts "validate_password_with_oauth? #{validate_password_with_oauth?.to_s}"
110
+ puts "validate_password_with_openid? #{validate_password_with_openid?.to_s}"
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -0,0 +1,77 @@
1
+ module AuthlogicConnect::Common::Variables
2
+ include AuthlogicConnect::Common::State
3
+
4
+ def auth_controller
5
+ is_auth_session? ? controller : session_class.controller
6
+ end
7
+
8
+ def auth_session
9
+ return {} unless (auth_controller && auth_controller.session)
10
+
11
+ auth_controller.session.symbolize_keys!
12
+ auth_controller.session.keys.each do |key|
13
+ auth_controller.session[key.to_s] = auth_controller.session.delete(key) if key.to_s =~ /^OpenID/
14
+ end
15
+ auth_controller.session
16
+ end
17
+
18
+ def auth_params
19
+ return {} unless (auth_controller && auth_controller.params)
20
+
21
+ auth_controller.params.symbolize_keys!
22
+ auth_controller.params.keys.each do |key|
23
+ auth_controller.params[key.to_s] = auth_controller.params.delete(key) if key.to_s =~ /^OpenID/
24
+ end
25
+ auth_controller.params
26
+ end
27
+
28
+ def auth_callback_url(options = {})
29
+ auth_controller.url_for({:controller => auth_controller.controller_name, :action => auth_controller.action_name}.merge(options))
30
+ end
31
+
32
+ # if we've said it's a "user" (registration), or a "session" (login)
33
+ def auth_type
34
+ from_session_or_params(:authentication_type)
35
+ end
36
+
37
+ # auth_params and auth_session attributes are all String!
38
+ def from_session_or_params(by)
39
+ key = by.is_a?(Symbol) ? by : by.to_sym
40
+ result = auth_params[key] if (auth_params && auth_params[key])
41
+ result = auth_session[key] if (result.nil? || result.blank?)
42
+ result
43
+ end
44
+
45
+ # because user and session are so closely tied together, I am still
46
+ # uncertain as to how they are saved. So this makes sure if we are
47
+ # logging in, it must be saving the session, otherwise the user.
48
+ def correct_request_class?
49
+ if is_auth_session?
50
+ auth_type.to_s == "session"
51
+ else
52
+ auth_type.to_s == "user"
53
+ end
54
+ end
55
+
56
+ def add_session_key(key, value)
57
+
58
+ end
59
+
60
+ # because we may need to store 6+ session variables, all with pretty lengthy names,
61
+ # might as well just tinify them.
62
+ # just an idea
63
+ def optimized_session_key(key)
64
+ @optimized_session_keys ||= {
65
+ :auth_request_class => :authcl,
66
+ :authentication_method => :authme,
67
+ :authentication_type => :authty,
68
+ :oauth_provider => :authpr,
69
+ :auth_callback_method => :authcb,
70
+ :oauth_request_token => :authtk,
71
+ :oauth_request_token_secret => :authsc,
72
+ :auth_attributes => :authat
73
+ }
74
+ @optimized_session_keys[key]
75
+ end
76
+
77
+ end
@@ -0,0 +1,14 @@
1
+ module AuthlogicConnect
2
+ class Engine < Rails::Engine
3
+
4
+ initializer "authlogic_connect.authentication_hook" do |app|
5
+ app.middleware.use AuthlogicConnect::CallbackFilter
6
+ app.middleware.use OpenIdAuthentication
7
+ end
8
+
9
+ initializer "authlogic_connect.finalize", :after => "authlogic_connect.authentication_hook" do |app|
10
+ OpenID::Util.logger = Rails.logger
11
+ ActionController::Base.send :include, OpenIdAuthentication
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,56 @@
1
+ # these are extensions I've found useful for this project
2
+ class String
3
+ # normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization
4
+ def normalize_identifier
5
+ # clean up whitespace
6
+ identifier = self.dup.strip
7
+
8
+ # if an XRI has a prefix, strip it.
9
+ identifier.gsub!(/xri:\/\//i, '')
10
+
11
+ # dodge XRIs -- TODO: validate, don't just skip.
12
+ unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0))
13
+ # does it begin with http? if not, add it.
14
+ identifier = "http://#{identifier}" unless identifier =~ /^http/i
15
+
16
+ # strip any fragments
17
+ identifier.gsub!(/\#(.*)$/, '')
18
+
19
+ begin
20
+ uri = URI.parse(identifier)
21
+ uri.scheme = uri.scheme.downcase # URI should do this
22
+ identifier = uri.normalize.to_s
23
+ rescue URI::InvalidURIError
24
+ raise InvalidOpenId.new("#{identifier} is not an OpenID identifier")
25
+ end
26
+ end
27
+
28
+ return identifier
29
+ end
30
+ end
31
+
32
+ class Hash
33
+ def recursively_symbolize_keys!
34
+ self.symbolize_keys!
35
+ self.values.each do |v|
36
+ if v.is_a? Hash
37
+ v.recursively_symbolize_keys!
38
+ elsif v.is_a? Array
39
+ v.recursively_symbolize_keys!
40
+ end
41
+ end
42
+ self
43
+ end
44
+ end
45
+
46
+ class Array
47
+ def recursively_symbolize_keys!
48
+ self.each do |item|
49
+ if item.is_a? Hash
50
+ item.recursively_symbolize_keys!
51
+ elsif item.is_a? Array
52
+ item.recursively_symbolize_keys!
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,14 @@
1
+ module AuthlogicConnect::Oauth
2
+ end
3
+
4
+ require File.dirname(__FILE__) + "/oauth/state"
5
+ require File.dirname(__FILE__) + "/oauth/variables"
6
+ require File.dirname(__FILE__) + "/oauth/process"
7
+ require File.dirname(__FILE__) + "/oauth/user"
8
+ require File.dirname(__FILE__) + "/oauth/session"
9
+ require File.dirname(__FILE__) + "/oauth/helper"
10
+
11
+ ActiveRecord::Base.send(:include, AuthlogicConnect::Oauth::User)
12
+ Authlogic::Session::Base.send(:include, AuthlogicConnect::Oauth::Session)
13
+ ActionController::Base.helper AuthlogicConnect::Oauth::Helper
14
+ ActionView::Helpers::FormBuilder.send(:include, AuthlogicConnect::Oauth::FormHelper)
@@ -0,0 +1,20 @@
1
+ module AuthlogicConnect::Oauth::Helper
2
+
3
+ # options include "name"
4
+ def oauth_register_hidden_input
5
+ oauth_input(:type => "user")
6
+ end
7
+
8
+ def oauth_login_hidden_input
9
+ oauth_input(:type => "session")
10
+ end
11
+
12
+ def oauth_input(options = {})
13
+ tag(:input, {:type => "hidden", :name => "authentication_type", :value => options[:type]})
14
+ end
15
+
16
+ end
17
+
18
+ module AuthlogicConnect::Oauth::FormHelper
19
+
20
+ end
@@ -0,0 +1,68 @@
1
+ module AuthlogicConnect::Oauth::Process
2
+
3
+ include AuthlogicConnect::Oauth::Variables
4
+
5
+ # Step 2: after save is called, it runs this method for validation
6
+ def validate_by_oauth
7
+ validate_email_field = false
8
+ unless new_oauth_request? # shouldn't be validating if it's redirecting...
9
+ restore_attributes
10
+ complete_oauth_transaction
11
+ end
12
+ end
13
+
14
+ # Step 3: if new_oauth_request?, redirect to oauth provider
15
+ def redirect_to_oauth
16
+ save_oauth_session
17
+ authorize_url = token_class.authorize_url(auth_callback_url) do |request_token|
18
+ save_auth_session_token(request_token) # only for oauth version 1
19
+ end
20
+ auth_controller.redirect_to authorize_url
21
+ end
22
+
23
+ # Step 3a: save our passed-parameters into the session,
24
+ # so we can retrieve them after the redirect calls back
25
+ def save_oauth_session
26
+ # Store the class which is redirecting, so we can ensure other classes
27
+ # don't get confused and attempt to use the response
28
+ auth_session[:auth_request_class] = self.class.name
29
+
30
+ auth_session[:authentication_type] = auth_params[:authentication_type]
31
+ auth_session[:oauth_provider] = auth_params[:oauth_provider]
32
+ auth_session[:auth_method] = "oauth"
33
+
34
+ # Tell our rack callback filter what method the current request is using
35
+ auth_session[:auth_callback_method] = auth_controller.request.method
36
+ end
37
+
38
+ # Step 3b (if version 1.0 of oauth)
39
+ def save_auth_session_token(request)
40
+ # store token and secret
41
+ auth_session[:oauth_request_token] = request.token
42
+ auth_session[:oauth_request_token_secret] = request.secret
43
+ end
44
+
45
+ def restore_attributes
46
+ end
47
+
48
+ # Step 4: on callback, run this method
49
+ def authenticate_with_oauth
50
+ # implemented in User and Session Oauth modules
51
+ end
52
+
53
+ # Step last, after the response
54
+ # having lots of trouble testing logging and out multiple times,
55
+ # so there needs to be a solid way to know when a user has messed up loggin in.
56
+ def cleanup_oauth_session
57
+ [:auth_request_class,
58
+ :authentication_type,
59
+ :auth_method,
60
+ :auth_attributes,
61
+ :oauth_provider,
62
+ :auth_callback_method,
63
+ :oauth_request_token,
64
+ :oauth_request_token_secret
65
+ ].each {|key| auth_session.delete(key)}
66
+ end
67
+
68
+ end
@@ -0,0 +1,58 @@
1
+ module AuthlogicConnect::Oauth
2
+ # This module is responsible for adding oauth
3
+ # to the Authlogic::Session::Base class.
4
+ module Session
5
+ def self.included(base)
6
+ base.class_eval do
7
+ include InstanceMethods
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ include Process
13
+
14
+ def self.included(klass)
15
+ klass.class_eval do
16
+ validate :validate_by_oauth, :if => :authenticating_with_oauth?
17
+ end
18
+ end
19
+
20
+ # Hooks into credentials so that you can pass a user who has already has an oauth access token.
21
+ def credentials=(value)
22
+ super
23
+ values = value.is_a?(Array) ? value : [value]
24
+ hash = values.first.is_a?(Hash) ? values.first.with_indifferent_access : nil
25
+ self.record = hash[:priority_record] if !hash.nil? && hash.key?(:priority_record)
26
+ end
27
+
28
+ def record=(record)
29
+ @record = record
30
+ end
31
+
32
+ private
33
+ # Clears out the block if we are authenticating with oauth,
34
+ # so that we can redirect without a DoubleRender error.
35
+ def save_with_oauth(&block)
36
+ block = nil if redirecting_to_oauth_server?
37
+ return block.nil?
38
+ end
39
+
40
+ def complete_oauth_transaction
41
+ if @record
42
+ self.attempted_record = record
43
+ else
44
+ # this generated token is always the same for a user!
45
+ # this is searching with User.find ...
46
+ # attempted_record is part of AuthLogic
47
+ hash = oauth_token_and_secret
48
+ token = token_class.find_by_key_or_token(hash[:key], hash[:token], :include => [:user]) # some weird error if I leave out the include)
49
+ self.attempted_record = token.user
50
+ end
51
+
52
+ if !attempted_record
53
+ errors.add_to_base("Could not find user in our database, have you registered with your oauth account?")
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end