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,54 @@
1
+ # all these methods must return true or false
2
+ module AuthlogicConnect::Oauth::State
3
+
4
+ # 1. to call
5
+ # checks that we just passed parameters to it,
6
+ # and that the parameters say 'authentication_method' == 'oauth'
7
+ def oauth_request?
8
+ !auth_params.nil? && oauth_provider?
9
+ end
10
+
11
+ # 2. from call
12
+ # checks that the correct session variables are there
13
+ def oauth_response?
14
+ !oauth_response.nil? && !auth_session.nil? && auth_session[:auth_request_class] == self.class.name && auth_session[:auth_method] == "oauth"
15
+ end
16
+ alias_method :oauth_complete?, :oauth_response?
17
+
18
+ # 3. either to or from call
19
+ def using_oauth?
20
+ oauth_request? || oauth_response?
21
+ end
22
+
23
+ def new_oauth_request?
24
+ oauth_response.blank?
25
+ end
26
+
27
+ def oauth_provider?
28
+ !oauth_provider.nil? && !oauth_provider.empty?
29
+ end
30
+
31
+ # main method we call on validation
32
+ def authenticating_with_oauth?
33
+ correct_request_class? && using_oauth?
34
+ end
35
+
36
+ def allow_oauth_redirect?
37
+ authenticating_with_oauth? && !oauth_complete?
38
+ end
39
+
40
+ # both checks if it can redirect, and does the redirect.
41
+ # is there a more concise way to do this?
42
+ def redirecting_to_oauth_server?
43
+ if allow_oauth_redirect?
44
+ redirect_to_oauth
45
+ return true
46
+ end
47
+ return false
48
+ end
49
+
50
+ def validate_password_with_oauth?
51
+ !using_oauth? && require_password?
52
+ end
53
+
54
+ end
@@ -0,0 +1,11 @@
1
+ # http://www.facebook.com/developers/apps.php
2
+ # http://developers.facebook.com/setup/
3
+ class FacebookToken < OauthToken
4
+
5
+ version 2.0
6
+
7
+ settings "https://graph.facebook.com",
8
+ :authorize_url => "https://graph.facebook.com/oauth/authorize",
9
+ :scope => "email, offline_access"
10
+
11
+ end
@@ -0,0 +1,9 @@
1
+ # http://getsatisfaction.com/developers/oauth
2
+ class GetSatisfactionToken < OauthToken
3
+
4
+ settings "http://getsatisfaction.com",
5
+ :request_token_path => "/api/request_token",
6
+ :authorize_url => "/api/authorize",
7
+ :access_token_path => "/api/access_token"
8
+
9
+ end
@@ -0,0 +1,41 @@
1
+ # http://code.google.com/apis/accounts/docs/OAuth_ref.html
2
+ # http://code.google.com/apis/accounts/docs/OpenID.html#settingup
3
+ # http://code.google.com/apis/accounts/docs/OAuth.html
4
+ # http://code.google.com/apis/accounts/docs/RegistrationForWebAppsAuto.html
5
+ # http://www.manu-j.com/blog/add-google-oauth-ruby-on-rails-sites/214/
6
+ # http://googlecodesamples.com/oauth_playground/
7
+ # Scopes:
8
+ # Analytics https://www.google.com/analytics/feeds/
9
+ # Google Base http://www.google.com/base/feeds/
10
+ # Book Search http://www.google.com/books/feeds/
11
+ # Blogger http://www.blogger.com/feeds/
12
+ # Calendar http://www.google.com/calendar/feeds/
13
+ # Contacts http://www.google.com/m8/feeds/
14
+ # Documents List http://docs.google.com/feeds/
15
+ # Finance http://finance.google.com/finance/feeds/
16
+ # GMail https://mail.google.com/mail/feed/atom
17
+ # Health https://www.google.com/health/feeds/
18
+ # H9 https://www.google.com/h9/feeds/
19
+ # Maps http://maps.google.com/maps/feeds/
20
+ # OpenSocial http://www-opensocial.googleusercontent.com/api/people/
21
+ # orkut http://www.orkut.com/social/rest
22
+ # Picasa Web http://picasaweb.google.com/data/
23
+ # Sidewiki http://www.google.com/sidewiki/feeds/
24
+ # Sites http://sites.google.com/feeds/
25
+ # Spreadsheets http://spreadsheets.google.com/feeds/
26
+ # Webmaster Tools http://www.google.com/webmasters/tools/feeds/
27
+ # YouTube http://gdata.youtube.com
28
+ class GoogleToken < OauthToken
29
+
30
+ settings "https://www.google.com",
31
+ :request_token_path => "/accounts/OAuthGetRequestToken",
32
+ :authorize_path => "/accounts/OAuthAuthorizeToken",
33
+ :access_token_path => "/accounts/OAuthGetAccessToken",
34
+ :scope => "https://www.google.com/m8/feeds/"
35
+
36
+ key do |access_token|
37
+ body = JSON.parse(access_token.get("https://www.google.com/m8/feeds/contacts/default/full?alt=json&max-results=0").body)
38
+ email = body["feed"]["author"].first["email"]["$t"] # $t is some weird google json thing
39
+ end
40
+
41
+ end
@@ -0,0 +1,19 @@
1
+ # http://developer.linkedin.com/docs/DOC-1008
2
+ # https://www.linkedin.com/secure/developer
3
+ # http://github.com/pengwynn/linkedin/tree/master/lib/linked_in/
4
+ class LinkedInToken < OauthToken
5
+
6
+ key do |access_token|
7
+ body = access_token.get("https://api.linkedin.com/v1/people/~:(id)").body
8
+ id = body.gsub("<id>([^><]+)</id>", "\\1") # so we don't need to also import nokogiri
9
+ id
10
+ end
11
+
12
+ settings "https://api.linkedin.com",
13
+ :request_token_path => "/uas/oauth/requestToken",
14
+ :access_token_path => "/uas/oauth/accessToken",
15
+ :authorize_path => "/uas/oauth/authorize",
16
+ :http_method => "get",
17
+ :scheme => :query_string
18
+
19
+ end
@@ -0,0 +1,26 @@
1
+ # http://wiki.developer.myspace.com/index.php?title=Category:MySpaceID
2
+ # http://developerwiki.myspace.com/index.php?title=OAuth_REST_API_Usage_-_Authentication_Process
3
+ # http://developerwiki.myspace.com/index.php?title=How_to_Set_Up_a_New_Application_for_OpenID
4
+ # http://developer.myspace.com/Modules/Apps/Pages/ApplyDevSandbox.aspx
5
+ # after you've signed up:
6
+ # http://developer.myspace.com/modules/apps/pages/createappaccount.aspx
7
+ # "Create a MySpaceID App"
8
+ # http://developer.myspace.com/modules/apps/pages/editapp.aspx?appid=188312&mode=create
9
+ # http://developer.myspace.com/Modules/APIs/Pages/OAuthTool.aspx
10
+ # http://developer.myspace.com/Community/forums/p/3626/15947.aspx
11
+ class MyspaceToken < OauthToken
12
+
13
+ # http://wiki.developer.myspace.com/index.php?title=Portable_Contacts_REST_Resources
14
+ key do |access_token|
15
+ body = JSON.parse(access_token.get("/v2/people/@me/@self?format=json").body)
16
+ id = body["entry"]["id"]
17
+ end
18
+
19
+ settings "http://api.myspace.com",
20
+ :request_token_path => "/request_token",
21
+ :authorize_path => "/authorize",
22
+ :access_token_path => "/access_token",
23
+ :http_method => "get",
24
+ :scheme => :query_string
25
+
26
+ end
@@ -0,0 +1,131 @@
1
+ class OauthToken < Token
2
+
3
+ def client
4
+ unless @client
5
+ if oauth_version == 1.0
6
+ @client = OAuth::AccessToken.new(self.consumer, self.token, self.secret)
7
+ else
8
+ @client = OAuth2::AccessToken.new(self.consumer, self.token)
9
+ end
10
+ end
11
+
12
+ @client
13
+ end
14
+
15
+ def oauth_version
16
+ self.class.oauth_version
17
+ end
18
+
19
+ def get(path, options = {})
20
+ client.get(path)
21
+ end
22
+
23
+ class << self
24
+
25
+ # oauth version, 1.0 or 2.0
26
+ def version(value)
27
+ @oauth_version = value
28
+ end
29
+
30
+ def oauth_version
31
+ @oauth_version ||= 1.0
32
+ end
33
+
34
+ # unique key that we will use from the AccessToken response
35
+ # to identify the user by.
36
+ # in Twitter, its "user_id". Twitter has "screen_name", but that's
37
+ # more subject to change than user_id. Pick whatever is least likely to change
38
+ def key(value = nil, &block)
39
+ if block_given?
40
+ @oauth_key = block
41
+ else
42
+ @oauth_key = value.is_a?(Symbol) ? value : value.to_sym
43
+ end
44
+ end
45
+
46
+ def oauth_key
47
+ @oauth_key
48
+ end
49
+
50
+ def consumer
51
+ unless @consumer
52
+ if oauth_version == 1.0
53
+ @consumer = OAuth::Consumer.new(credentials[:key], credentials[:secret], config.merge(credentials[:options] || {}))
54
+ else
55
+ @consumer = OAuth2::Client.new(credentials[:key], credentials[:secret], config)
56
+ end
57
+ end
58
+
59
+ @consumer
60
+ end
61
+
62
+ # if we're lucky we can find it by the token.
63
+ def find_by_key_or_token(key, token, options = {})
64
+ result = self.find_by_key(key, options) unless key.nil?
65
+ unless result
66
+ result = self.find_by_token(token, options) unless token.nil?
67
+ end
68
+ result
69
+ end
70
+
71
+ # this is a wrapper around oauth 1 and 2.
72
+ # it looks obscure, but from the api point of view
73
+ # you won't have to worry about it's implementation.
74
+ # in oauth 1.0, key = oauth_token, secret = oauth_secret
75
+ # in oauth 2.0, key = code, secret = access_token
76
+ def get_token_and_secret(options = {})
77
+ oauth_verifier = options[:oauth_verifier]
78
+ redirect_uri = options[:redirect_uri]
79
+ token = options[:token]
80
+ secret = options[:secret]
81
+ if oauth_version == 1.0
82
+ access = request_token(token, secret).get_access_token(:oauth_verifier => oauth_verifier)
83
+ result = {:token => access.token, :secret => access.secret, :key => nil}
84
+ if self.oauth_key
85
+ if oauth_key.is_a?(Proc)
86
+ result[:key] = oauth_key.call(access)
87
+ else
88
+ result[:key] = access.params[self.oauth_key] || access.params[self.oauth_key.to_s] # try both
89
+ end
90
+ else
91
+ puts "Access Token: #{access.inspect}"
92
+ raise "please set an oauth key for #{service_name.to_s}"
93
+ end
94
+ else
95
+ access = consumer.web_server.get_access_token(secret, :redirect_uri => redirect_uri)
96
+ result = {:token => access.token, :secret => secret, :key => nil}
97
+ end
98
+ result
99
+ end
100
+
101
+ # this is a cleaner method so we can access the authorize_url
102
+ # from oauth 1 or 2
103
+ def authorize_url(callback_url, &block)
104
+ if oauth_version == 1.0
105
+ request = get_request_token(callback_url)
106
+ yield request if block_given?
107
+ return request.authorize_url
108
+ else
109
+ options = {:redirect_uri => callback_url}
110
+ options[:scope] = self.config[:scope] unless self.config[:scope].blank?
111
+ return consumer.web_server.authorize_url(options)
112
+ end
113
+ end
114
+
115
+ def request_token(token, secret)
116
+ OAuth::RequestToken.new(consumer, token, secret)
117
+ end
118
+
119
+ # if you pass a hash as the second parameter to consumer.get_request_token,
120
+ # ruby oauth will think this is a form and all sorts of bad things happen
121
+ def get_request_token(callback_url)
122
+ options = {:scope => config[:scope]} if config[:scope]
123
+ consumer.get_request_token({:oauth_callback => callback_url}, options)
124
+ end
125
+
126
+ def get_access_token(oauth_verifier)
127
+ request_token.get_access_token(:oauth_verifier => oauth_verifier)
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,8 @@
1
+ class TwitterToken < OauthToken
2
+
3
+ key :user_id
4
+
5
+ settings "http://twitter.com",
6
+ :authorize_url => "http://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,68 @@
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
+ end
28
+
29
+ # email needs to be optional for oauth
30
+ base.validate_email_field = false
31
+ end
32
+
33
+ # user adds a few extra things to this method from Process
34
+ # modules work like inheritance
35
+ def save_oauth_session
36
+ super
37
+ auth_session[:auth_attributes] = attributes.reject!{|k, v| v.blank?} unless is_auth_session?
38
+ end
39
+
40
+ def restore_attributes
41
+ # Restore any attributes which were saved before redirecting to the auth server
42
+ self.attributes = auth_session[:auth_attributes]
43
+ end
44
+
45
+ # single implementation method for oauth.
46
+ # this is called after we get the callback url and we are saving the user
47
+ # to the database.
48
+ # it is called by the validation chain.
49
+ def complete_oauth_transaction
50
+ unless create_oauth_token
51
+ self.errors.add(:tokens, "you have already created an account using your #{token_class.service_name} account, so it")
52
+ end
53
+ end
54
+
55
+ def create_oauth_token
56
+ token = token_class.new(oauth_token_and_secret)
57
+
58
+ if has_token?(oauth_provider) || Token.find_by_key(token.key) || Token.find_by_token(token.token)
59
+ return false
60
+ else
61
+ self.tokens << token
62
+ self.active_token = token
63
+ return true
64
+ end
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,55 @@
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
+ # this is a thick method.
45
+ # it gives you the final key and secret that we will store in the database
46
+ def oauth_token_and_secret
47
+ token_class.get_token_and_secret(
48
+ :token => auth_session[:oauth_request_token],
49
+ :secret => oauth_version == 1.0 ? auth_session[:oauth_request_token_secret] : oauth_token,
50
+ :oauth_verifier => auth_params[:oauth_verifier],
51
+ :redirect_uri => auth_callback_url
52
+ )
53
+ end
54
+
55
+ end