tfe-authlogic_openid 0.1.0

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 (39) hide show
  1. data/CHANGELOG.rdoc +25 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Manifest.txt +38 -0
  4. data/README.rdoc +93 -0
  5. data/Rakefile +137 -0
  6. data/init.rb +1 -0
  7. data/lib/authlogic_openid.rb +6 -0
  8. data/lib/authlogic_openid/acts_as_authentic.rb +174 -0
  9. data/lib/authlogic_openid/session.rb +125 -0
  10. data/lib/authlogic_openid/version.rb +51 -0
  11. data/test/acts_as_authentic_test.rb +105 -0
  12. data/test/fixtures/users.yml +9 -0
  13. data/test/libs/open_id_authentication/CHANGELOG +35 -0
  14. data/test/libs/open_id_authentication/README +231 -0
  15. data/test/libs/open_id_authentication/Rakefile +22 -0
  16. data/test/libs/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb +11 -0
  17. data/test/libs/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb +20 -0
  18. data/test/libs/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb +26 -0
  19. data/test/libs/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb +11 -0
  20. data/test/libs/open_id_authentication/init.rb +18 -0
  21. data/test/libs/open_id_authentication/lib/open_id_authentication.rb +244 -0
  22. data/test/libs/open_id_authentication/lib/open_id_authentication/association.rb +9 -0
  23. data/test/libs/open_id_authentication/lib/open_id_authentication/db_store.rb +55 -0
  24. data/test/libs/open_id_authentication/lib/open_id_authentication/mem_cache_store.rb +73 -0
  25. data/test/libs/open_id_authentication/lib/open_id_authentication/nonce.rb +5 -0
  26. data/test/libs/open_id_authentication/lib/open_id_authentication/request.rb +23 -0
  27. data/test/libs/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb +20 -0
  28. data/test/libs/open_id_authentication/tasks/open_id_authentication_tasks.rake +30 -0
  29. data/test/libs/open_id_authentication/test/mem_cache_store_test.rb +151 -0
  30. data/test/libs/open_id_authentication/test/normalize_test.rb +32 -0
  31. data/test/libs/open_id_authentication/test/open_id_authentication_test.rb +46 -0
  32. data/test/libs/open_id_authentication/test/status_test.rb +14 -0
  33. data/test/libs/open_id_authentication/test/test_helper.rb +17 -0
  34. data/test/libs/rails_trickery.rb +41 -0
  35. data/test/libs/user.rb +3 -0
  36. data/test/libs/user_session.rb +2 -0
  37. data/test/session_test.rb +32 -0
  38. data/test/test_helper.rb +78 -0
  39. metadata +107 -0
