foreverman-authlogic-connect 0.0.1

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 (62) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.markdown +234 -0
  3. data/Rakefile +85 -0
  4. data/init.rb +1 -0
  5. data/lib/authlogic-connect.rb +39 -0
  6. data/lib/authlogic_connect/access_token.rb +61 -0
  7. data/lib/authlogic_connect/authlogic_connect.rb +46 -0
  8. data/lib/authlogic_connect/callback_filter.rb +19 -0
  9. data/lib/authlogic_connect/common.rb +10 -0
  10. data/lib/authlogic_connect/common/session.rb +30 -0
  11. data/lib/authlogic_connect/common/state.rb +45 -0
  12. data/lib/authlogic_connect/common/user.rb +77 -0
  13. data/lib/authlogic_connect/common/variables.rb +124 -0
  14. data/lib/authlogic_connect/engine.rb +14 -0
  15. data/lib/authlogic_connect/ext.rb +56 -0
  16. data/lib/authlogic_connect/oauth.rb +14 -0
  17. data/lib/authlogic_connect/oauth/helper.rb +20 -0
  18. data/lib/authlogic_connect/oauth/process.rb +75 -0
  19. data/lib/authlogic_connect/oauth/session.rb +62 -0
  20. data/lib/authlogic_connect/oauth/state.rb +60 -0
  21. data/lib/authlogic_connect/oauth/tokens/aol_token.rb +2 -0
  22. data/lib/authlogic_connect/oauth/tokens/facebook_token.rb +11 -0
  23. data/lib/authlogic_connect/oauth/tokens/foursquare_token.rb +15 -0
  24. data/lib/authlogic_connect/oauth/tokens/get_satisfaction_token.rb +9 -0
  25. data/lib/authlogic_connect/oauth/tokens/github_token.rb +14 -0
  26. data/lib/authlogic_connect/oauth/tokens/google_token.rb +41 -0
  27. data/lib/authlogic_connect/oauth/tokens/linked_in_token.rb +19 -0
  28. data/lib/authlogic_connect/oauth/tokens/meetup_token.rb +12 -0
  29. data/lib/authlogic_connect/oauth/tokens/myspace_token.rb +26 -0
  30. data/lib/authlogic_connect/oauth/tokens/netflix_token.rb +10 -0
  31. data/lib/authlogic_connect/oauth/tokens/oauth_token.rb +164 -0
  32. data/lib/authlogic_connect/oauth/tokens/ohloh_token.rb +9 -0
  33. data/lib/authlogic_connect/oauth/tokens/opensocial_token.rb +0 -0
  34. data/lib/authlogic_connect/oauth/tokens/twitter_token.rb +8 -0
  35. data/lib/authlogic_connect/oauth/tokens/vimeo_token.rb +18 -0
  36. data/lib/authlogic_connect/oauth/tokens/yahoo_token.rb +19 -0
  37. data/lib/authlogic_connect/oauth/user.rb +64 -0
  38. data/lib/authlogic_connect/oauth/variables.rb +64 -0
  39. data/lib/authlogic_connect/openid.rb +11 -0
  40. data/lib/authlogic_connect/openid/process.rb +74 -0
  41. data/lib/authlogic_connect/openid/session.rb +56 -0
  42. data/lib/authlogic_connect/openid/state.rb +48 -0
  43. data/lib/authlogic_connect/openid/tokens/aol_token.rb +0 -0
  44. data/lib/authlogic_connect/openid/tokens/blogger_token.rb +0 -0
  45. data/lib/authlogic_connect/openid/tokens/flickr_token.rb +0 -0
  46. data/lib/authlogic_connect/openid/tokens/my_openid_token.rb +3 -0
  47. data/lib/authlogic_connect/openid/tokens/openid_token.rb +9 -0
  48. data/lib/authlogic_connect/openid/user.rb +38 -0
  49. data/lib/authlogic_connect/openid/variables.rb +19 -0
  50. data/lib/authlogic_connect/rack_state.rb +19 -0
  51. data/lib/open_id_authentication.rb +127 -0
  52. data/rails/init.rb +19 -0
  53. data/test/controllers/test_users_controller.rb +21 -0
  54. data/test/database.yml +3 -0
  55. data/test/libs/database.rb +47 -0
  56. data/test/libs/user.rb +7 -0
  57. data/test/libs/user_session.rb +2 -0
  58. data/test/test_helper.rb +178 -0
  59. data/test/test_oauth.rb +178 -0
  60. data/test/test_openid.rb +71 -0
  61. data/test/test_user.rb +85 -0
  62. metadata +244 -0
