270 lines
9.0 KiB
Ruby
270 lines
9.0 KiB
Ruby
|
require 'test/unit'
|
||
|
require 'openid/store/interface'
|
||
|
require 'openid/store/filesystem'
|
||
|
require 'openid/store/memory'
|
||
|
require 'openid/util'
|
||
|
require 'openid/store/nonce'
|
||
|
require 'openid/association'
|
||
|
|
||
|
module OpenID
|
||
|
module Store
|
||
|
module StoreTestCase
|
||
|
@@allowed_handle = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
|
||
|
@@allowed_nonce = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||
|
|
||
|
def _gen_nonce
|
||
|
OpenID::CryptUtil.random_string(8, @@allowed_nonce)
|
||
|
end
|
||
|
|
||
|
def _gen_handle(n)
|
||
|
OpenID::CryptUtil.random_string(n, @@allowed_handle)
|
||
|
end
|
||
|
|
||
|
def _gen_secret(n, chars=nil)
|
||
|
OpenID::CryptUtil.random_string(n, chars)
|
||
|
end
|
||
|
|
||
|
def _gen_assoc(issued, lifetime=600)
|
||
|
secret = _gen_secret(20)
|
||
|
handle = _gen_handle(128)
|
||
|
OpenID::Association.new(handle, secret, Time.now + issued, lifetime,
|
||
|
'HMAC-SHA1')
|
||
|
end
|
||
|
|
||
|
def _check_retrieve(url, handle=nil, expected=nil)
|
||
|
ret_assoc = @store.get_association(url, handle)
|
||
|
|
||
|
if expected.nil?
|
||
|
assert_nil(ret_assoc)
|
||
|
else
|
||
|
assert_equal(expected, ret_assoc)
|
||
|
assert_equal(expected.handle, ret_assoc.handle)
|
||
|
assert_equal(expected.secret, ret_assoc.secret)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def _check_remove(url, handle, expected)
|
||
|
present = @store.remove_association(url, handle)
|
||
|
assert_equal(expected, present)
|
||
|
end
|
||
|
|
||
|
def test_store
|
||
|
server_url = "http://www.myopenid.com/openid"
|
||
|
assoc = _gen_assoc(issued=0)
|
||
|
|
||
|
# Make sure that a missing association returns no result
|
||
|
_check_retrieve(server_url)
|
||
|
|
||
|
# Check that after storage, getting returns the same result
|
||
|
@store.store_association(server_url, assoc)
|
||
|
_check_retrieve(server_url, nil, assoc)
|
||
|
|
||
|
# more than once
|
||
|
_check_retrieve(server_url, nil, assoc)
|
||
|
|
||
|
# Storing more than once has no ill effect
|
||
|
@store.store_association(server_url, assoc)
|
||
|
_check_retrieve(server_url, nil, assoc)
|
||
|
|
||
|
# Removing an association that does not exist returns not present
|
||
|
_check_remove(server_url, assoc.handle + 'x', false)
|
||
|
|
||
|
# Removing an association that does not exist returns not present
|
||
|
_check_remove(server_url + 'x', assoc.handle, false)
|
||
|
|
||
|
# Removing an association that is present returns present
|
||
|
_check_remove(server_url, assoc.handle, true)
|
||
|
|
||
|
# but not present on subsequent calls
|
||
|
_check_remove(server_url, assoc.handle, false)
|
||
|
|
||
|
# Put assoc back in the store
|
||
|
@store.store_association(server_url, assoc)
|
||
|
|
||
|
# More recent and expires after assoc
|
||
|
assoc2 = _gen_assoc(issued=1)
|
||
|
@store.store_association(server_url, assoc2)
|
||
|
|
||
|
# After storing an association with a different handle, but the
|
||
|
# same server_url, the handle with the later expiration is returned.
|
||
|
_check_retrieve(server_url, nil, assoc2)
|
||
|
|
||
|
# We can still retrieve the older association
|
||
|
_check_retrieve(server_url, assoc.handle, assoc)
|
||
|
|
||
|
# Plus we can retrieve the association with the later expiration
|
||
|
# explicitly
|
||
|
_check_retrieve(server_url, assoc2.handle, assoc2)
|
||
|
|
||
|
# More recent, and expires earlier than assoc2 or assoc. Make sure
|
||
|
# that we're picking the one with the latest issued date and not
|
||
|
# taking into account the expiration.
|
||
|
assoc3 = _gen_assoc(issued=2, lifetime=100)
|
||
|
@store.store_association(server_url, assoc3)
|
||
|
|
||
|
_check_retrieve(server_url, nil, assoc3)
|
||
|
_check_retrieve(server_url, assoc.handle, assoc)
|
||
|
_check_retrieve(server_url, assoc2.handle, assoc2)
|
||
|
_check_retrieve(server_url, assoc3.handle, assoc3)
|
||
|
|
||
|
_check_remove(server_url, assoc2.handle, true)
|
||
|
|
||
|
_check_retrieve(server_url, nil, assoc3)
|
||
|
_check_retrieve(server_url, assoc.handle, assoc)
|
||
|
_check_retrieve(server_url, assoc2.handle, nil)
|
||
|
_check_retrieve(server_url, assoc3.handle, assoc3)
|
||
|
|
||
|
_check_remove(server_url, assoc2.handle, false)
|
||
|
_check_remove(server_url, assoc3.handle, true)
|
||
|
|
||
|
_check_retrieve(server_url, nil, assoc)
|
||
|
_check_retrieve(server_url, assoc.handle, assoc)
|
||
|
_check_retrieve(server_url, assoc2.handle, nil)
|
||
|
_check_retrieve(server_url, assoc3.handle, nil)
|
||
|
|
||
|
_check_remove(server_url, assoc2.handle, false)
|
||
|
_check_remove(server_url, assoc.handle, true)
|
||
|
_check_remove(server_url, assoc3.handle, false)
|
||
|
|
||
|
_check_retrieve(server_url, nil, nil)
|
||
|
_check_retrieve(server_url, assoc.handle, nil)
|
||
|
_check_retrieve(server_url, assoc2.handle, nil)
|
||
|
_check_retrieve(server_url, assoc3.handle, nil)
|
||
|
|
||
|
_check_remove(server_url, assoc2.handle, false)
|
||
|
_check_remove(server_url, assoc.handle, false)
|
||
|
_check_remove(server_url, assoc3.handle, false)
|
||
|
|
||
|
assocValid1 = _gen_assoc(-3600, 7200)
|
||
|
assocValid2 = _gen_assoc(-5)
|
||
|
assocExpired1 = _gen_assoc(-7200, 3600)
|
||
|
assocExpired2 = _gen_assoc(-7200, 3600)
|
||
|
|
||
|
@store.cleanup_associations
|
||
|
@store.store_association(server_url + '1', assocValid1)
|
||
|
@store.store_association(server_url + '1', assocExpired1)
|
||
|
@store.store_association(server_url + '2', assocExpired2)
|
||
|
@store.store_association(server_url + '3', assocValid2)
|
||
|
|
||
|
cleaned = @store.cleanup_associations()
|
||
|
assert_equal(2, cleaned, "cleaned up associations")
|
||
|
end
|
||
|
|
||
|
def _check_use_nonce(nonce, expected, server_url, msg='')
|
||
|
stamp, salt = Nonce::split_nonce(nonce)
|
||
|
actual = @store.use_nonce(server_url, stamp, salt)
|
||
|
assert_equal(expected, actual, msg)
|
||
|
end
|
||
|
|
||
|
def test_nonce
|
||
|
server_url = "http://www.myopenid.com/openid"
|
||
|
[server_url, ''].each{|url|
|
||
|
nonce1 = Nonce::mk_nonce
|
||
|
|
||
|
_check_use_nonce(nonce1, true, url, "#{url}: nonce allowed by default")
|
||
|
_check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed twice")
|
||
|
_check_use_nonce(nonce1, false, url, "#{url}: nonce not allowed third time")
|
||
|
|
||
|
# old nonces shouldn't pass
|
||
|
old_nonce = Nonce::mk_nonce(3600)
|
||
|
_check_use_nonce(old_nonce, false, url, "Old nonce #{old_nonce.inspect} passed")
|
||
|
|
||
|
}
|
||
|
|
||
|
now = Time.now.to_i
|
||
|
old_nonce1 = Nonce::mk_nonce(now - 20000)
|
||
|
old_nonce2 = Nonce::mk_nonce(now - 10000)
|
||
|
recent_nonce = Nonce::mk_nonce(now - 600)
|
||
|
|
||
|
orig_skew = Nonce.skew
|
||
|
Nonce.skew = 0
|
||
|
count = @store.cleanup_nonces
|
||
|
Nonce.skew = 1000000
|
||
|
ts, salt = Nonce::split_nonce(old_nonce1)
|
||
|
assert(@store.use_nonce(server_url, ts, salt), "oldnonce1")
|
||
|
ts, salt = Nonce::split_nonce(old_nonce2)
|
||
|
assert(@store.use_nonce(server_url, ts, salt), "oldnonce2")
|
||
|
ts, salt = Nonce::split_nonce(recent_nonce)
|
||
|
assert(@store.use_nonce(server_url, ts, salt), "recent_nonce")
|
||
|
|
||
|
|
||
|
Nonce.skew = 1000
|
||
|
cleaned = @store.cleanup_nonces
|
||
|
assert_equal(2, cleaned, "Cleaned #{cleaned} nonces")
|
||
|
|
||
|
Nonce.skew = 100000
|
||
|
ts, salt = Nonce::split_nonce(old_nonce1)
|
||
|
assert(@store.use_nonce(server_url, ts, salt), "oldnonce1 after cleanup")
|
||
|
ts, salt = Nonce::split_nonce(old_nonce2)
|
||
|
assert(@store.use_nonce(server_url, ts, salt), "oldnonce2 after cleanup")
|
||
|
ts, salt = Nonce::split_nonce(recent_nonce)
|
||
|
assert(!@store.use_nonce(server_url, ts, salt), "recent_nonce after cleanup")
|
||
|
|
||
|
Nonce.skew = orig_skew
|
||
|
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class FileStoreTestCase < Test::Unit::TestCase
|
||
|
include StoreTestCase
|
||
|
|
||
|
def setup
|
||
|
raise "filestoretest directory exists" if File.exists?('filestoretest')
|
||
|
@store = Filesystem.new('filestoretest')
|
||
|
end
|
||
|
|
||
|
def teardown
|
||
|
Kernel.system('rm -r filestoretest')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class MemoryStoreTestCase < Test::Unit::TestCase
|
||
|
include StoreTestCase
|
||
|
|
||
|
def setup
|
||
|
@store = Memory.new
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class AbstractStoreTestCase < Test::Unit::TestCase
|
||
|
def test_abstract_class
|
||
|
# the abstract made concrete
|
||
|
abc = Interface.new()
|
||
|
server_url = "http://server.com/"
|
||
|
association = OpenID::Association.new("foo", "bar", Time.now, Time.now + 10, "dummy")
|
||
|
|
||
|
assert_raise(NotImplementedError) {
|
||
|
abc.store_association(server_url, association)
|
||
|
}
|
||
|
|
||
|
assert_raise(NotImplementedError) {
|
||
|
abc.get_association(server_url)
|
||
|
}
|
||
|
|
||
|
assert_raise(NotImplementedError) {
|
||
|
abc.remove_association(server_url, association.handle)
|
||
|
}
|
||
|
|
||
|
assert_raise(NotImplementedError) {
|
||
|
abc.use_nonce(server_url, Time.now.to_i, "foo")
|
||
|
}
|
||
|
|
||
|
assert_raise(NotImplementedError) {
|
||
|
abc.cleanup_nonces()
|
||
|
}
|
||
|
|
||
|
assert_raise(NotImplementedError) {
|
||
|
abc.cleanup_associations()
|
||
|
}
|
||
|
|
||
|
assert_raise(NotImplementedError) {
|
||
|
abc.cleanup()
|
||
|
}
|
||
|
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|