@@ -0,0 +1,5 @@
1
+ module OpenIdAuthentication
2
+ class Nonce < ActiveRecord::Base
3
+ set_table_name :open_id_authentication_nonces
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ module OpenIdAuthentication
2
+ module Request
3
+ def self.included(base)
4
+ base.alias_method_chain :request_method, :openid
5
+ end
6
+
7
+ def request_method_with_openid
8
+ if !parameters[:_method].blank? && parameters[:open_id_complete] == '1'
9
+ parameters[:_method].to_sym
10
+ else
11
+ request_method_without_openid
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ # In Rails 2.3, the request object has been renamed
18
+ # from AbstractRequest to Request
19
+ if defined? ActionController::Request
20
+ ActionController::Request.send :include, OpenIdAuthentication::Request
21
+ else
22
+ ActionController::AbstractRequest.send :include, OpenIdAuthentication::Request
23
+ end
@@ -0,0 +1,20 @@
1
+ # http://trac.openidenabled.com/trac/ticket/156
2
+ module OpenID
3
+ @@timeout_threshold = 20
4
+
5
+ def self.timeout_threshold
6
+ @@timeout_threshold
7
+ end
8
+
9
+ def self.timeout_threshold=(value)
10
+ @@timeout_threshold = value
11
+ end
12
+
13
+ class StandardFetcher
14
+ def make_http(uri)
15
+ http = @proxy.new(uri.host, uri.port)
16
+ http.read_timeout = http.open_timeout = OpenID.timeout_threshold
17
+ http
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ namespace :open_id_authentication do
2
+ namespace :db do
3
+ desc "Creates authentication tables for use with OpenIdAuthentication"
4
+ task :create => :environment do
5
+ generate_migration(["open_id_authentication_tables", "add_open_id_authentication_tables"])
6
+ end
7
+
8
+ desc "Upgrade authentication tables from ruby-openid 1.x.x to 2.x.x"
9
+ task :upgrade => :environment do
10
+ generate_migration(["upgrade_open_id_authentication_tables", "upgrade_open_id_authentication_tables"])
11
+ end
12
+
13
+ def generate_migration(args)
14
+ require 'rails_generator'
15
+ require 'rails_generator/scripts/generate'
16
+
17
+ if ActiveRecord::Base.connection.supports_migrations?
18
+ Rails::Generator::Scripts::Generate.new.run(args)
19
+ else
20
+ raise "Task unavailable to this database (no migration support)"
21
+ end
22
+ end
23
+
24
+ desc "Clear the authentication tables"
25
+ task :clear => :environment do
26
+ OpenIdAuthentication::DbStore.cleanup_nonces
27
+ OpenIdAuthentication::DbStore.cleanup_associations
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,151 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require File.dirname(__FILE__) + '/../lib/open_id_authentication/mem_cache_store'
3
+
4
+ # Mock MemCacheStore with MemoryStore for testing
5
+ class OpenIdAuthentication::MemCacheStore < OpenID::Store::Interface
6
+ def initialize(*addresses)
7
+ @connection = ActiveSupport::Cache::MemoryStore.new
8
+ end
9
+ end
10
+
11
+ class MemCacheStoreTest < Test::Unit::TestCase
12
+ ALLOWED_HANDLE = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
13
+
14
+ def setup
15
+ @store = OpenIdAuthentication::MemCacheStore.new
16
+ end
17
+
18
+ def test_store
19
+ server_url = "http://www.myopenid.com/openid"
20
+ assoc = gen_assoc(0)
21
+
22
+ # Make sure that a missing association returns no result
23
+ assert_retrieve(server_url)
24
+
25
+ # Check that after storage, getting returns the same result
26
+ @store.store_association(server_url, assoc)
27
+ assert_retrieve(server_url, nil, assoc)
28
+
29
+ # more than once
30
+ assert_retrieve(server_url, nil, assoc)
31
+
32
+ # Storing more than once has no ill effect
33
+ @store.store_association(server_url, assoc)
34
+ assert_retrieve(server_url, nil, assoc)
35
+
36
+ # Removing an association that does not exist returns not present
37
+ assert_remove(server_url, assoc.handle + 'x', false)
38
+
39
+ # Removing an association that does not exist returns not present
40
+ assert_remove(server_url + 'x', assoc.handle, false)
41
+
42
+ # Removing an association that is present returns present
43
+ assert_remove(server_url, assoc.handle, true)
44
+
45
+ # but not present on subsequent calls
46
+ assert_remove(server_url, assoc.handle, false)
47
+
48
+ # Put assoc back in the store
49
+ @store.store_association(server_url, assoc)
50
+
51
+ # More recent and expires after assoc
52
+ assoc2 = gen_assoc(1)
53
+ @store.store_association(server_url, assoc2)
54
+
55
+ # After storing an association with a different handle, but the
56
+ # same server_url, the handle with the later expiration is returned.
57
+ assert_retrieve(server_url, nil, assoc2)
58
+
59
+ # We can still retrieve the older association
60
+ assert_retrieve(server_url, assoc.handle, assoc)
61
+
62
+ # Plus we can retrieve the association with the later expiration
63
+ # explicitly
64
+ assert_retrieve(server_url, assoc2.handle, assoc2)
65
+
66
+ # More recent, and expires earlier than assoc2 or assoc. Make sure
67
+ # that we're picking the one with the latest issued date and not
68
+ # taking into account the expiration.
69
+ assoc3 = gen_assoc(2, 100)
70
+ @store.store_association(server_url, assoc3)
71
+
72
+ assert_retrieve(server_url, nil, assoc3)
73
+ assert_retrieve(server_url, assoc.handle, assoc)
74
+ assert_retrieve(server_url, assoc2.handle, assoc2)
75
+ assert_retrieve(server_url, assoc3.handle, assoc3)
76
+
77
+ assert_remove(server_url, assoc2.handle, true)
78
+
79
+ assert_retrieve(server_url, nil, assoc3)
80
+ assert_retrieve(server_url, assoc.handle, assoc)
81
+ assert_retrieve(server_url, assoc2.handle, nil)
82
+ assert_retrieve(server_url, assoc3.handle, assoc3)
83
+
84
+ assert_remove(server_url, assoc2.handle, false)
85
+ assert_remove(server_url, assoc3.handle, true)
86
+
87
+ assert_retrieve(server_url, nil, assoc)
88
+ assert_retrieve(server_url, assoc.handle, assoc)
89
+ assert_retrieve(server_url, assoc2.handle, nil)
90
+ assert_retrieve(server_url, assoc3.handle, nil)
91
+
92
+ assert_remove(server_url, assoc2.handle, false)
93
+ assert_remove(server_url, assoc.handle, true)
94
+ assert_remove(server_url, assoc3.handle, false)
95
+
96
+ assert_retrieve(server_url, nil, nil)
97
+ assert_retrieve(server_url, assoc.handle, nil)
98
+ assert_retrieve(server_url, assoc2.handle, nil)
99
+ assert_retrieve(server_url, assoc3.handle, nil)
100
+
101
+ assert_remove(server_url, assoc2.handle, false)
102
+ assert_remove(server_url, assoc.handle, false)
103
+ assert_remove(server_url, assoc3.handle, false)
104
+ end
105
+
106
+ def test_nonce
107
+ server_url = "http://www.myopenid.com/openid"
108
+
109
+ [server_url, ''].each do |url|
110
+ nonce1 = OpenID::Nonce::mk_nonce
111
+
112
+ assert_nonce(nonce1, true, url, "#{url}: nonce allowed by default")
113
+ assert_nonce(nonce1, false, url, "#{url}: nonce not allowed twice")
114
+ assert_nonce(nonce1, false, url, "#{url}: nonce not allowed third time")
115
+
116
+ # old nonces shouldn't pass
117
+ old_nonce = OpenID::Nonce::mk_nonce(3600)
118
+ assert_nonce(old_nonce, false, url, "Old nonce #{old_nonce.inspect} passed")
119
+ end
120
+ end
121
+
122
+ private
123
+ def gen_assoc(issued, lifetime = 600)
124
+ secret = OpenID::CryptUtil.random_string(20, nil)
125
+ handle = OpenID::CryptUtil.random_string(128, ALLOWED_HANDLE)
126
+ OpenID::Association.new(handle, secret, Time.now + issued, lifetime, 'HMAC-SHA1')
127
+ end
128
+
129
+ def assert_retrieve(url, handle = nil, expected = nil)
130
+ assoc = @store.get_association(url, handle)
131
+
132
+ if expected.nil?
133
+ assert_nil(assoc)
134
+ else
135
+ assert_equal(expected, assoc)
136
+ assert_equal(expected.handle, assoc.handle)
137
+ assert_equal(expected.secret, assoc.secret)
138
+ end
139
+ end
140
+
141
+ def assert_remove(url, handle, expected)
142
+ present = @store.remove_association(url, handle)
143
+ assert_equal(expected, present)
144
+ end
145
+
146
+ def assert_nonce(nonce, expected, server_url, msg = "")
147
+ stamp, salt = OpenID::Nonce::split_nonce(nonce)
148
+ actual = @store.use_nonce(server_url, stamp, salt)
149
+ assert_equal(expected, actual, msg)
150
+ end
151
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class NormalizeTest < Test::Unit::TestCase
4
+ include OpenIdAuthentication
5
+
6
+ NORMALIZATIONS = {
7
+ "openid.aol.com/nextangler" => "http://openid.aol.com/nextangler",
8
+ "http://openid.aol.com/nextangler" => "http://openid.aol.com/nextangler",
9
+ "https://openid.aol.com/nextangler" => "https://openid.aol.com/nextangler",
10
+ "HTTP://OPENID.AOL.COM/NEXTANGLER" => "http://openid.aol.com/NEXTANGLER",
11
+ "HTTPS://OPENID.AOL.COM/NEXTANGLER" => "https://openid.aol.com/NEXTANGLER",
12
+ "loudthinking.com" => "http://loudthinking.com/",
13
+ "http://loudthinking.com" => "http://loudthinking.com/",
14
+ "http://loudthinking.com:80" => "http://loudthinking.com/",
15
+ "https://loudthinking.com:443" => "https://loudthinking.com/",
16
+ "http://loudthinking.com:8080" => "http://loudthinking.com:8080/",
17
+ "techno-weenie.net" => "http://techno-weenie.net/",
18
+ "http://techno-weenie.net" => "http://techno-weenie.net/",
19
+ "http://techno-weenie.net " => "http://techno-weenie.net/",
20
+ "=name" => "=name"
21
+ }
22
+
23
+ def test_normalizations
24
+ NORMALIZATIONS.each do |from, to|
25
+ assert_equal to, normalize_identifier(from)
26
+ end
27
+ end
28
+
29
+ def test_broken_open_id
30
+ assert_raises(InvalidOpenId) { normalize_identifier(nil) }
31
+ end
32
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class OpenIdAuthenticationTest < Test::Unit::TestCase
4
+ def setup
5
+ @controller = Class.new do
6
+ include OpenIdAuthentication
7
+ def params() {} end
8
+ end.new
9
+ end
10
+
11
+ def test_authentication_should_fail_when_the_identity_server_is_missing
12
+ open_id_consumer = mock()
13
+ open_id_consumer.expects(:begin).raises(OpenID::OpenIDError)
14
+ @controller.expects(:open_id_consumer).returns(open_id_consumer)
15
+ @controller.expects(:logger).returns(mock(:error => true))
16
+
17
+ @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url|
18
+ assert result.missing?
19
+ assert_equal "Sorry, the OpenID server couldn't be found", result.message
20
+ end
21
+ end
22
+
23
+ def test_authentication_should_be_invalid_when_the_identity_url_is_invalid
24
+ @controller.send(:authenticate_with_open_id, "!") do |result, identity_url|
25
+ assert result.invalid?, "Result expected to be invalid but was not"
26
+ assert_equal "Sorry, but this does not appear to be a valid OpenID", result.message
27
+ end
28
+ end
29
+
30
+ def test_authentication_should_fail_when_the_identity_server_times_out
31
+ open_id_consumer = mock()
32
+ open_id_consumer.expects(:begin).raises(Timeout::Error, "Identity Server took too long.")
33
+ @controller.expects(:open_id_consumer).returns(open_id_consumer)
34
+ @controller.expects(:logger).returns(mock(:error => true))
35
+
36
+ @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url|
37
+ assert result.missing?
38
+ assert_equal "Sorry, the OpenID server couldn't be found", result.message
39
+ end
40
+ end
41
+
42
+ def test_authentication_should_begin_when_the_identity_server_is_present
43
+ @controller.expects(:begin_open_id_authentication)
44
+ @controller.send(:authenticate_with_open_id, "http://someone.example.com")
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class StatusTest < Test::Unit::TestCase
4
+ include OpenIdAuthentication
5
+
6
+ def test_state_conditional
7
+ assert Result[:missing].missing?
8
+ assert Result[:missing].unsuccessful?
9
+ assert !Result[:missing].successful?
10
+
11
+ assert Result[:successful].successful?
12
+ assert !Result[:successful].unsuccessful?
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+
4
+ gem 'activesupport'
5
+ require 'active_support'
6
+
7
+ gem 'actionpack'
8
+ require 'action_controller'
9
+
10
+ gem 'mocha'
11
+ require 'mocha'
12
+
13
+ gem 'ruby-openid'
14
+ require 'openid'
15
+
16
+ RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT
17
+ require File.dirname(__FILE__) + "/../lib/open_id_authentication"
@@ -0,0 +1,41 @@
1
+ # The only reason I am doing all of this non sense is becuase the openid_authentication requires that
2
+ # these constants be present. The only other alternative is to use an entire rails application for testing
3
+ # which is a little too overboard for this, I think.
4
+
5
+ RAILS_ROOT = ''
6
+
7
+ class ActionController < Authlogic::TestCase::MockController
8
+ class Request < Authlogic::TestCase::MockRequest
9
+ def request_method
10
+ ""
11
+ end
12
+ end
13
+
14
+ def root_url
15
+ ''
16
+ end
17
+
18
+ def request
19
+ return @request if defined?(@request)
20
+ super
21
+ # Rails does some crazy s#!t with the "method" method. If I don't do this I get a "wrong arguments (0 for 1) error"
22
+ @request.class.class_eval do
23
+ def method
24
+ nil
25
+ end
26
+ end
27
+ @request
28
+ end
29
+
30
+ def url_for(*args)
31
+ ''
32
+ end
33
+
34
+ def redirecting_to
35
+ @redirect_to
36
+ end
37
+
38
+ def redirect_to(*args)
39
+ @redirect_to = args
40
+ end
41
+ end
data/test/libs/user.rb ADDED
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ acts_as_authentic
3
+ end
@@ -0,0 +1,2 @@
1
+ class UserSession < Authlogic::Session::Base
2
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class SessionTest < ActiveSupport::TestCase
4
+ def test_openid_identifier
5
+ session = UserSession.new
6
+ assert session.respond_to?(:openid_identifier)
7
+ session.openid_identifier = "test"
8
+ assert_equal "http://test/", session.openid_identifier
9
+ end
10
+
11
+ def test_validate_openid_error
12
+ session = UserSession.new
13
+ session.openid_identifier = "yes"
14
+ session.openid_identifier = "%"
15
+ assert_nil session.openid_identifier
16
+ assert !session.save
17
+ assert session.errors.on(:openid_identifier)
18
+ end
19
+
20
+ def test_validate_by_nil_openid_identifier
21
+ session = UserSession.new
22
+ assert !session.save
23
+ assert !redirecting_to_yahoo?
24
+ end
25
+
26
+ def test_validate_by_correct_openid_identifier
27
+ session = UserSession.new
28
+ session.openid_identifier = "https://me.yahoo.com/a/9W0FJjRj0o981TMSs0vqVxPdmMUVOQ--"
29
+ assert !session.save
30
+ assert redirecting_to_yahoo?
31
+ end
32
+ end
@@ -0,0 +1,78 @@
1
+ require "test/unit"
2
+ require "rubygems"
3
+ require "ruby-debug"
4
+ require "active_record"
5
+
6
+ ActiveRecord::Schema.verbose = false
7
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
8
+ ActiveRecord::Base.configurations = true
9
+ ActiveRecord::Schema.define(:version => 1) do
10
+ create_table :open_id_authentication_associations, :force => true do |t|
11
+ t.integer :issued, :lifetime
12
+ t.string :handle, :assoc_type
13
+ t.binary :server_url, :secret
14
+ end
15
+
16
+ create_table :open_id_authentication_nonces, :force => true do |t|
17
+ t.integer :timestamp, :null => false
18
+ t.string :server_url, :null => true
19
+ t.string :salt, :null => false
20
+ end
21
+
22
+ create_table :users do |t|
23
+ t.datetime :created_at
24
+ t.datetime :updated_at
25
+ t.integer :lock_version, :default => 0
26
+ t.string :login
27
+ t.string :crypted_password
28
+ t.string :password_salt
29
+ t.string :persistence_token
30
+ t.string :single_access_token
31
+ t.string :perishable_token
32
+ t.string :openid_identifier
33
+ t.string :email
34
+ t.string :first_name
35
+ t.string :last_name
36
+ t.integer :login_count, :default => 0, :null => false
37
+ t.integer :failed_login_count, :default => 0, :null => false
38
+ t.datetime :last_request_at
39
+ t.datetime :current_login_at
40
+ t.datetime :last_login_at
41
+ t.string :current_login_ip
42
+ t.string :last_login_ip
43
+ end
44
+ end
45
+
46
+ require "active_record/fixtures"
47
+ require "openid"
48
+ Rails = true # to trick authlogic into loading the rails adapter
49
+ require File.dirname(__FILE__) + "/../../authlogic/lib/authlogic"
50
+ require File.dirname(__FILE__) + "/../../authlogic/lib/authlogic/test_case"
51
+ #require File.dirname(__FILE__) + "/libs/rails_trickery"
52
+ require File.dirname(__FILE__) + '/libs/open_id_authentication/lib/open_id_authentication'
53
+ require File.dirname(__FILE__) + '/../lib/authlogic_openid' unless defined?(AuthlogicOpenid)
54
+ require File.dirname(__FILE__) + '/libs/user'
55
+ require File.dirname(__FILE__) + '/libs/user_session'
56
+
57
+ class ActiveSupport::TestCase
58
+ include ActiveRecord::TestFixtures
59
+ self.fixture_path = File.dirname(__FILE__) + "/fixtures"
60
+ self.use_transactional_fixtures = false
61
+ self.use_instantiated_fixtures = false
62
+ self.pre_loaded_fixtures = false
63
+ fixtures :all
64
+ setup :activate_authlogic
65
+
66
+ private
67
+ def activate_authlogic
68
+ Authlogic::Session::Base.controller = controller
69
+ end
70
+
71
+ def controller
72
+ @controller ||= Authlogic::ControllerAdapters::RailsAdapter.new(ActionController.new)
73
+ end
74
+
75
+ def redirecting_to_yahoo?
76
+ controller.redirecting_to.to_s =~ /^https:\/\/open.login.yahooapis.com\/openid\/op\/auth/
77
+ end
78
+ end