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,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