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.
- data/MIT-LICENSE +20 -0
- data/README.markdown +234 -0
- data/Rakefile +85 -0
- data/init.rb +1 -0
- data/lib/authlogic-connect.rb +39 -0
- data/lib/authlogic_connect/access_token.rb +61 -0
- data/lib/authlogic_connect/authlogic_connect.rb +46 -0
- data/lib/authlogic_connect/callback_filter.rb +19 -0
- data/lib/authlogic_connect/common.rb +10 -0
- data/lib/authlogic_connect/common/session.rb +30 -0
- data/lib/authlogic_connect/common/state.rb +45 -0
- data/lib/authlogic_connect/common/user.rb +77 -0
- data/lib/authlogic_connect/common/variables.rb +124 -0
- data/lib/authlogic_connect/engine.rb +14 -0
- data/lib/authlogic_connect/ext.rb +56 -0
- data/lib/authlogic_connect/oauth.rb +14 -0
- data/lib/authlogic_connect/oauth/helper.rb +20 -0
- data/lib/authlogic_connect/oauth/process.rb +75 -0
- data/lib/authlogic_connect/oauth/session.rb +62 -0
- data/lib/authlogic_connect/oauth/state.rb +60 -0
- data/lib/authlogic_connect/oauth/tokens/aol_token.rb +2 -0
- data/lib/authlogic_connect/oauth/tokens/facebook_token.rb +11 -0
- data/lib/authlogic_connect/oauth/tokens/foursquare_token.rb +15 -0
- data/lib/authlogic_connect/oauth/tokens/get_satisfaction_token.rb +9 -0
- data/lib/authlogic_connect/oauth/tokens/github_token.rb +14 -0
- data/lib/authlogic_connect/oauth/tokens/google_token.rb +41 -0
- data/lib/authlogic_connect/oauth/tokens/linked_in_token.rb +19 -0
- data/lib/authlogic_connect/oauth/tokens/meetup_token.rb +12 -0
- data/lib/authlogic_connect/oauth/tokens/myspace_token.rb +26 -0
- data/lib/authlogic_connect/oauth/tokens/netflix_token.rb +10 -0
- data/lib/authlogic_connect/oauth/tokens/oauth_token.rb +164 -0
- data/lib/authlogic_connect/oauth/tokens/ohloh_token.rb +9 -0
- data/lib/authlogic_connect/oauth/tokens/opensocial_token.rb +0 -0
- data/lib/authlogic_connect/oauth/tokens/twitter_token.rb +8 -0
- data/lib/authlogic_connect/oauth/tokens/vimeo_token.rb +18 -0
- data/lib/authlogic_connect/oauth/tokens/yahoo_token.rb +19 -0
- data/lib/authlogic_connect/oauth/user.rb +64 -0
- data/lib/authlogic_connect/oauth/variables.rb +64 -0
- data/lib/authlogic_connect/openid.rb +11 -0
- data/lib/authlogic_connect/openid/process.rb +74 -0
- data/lib/authlogic_connect/openid/session.rb +56 -0
- data/lib/authlogic_connect/openid/state.rb +48 -0
- data/lib/authlogic_connect/openid/tokens/aol_token.rb +0 -0
- data/lib/authlogic_connect/openid/tokens/blogger_token.rb +0 -0
- data/lib/authlogic_connect/openid/tokens/flickr_token.rb +0 -0
- data/lib/authlogic_connect/openid/tokens/my_openid_token.rb +3 -0
- data/lib/authlogic_connect/openid/tokens/openid_token.rb +9 -0
- data/lib/authlogic_connect/openid/user.rb +38 -0
- data/lib/authlogic_connect/openid/variables.rb +19 -0
- data/lib/authlogic_connect/rack_state.rb +19 -0
- data/lib/open_id_authentication.rb +127 -0
- data/rails/init.rb +19 -0
- data/test/controllers/test_users_controller.rb +21 -0
- data/test/database.yml +3 -0
- data/test/libs/database.rb +47 -0
- data/test/libs/user.rb +7 -0
- data/test/libs/user_session.rb +2 -0
- data/test/test_helper.rb +178 -0
- data/test/test_oauth.rb +178 -0
- data/test/test_openid.rb +71 -0
- data/test/test_user.rb +85 -0
- metadata +244 -0
File without changes
|
@@ -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
|
File without changes
|
File without changes
|
@@ -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
|