lsdr-authlogic-connect 0.0.3.9

Sign up to get free protection for your applications and to get access to all the features.
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