@@ -0,0 +1,9 @@
1
+ # https://www.ohloh.net/
2
+ # http://www.ohloh.net/api/oauth
3
+ class OhlohToken < OauthToken
4
+
5
+ key :user_id
6
+
7
+ settings "http://www.ohloh.net"
8
+
9
+ end
@@ -0,0 +1,8 @@
1
+ class TwitterToken < OauthToken
2
+
3
+ key :user_id
4
+
5
+ settings "http://api.twitter.com",
6
+ :authorize_url => "http://api.twitter.com/oauth/authenticate"
7
+
8
+ end
@@ -0,0 +1,18 @@
1
+ # http://www.vimeo.com/api/docs/oauth
2
+ # http://www.vimeo.com/api/applications/new
3
+ # http://vimeo.com/api/applications
4
+ class VimeoToken < OauthToken
5
+
6
+ key do |access_token|
7
+ body = JSON.parse(access_token.get("http://vimeo.com/api/v2/#{access_token.token}/info.json"))
8
+ user_id = body.first["id"]
9
+ end
10
+
11
+ settings "http://vimeo.com",
12
+ :request_token_path => "/oauth/request_token",
13
+ :authorize_path => "/oauth/authorize",
14
+ :access_token_path => "/oauth/access_token",
15
+ :http_method => "get",
16
+ :scheme => :query_string
17
+
18
+ end
@@ -0,0 +1,19 @@
1
+ # https://developer.apps.yahoo.com/dashboard/createKey.html
2
+ # https://developer.apps.yahoo.com/projects
3
+ # http://developer.yahoo.com/oauth/guide/oauth-accesstoken.html
4
+ # http://developer.yahoo.com/oauth/guide/oauth-auth-flow.html
5
+ # http://code.google.com/apis/gadgets/docs/oauth.html
6
+ # http://developer.yahoo.com/social/rest_api_guide/web-services-guids.html
7
+ # A GUID identifies a person
8
+ # http://social.yahooapis.com/v1/me/guid
9
+ class YahooToken < OauthToken
10
+
11
+ # http://social.yahooapis.com/v1/me/guid
12
+ key :xoauth_yahoo_guid
13
+
14
+ settings "https://api.login.yahoo.com",
15
+ :request_token_path => '/oauth/v2/get_request_token',
16
+ :access_token_path => '/oauth/v2/get_token',
17
+ :authorize_path => '/oauth/v2/request_auth'
18
+
19
+ end
@@ -0,0 +1,64 @@
1
+ module AuthlogicConnect::Oauth::User
2
+
3
+ def self.included(base)
4
+ base.class_eval do
5
+ # add_acts_as_authentic_module makes sure it is
6
+ # only added to the user model, not all activerecord models.
7
+ add_acts_as_authentic_module(InstanceMethods, :prepend)
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ include AuthlogicConnect::Oauth::Process
13
+
14
+ # Set up some simple validations
15
+ def self.included(base)
16
+ base.class_eval do
17
+
18
+ validate :validate_by_oauth, :if => :authenticating_with_oauth?
19
+
20
+ # need these validation options if you don't want it to choke
21
+ # on password length, which you don't need if you're using oauth
22
+ validates_length_of_password_field_options validates_length_of_password_field_options.merge(:if => :validate_password_with_oauth?)
23
+ validates_confirmation_of_password_field_options validates_confirmation_of_password_field_options.merge(:if => :validate_password_with_oauth?)
24
+ validates_length_of_password_confirmation_field_options validates_length_of_password_confirmation_field_options.merge(:if => :validate_password_with_oauth?)
25
+ validates_length_of_login_field_options validates_length_of_login_field_options.merge(:if => :validate_password_with_oauth?)
26
+ validates_format_of_login_field_options validates_format_of_login_field_options.merge(:if => :validate_password_with_oauth?)
27
+
28
+ end
29
+ end
30
+
31
+ # user adds a few extra things to this method from Process
32
+ # modules work like inheritance
33
+ def save_oauth_session
34
+ super
35
+ auth_session[:auth_attributes] = attributes.reject!{|k, v| v.blank? || !self.respond_to?(k)} unless is_auth_session?
36
+ end
37
+
38
+ def redirect_to_oauth
39
+ return has_token?(oauth_provider) ? false : super
40
+ end
41
+
42
+ def restore_attributes
43
+ # Restore any attributes which were saved before redirecting to the auth server
44
+ self.attributes = auth_session[:auth_attributes]
45
+ end
46
+
47
+ # single implementation method for oauth.
48
+ # this is called after we get the callback url and we are saving the user
49
+ # to the database.
50
+ # it is called by the validation chain.
51
+ def complete_oauth_transaction
52
+ token = token_class.new(oauth_token_and_secret)
53
+ old_token = token_class.find_by_key_or_token(token.key, token.token)
54
+ token = old_token if old_token
55
+
56
+ if has_token?(oauth_provider)
57
+ self.errors.add(:tokens, "you have already created an account using your #{token_class.service_name} account, so it")
58
+ else
59
+ self.access_tokens << token
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,64 @@
1
+ module AuthlogicConnect::Oauth::Variables
2
+ include AuthlogicConnect::Oauth::State
3
+
4
+ # this doesn't do anything yet, just to show what variables
5
+ # we need from the form
6
+ def oauth_variables
7
+ [:oauth_provider]
8
+ end
9
+
10
+ # this comes straight from either the params or session.
11
+ # it is required for most of the other accessors in here
12
+ def oauth_provider
13
+ from_session_or_params(:oauth_provider)
14
+ end
15
+
16
+ # next is "token_class", which is found from the oauth_provider key.
17
+ # it is the OauthToken subclass, such as TwitterToken, which we
18
+ # use as the api for accessing oauth and saving the response to the database for a user.
19
+ def token_class
20
+ AuthlogicConnect.token(oauth_provider) unless oauth_provider.blank?
21
+ end
22
+
23
+ # This should go...
24
+ def oauth_response
25
+ auth_params && oauth_token
26
+ end
27
+
28
+ # the token from the response parameters
29
+ def oauth_token
30
+ return nil unless token_class
31
+ oauth_version == 1.0 ? auth_params[:oauth_token] : auth_params[:code]
32
+ end
33
+
34
+ # the version of oauth we're using. Accessed from the OauthToken subclass
35
+ def oauth_version
36
+ token_class.oauth_version
37
+ end
38
+
39
+ # the Oauth gem consumer, whereby we can make requests to the server
40
+ def oauth_consumer
41
+ token_class.consumer
42
+ end
43
+
44
+ def stored_oauth_token_and_secret
45
+ if auth_controller?
46
+ {:key => auth_params[:_key], :token => auth_params[:_token], :secret => auth_params[:_secret]}
47
+ else
48
+ {:key => nil, :token => nil, :secret => nil}
49
+ end
50
+ end
51
+
52
+ # this is a thick method.
53
+ # it gives you the final key and secret that we will store in the database
54
+ def oauth_token_and_secret
55
+ return stored_oauth_token_and_secret if stored_oauth_token_and_secret?
56
+ token_class.get_token_and_secret(
57
+ :token => auth_session[:oauth_request_token],
58
+ :secret => oauth_version == 1.0 ? auth_session[:oauth_request_token_secret] : oauth_token,
59
+ :oauth_verifier => auth_params[:oauth_verifier],
60
+ :redirect_uri => auth_callback_url
61
+ )
62
+ end
63
+
64
+ end
@@ -0,0 +1,11 @@
1
+ module AuthlogicConnect::Openid
2
+ end
3
+
4
+ require File.dirname(__FILE__) + "/openid/state"
5
+ require File.dirname(__FILE__) + "/openid/variables"
6
+ require File.dirname(__FILE__) + "/openid/process"
7
+ require File.dirname(__FILE__) + "/openid/user"
8
+ require File.dirname(__FILE__) + "/openid/session"
9
+
10
+ ActiveRecord::Base.send(:include, AuthlogicConnect::Openid::User)
11
+ Authlogic::Session::Base.send(:include, AuthlogicConnect::Openid::Session)
@@ -0,0 +1,74 @@
1
+ module AuthlogicConnect::Openid::Process
2
+
3
+ include AuthlogicConnect::Openid::Variables
4
+
5
+ def start_openid
6
+ save_openid_session
7
+ call_openid
8
+ end
9
+
10
+ def complete_openid
11
+ restore_attributes
12
+ call_openid
13
+ end
14
+
15
+ def call_openid
16
+ options = {}
17
+ options[:return_to] = auth_callback_url
18
+ # this is called both on start and complete.
19
+ # reason being, in the open_id_authentication library (where "authenticate_with_open_id" is defined),
20
+ # it checks the rack session to find openid pareters, and knows whether we're at
21
+ # start or complete
22
+ auth_controller.send(:authenticate_with_open_id, openid_identifier, options) do |result, openid_identifier|
23
+ complete_openid_transaction(result, openid_identifier)
24
+ return true
25
+ end
26
+ return false
27
+ end
28
+
29
+ def complete_openid_transaction(result, openid_identifier)
30
+ if result.unsuccessful?
31
+ errors.add_to_base(result.message)
32
+ end
33
+
34
+ if AccessToken.find_by_key(openid_identifier.normalize_identifier)
35
+ else
36
+ token = OpenidToken.new(:key => openid_identifier)
37
+ self.access_tokens << token
38
+ self.active_token = token
39
+ end
40
+ end
41
+
42
+ # want to do this after the final save
43
+ def cleanup_openid_session
44
+ [:auth_attributes, :authentication_type, :auth_callback_method].each {|key| remove_session_key(key)}
45
+ auth_session.each_key do |key|
46
+ remove_session_key(key) if key.to_s =~ /^OpenID/
47
+ end
48
+ end
49
+
50
+ def validate_by_openid
51
+ if processing_authentication
52
+ authentication_protocol(:openid, :start) || authentication_protocol(:openid, :complete)
53
+ errors.add(:access_tokens, "had the following error: #{@openid_error}") if @openid_error
54
+ end
55
+ end
56
+
57
+ def save_openid_session
58
+ # Tell our rack callback filter what method the current request is using
59
+ auth_session[:auth_callback_method] = auth_controller.request.method
60
+ auth_session[:auth_attributes] = attributes_to_save
61
+ auth_session[:authentication_type] = auth_params[:authentication_type]
62
+ auth_session[:auth_method] = "openid"
63
+ end
64
+
65
+ def attributes_to_save
66
+ {}
67
+ end
68
+
69
+ def restore_attributes
70
+ # Restore any attributes which were saved before redirecting to the auth server
71
+ self.attributes = auth_session[:auth_attributes] unless is_auth_session?
72
+ end
73
+
74
+ end
@@ -0,0 +1,56 @@
1
+ module AuthlogicConnect::Openid
2
+ # This module is responsible for adding all of the OpenID goodness to the Authlogic::Session::Base class.
3
+ module Session
4
+ # Add a simple openid_identifier attribute and some validations for the field.
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ include InstanceMethods
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ include AuthlogicConnect::Openid::Process
13
+
14
+ def self.included(klass)
15
+ klass.class_eval do
16
+ validate :validate_by_openid, :if => :authenticating_with_openid?
17
+ end
18
+ end
19
+
20
+ # Hooks into credentials so that you can pass an :openid_identifier key.
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
+ end
26
+
27
+ private
28
+
29
+ def auto_register?
30
+ false
31
+ end
32
+
33
+ def complete_openid_transaction(result, openid_identifier)
34
+ if result.unsuccessful?
35
+ errors.add_to_base(result.message)
36
+ end
37
+
38
+ token = AccessToken.find_by_key(openid_identifier.normalize_identifier, :include => [:user])
39
+
40
+ self.attempted_record = token.user if token
41
+
42
+ if !attempted_record
43
+ if auto_register?
44
+ self.attempted_record = klass.new
45
+ self.attempted_record.access_tokens << OpenidToken.new(:key => openid_identifier.normalize_identifier)
46
+ self.attempted_record.save
47
+ else
48
+ auth_session[:openid_identifier] = openid_identifier
49
+ errors.add(:user, "Could not find user in our database, have you registered with your openid account?")
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,48 @@
1
+ # all these methods must return true or false
2
+ module AuthlogicConnect::Openid::State
3
+
4
+ # 1. to call
5
+ def openid_request?
6
+ !openid_identifier.blank? && auth_session[:auth_attributes].nil?
7
+ end
8
+
9
+ def openid_identifier?
10
+ openid_request?
11
+ end
12
+
13
+ def openid_provider?
14
+
15
+ end
16
+
17
+ # 2. from call
18
+ # better check needed
19
+ def openid_response?
20
+ auth_controller? && !auth_session[:auth_attributes].nil? && auth_session[:auth_method] == "openid"
21
+ end
22
+ alias_method :openid_complete?, :openid_response?
23
+
24
+ # 3. either to or from call
25
+ # this should include more!
26
+ # we know we are using open id if:
27
+ # the params passed in have "openid_identifier"
28
+ def using_openid?
29
+ auth_controller? && (openid_request? || openid_response?)
30
+ end
31
+
32
+ def authenticating_with_openid?
33
+ auth_controller? && auth_class.activated? && using_openid?
34
+ end
35
+
36
+ def start_openid?
37
+ authenticating_with_openid? && !openid_response?
38
+ end
39
+
40
+ def complete_openid?
41
+ openid_complete?
42
+ end
43
+
44
+ def validate_password_with_openid?
45
+ !using_openid? && require_password?
46
+ end
47
+
48
+ end
File without changes
@@ -0,0 +1,3 @@
1
+ class MyOpenidToken < OpenidToken
2
+
3
+ end
@@ -0,0 +1,9 @@
1
+ class OpenidToken < AccessToken
2
+
3
+ before_save :format_identifier
4
+
5
+ def format_identifier
6
+ self.key = self.key.to_s.normalize_identifier unless self.key.blank?
7
+ end
8
+
9
+ end
@@ -0,0 +1,38 @@
1
+ module AuthlogicConnect::Openid
2
+ module User
3
+ def self.included(base)
4
+ base.class_eval do
5
+ add_acts_as_authentic_module(AuthlogicConnect::Openid::Process, :prepend)
6
+ add_acts_as_authentic_module(InstanceMethods, :append)
7
+ end
8
+ end
9
+
10
+ module InstanceMethods
11
+
12
+ def self.included(base)
13
+ base.class_eval do
14
+ validate :validate_by_openid, :if => :authenticating_with_openid?
15
+
16
+ validates_length_of_password_field_options validates_length_of_password_field_options.merge(:if => :validate_password_with_openid?)
17
+ validates_confirmation_of_password_field_options validates_confirmation_of_password_field_options.merge(:if => :validate_password_with_openid?)
18
+ validates_length_of_password_confirmation_field_options validates_length_of_password_confirmation_field_options.merge(:if => :validate_password_with_openid?)
19
+ validates_length_of_login_field_options validates_length_of_login_field_options.merge(:if => :validate_password_with_openid?)
20
+ validates_format_of_login_field_options validates_format_of_login_field_options.merge(:if => :validate_password_with_openid?)
21
+ end
22
+ end
23
+
24
+ def attributes_to_save
25
+ attr_list = [:id, :password, crypted_password_field, password_salt_field, :persistence_token, :perishable_token, :single_access_token, :login_count,
26
+ :failed_login_count, :last_request_at, :current_login_at, :last_login_at, :current_login_ip, :last_login_ip, :created_at,
27
+ :updated_at, :lock_version]
28
+ attrs_to_save = attributes.clone.delete_if do |k, v|
29
+ attr_list.include?(k.to_sym)
30
+ end
31
+ if self.respond_to?(:password) && self.respond_to?(:password_confirmation)
32
+ attrs_to_save.merge!(:password => password, :password_confirmation => password_confirmation)
33
+ end
34
+ attrs_to_save.reject!{|k, v| v.blank? || !self.respond_to?(k)}
35
+ end
36
+ end
37
+ end
38
+ end