pasaporte 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.
Files changed (41) hide show
  1. data/History.txt +2 -0
  2. data/Manifest.txt +41 -0
  3. data/README.txt +72 -0
  4. data/Rakefile +111 -0
  5. data/TODO.txt +2 -0
  6. data/bin/pasaporte-fcgi.rb +17 -0
  7. data/lib/pasaporte/.DS_Store +0 -0
  8. data/lib/pasaporte/assets/.DS_Store +0 -0
  9. data/lib/pasaporte/assets/bgbar.png +0 -0
  10. data/lib/pasaporte/assets/lock.png +0 -0
  11. data/lib/pasaporte/assets/mainbg_green.gif +0 -0
  12. data/lib/pasaporte/assets/mainbg_red.gif +0 -0
  13. data/lib/pasaporte/assets/openid.png +0 -0
  14. data/lib/pasaporte/assets/pasaporte.css +192 -0
  15. data/lib/pasaporte/assets/pasaporte.js +10 -0
  16. data/lib/pasaporte/assets/user.png +0 -0
  17. data/lib/pasaporte/auth/cascade.rb +16 -0
  18. data/lib/pasaporte/auth/remote_web_workplace.rb +61 -0
  19. data/lib/pasaporte/auth/yaml_digest_table.rb +23 -0
  20. data/lib/pasaporte/auth/yaml_table.rb +43 -0
  21. data/lib/pasaporte/faster_openid.rb +39 -0
  22. data/lib/pasaporte/iso_countries.yml +247 -0
  23. data/lib/pasaporte/julik_state.rb +42 -0
  24. data/lib/pasaporte/markaby_ext.rb +8 -0
  25. data/lib/pasaporte/pasaporte_store.rb +60 -0
  26. data/lib/pasaporte/timezones.yml +797 -0
  27. data/lib/pasaporte.rb +1214 -0
  28. data/test/fixtures/pasaporte_approvals.yml +12 -0
  29. data/test/fixtures/pasaporte_profiles.yml +45 -0
  30. data/test/fixtures/pasaporte_throttles.yml +4 -0
  31. data/test/helper.rb +66 -0
  32. data/test/mosquito.rb +596 -0
  33. data/test/test_approval.rb +33 -0
  34. data/test/test_auth_backends.rb +59 -0
  35. data/test/test_openid.rb +363 -0
  36. data/test/test_pasaporte.rb +326 -0
  37. data/test/test_profile.rb +165 -0
  38. data/test/test_settings.rb +27 -0
  39. data/test/test_throttle.rb +70 -0
  40. data/test/testable_openid_fetcher.rb +82 -0
  41. metadata +151 -0
@@ -0,0 +1,165 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestProfile < Camping::ModelTest
4
+ DOMAIN = 'my-pasaporte.com'
5
+ fixtures :pasaporte_profiles
6
+
7
+ def test_aa_fixtures_loaded
8
+ assert_equal 4, Profile.count
9
+ end
10
+
11
+ def test_assumes_localhost_as_default_domain
12
+ @profile = Profile.new
13
+ assert_equal 'localhost', @profile.domain_name
14
+ end
15
+
16
+ def test_requires_nickname_and_domain
17
+ @profile = Profile.new
18
+
19
+ deny @profile.valid?, "The profile without a nickname and a domain name is invalid"
20
+ @profile.nickname = 'xxx'
21
+ @profile.domain_name = ''
22
+
23
+ deny @profile.valid?, "The profile without a domain name is invalid"
24
+
25
+ @profile.domain_name = 'somedomain'
26
+ assert @profile.valid?
27
+ end
28
+
29
+ def test_domain_name_and_nickname_are_protected
30
+ @profile = Profile.new
31
+ @profile.attributes = {:nickname => 'xyz', :domain_name => 'google'}
32
+
33
+ assert_not_equal @profile.nickname, 'xyz'
34
+ assert_not_equal @profile.domain_name, 'google'
35
+ end
36
+
37
+ def test_find_or_create_by_domain_and_nickname_exempted_from_attribute_protection
38
+ prof = create("julik", "julik.nl")
39
+ assert prof.valid?
40
+ deny prof.new_record?
41
+ assert_equal 'julik.nl', prof.domain_name
42
+ assert_equal 'julik', prof.nickname
43
+ prof = create("julik", "julik.nl")
44
+ assert prof.valid?
45
+ deny prof.new_record?
46
+ assert_equal 'julik.nl', prof.domain_name
47
+ assert_equal 'julik', prof.nickname
48
+ end
49
+
50
+ def test_secret_integer_generated
51
+ secrets = %w( foo bar baz daz daing ).map do | word |
52
+ prof = Profile.find_or_create_by_nickname_and_domain_name(word, word)
53
+ deny prof.new_record?
54
+ prof.secret_salt
55
+ end
56
+ assert_equal secrets.length, secrets.uniq.length,
57
+ "All generated secrets should be autogenerated and unique"
58
+ end
59
+
60
+ def test_enforces_unique_nickname_and_domain
61
+ prof1 = create("MisterZed", "google.com")
62
+ prof2 = Profile.new do | p |
63
+ p.nickname = "MisterZed"
64
+ p.domain_name = "google.com"
65
+ end
66
+
67
+ assert prof1.valid?, "The first created should be valid"
68
+ deny prof2.valid?, "The second one clashes"
69
+
70
+ prof2.domain_name = "yahoo.com"
71
+ assert prof2.valid?, "The second one is valid too because there are no clashes anymore"
72
+ end
73
+
74
+ def test_validates_both_delegate_urls
75
+ p = create("strained", "test.host")
76
+ assert p.valid?, "The newly created profile should be valid"
77
+
78
+ p.openid_server = "watatoe.com/openid"
79
+ deny p.valid?, "The profile cannot be valid with only the server URL"
80
+ assert_not_nil p.errors[:openid_delegate], "Should require delegate URL"
81
+
82
+ p.openid_delegate = "watatoe.com/openid/backend"
83
+ assert p.valid?, "As two URLs are present the profile becomes valid"
84
+ end
85
+
86
+ def test_delegate_urls_removed_when_delegate_set_to_false
87
+ p = create('julik', DOMAIN,
88
+ :openid_server => 'xxx.com', :openid_delegate => 'xyz.org/x')
89
+ assert p.delegates_openid?, "This profile delegates"
90
+ p.delegates_openid = false
91
+ p.save!
92
+
93
+ assert p.openid_server.blank?, "The openid server should have been removed"
94
+ assert p.openid_delegate.blank?, "The openid delegate should have been removed"
95
+ deny p.delegates_openid?, "Delegation is now turned off because we sent a bool switch of false"
96
+ end
97
+
98
+ def test_normalizes_both_delegate_urls
99
+ p = create('julik', DOMAIN,
100
+ :openid_server => 'xxx.com', :openid_delegate => 'xyz.org/x')
101
+ assert_equal 'http://xxx.com/', p.openid_server,
102
+ "The URL should be normalized with HTTP scheme and trailing slash"
103
+ assert_equal 'http://xyz.org/x', p.openid_delegate,
104
+ "The URL should be normalized with HTTP scheme"
105
+ end
106
+
107
+ def test_to_sreg_fields_by_default
108
+ p = create('julik', DOMAIN,
109
+ :email => 'foo@var.com', :dob => Date.parse("10.15.1983"))
110
+ all_fields = p.to_sreg_fields
111
+ r = {"dob"=>"1983-10-15", "nickname"=>"julik", "email"=>"foo@var.com"}
112
+ assert_equal r, all_fields
113
+ end
114
+
115
+ def test_to_sreg_fields_with_requested_fields
116
+ p = create('julik', DOMAIN,
117
+ :email => 'foo@var.com', :dob => Date.parse("10.15.1983"))
118
+ partial_fields = p.to_sreg_fields([:dob, :gender, :country])
119
+ r = {"dob"=>"1983-10-15"}
120
+ assert_equal r, partial_fields
121
+ end
122
+
123
+ def test_to_sreg_fields_with_lotso_data
124
+ mh = Profile.find(1)
125
+ ref = {"dob"=>"1953-01-12", "postcode"=>"1234",
126
+ "nickname"=>"monsieur-hulot",
127
+ "country"=>"fr", "fullname"=>"Monsieur Hulot", "gender"=>"m"}
128
+ assert_equal ref, mh.to_sreg_fields
129
+ end
130
+
131
+ def test_openid_requestor
132
+ begin
133
+ o = Pasaporte::ALLOW_DELEGATION
134
+ silence_warnings { Pasaporte.const_set(:ALLOW_DELEGATION, true) }
135
+
136
+ mh = Profile.find(1)
137
+ deny mh.delegates_openid?
138
+ assert mh.update_attributes(
139
+ :openid_server => 'http://tativille.fr/oid',
140
+ :openid_delegate => 'http://tativille.fr/oid/proc'
141
+ )
142
+
143
+ assert mh.delegates_openid?, "delegates_openid? should be true"
144
+ assert mh.update_attributes(:openid_server => '', :openid_delegate => '')
145
+ deny mh.delegates_openid?, "There are no URLS - no delegation happens"
146
+
147
+ assert mh.update_attributes(
148
+ :openid_server => 'http://tativille.fr/oid',
149
+ :openid_delegate => 'http://tativille.fr/oid/proc'
150
+ )
151
+ silence_warnings { Pasaporte.const_set(:ALLOW_DELEGATION, false) }
152
+ deny mh.delegates_openid?, "Delegation is turned off - "+
153
+ "no delegation happens"
154
+ ensure
155
+ silence_warnings { Pasaporte.const_set(:ALLOW_DELEGATION, o) }
156
+ end
157
+ end
158
+
159
+ private
160
+ def create(nick, domain, extras = {})
161
+ p = Profile.find_or_create_by_nickname_and_domain_name(nick, domain)
162
+ p.update_attributes(extras) if extras.any?
163
+ p
164
+ end
165
+ end
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestSettings < Camping::Test
4
+ CONFIG = File.dirname(Pasaporte::PATH) + '/pasaporte/config.yml'
5
+
6
+ def test_application
7
+ emit :throttle_for => 45.minutes
8
+ assert_nothing_raised { Pasaporte.apply_config! }
9
+ assert_equal 45.minutes, Pasaporte::THROTTLE_FOR, "The setting should have " +
10
+ "been applied"
11
+ end
12
+
13
+ def test_bail_on_unknowns
14
+ emit :achtung => "shtoink"
15
+ e = assert_raise(NameError) { Pasaporte.apply_config! }
16
+ assert_match /ACHTUNG/i, e.message
17
+ end
18
+
19
+ def teardown
20
+ begin; File.unlink(CONFIG); rescue Errno::ENOENT; end
21
+ end
22
+
23
+ private
24
+ def emit(hash = {})
25
+ File.open(CONFIG, 'w') { | f | f << hash.to_yaml }
26
+ end
27
+ end
@@ -0,0 +1,70 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TestThrottle < Camping::ModelTest
4
+ DOMAIN = 'my-pasaporte.com'
5
+ HEADERS = Mosquito::MockRequest::DEFAULT_HEADERS.merge('REMOTE_ADDR' => '120.171.0.1')
6
+
7
+ def setup
8
+ silence_warnings { Pasaporte.const_set(:THROTTLE_FOR, 2.minutes) }
9
+ super
10
+ end
11
+
12
+ def test_throttle_set
13
+ deny Throttle.throttled?(HEADERS)
14
+
15
+ t = Throttle.set!(HEADERS)
16
+ assert_kind_of Throttle, t
17
+ deny t.new_record?
18
+ assert Throttle.throttled?(HEADERS)
19
+ end
20
+
21
+ def test_throttle_response_depends_on_cutoff
22
+ Throttle.set!(HEADERS)
23
+ flexmock(Throttle).should_receive(:cutoff).at_least.once.and_return(Time.now + 10)
24
+ deny Throttle.throttled?(HEADERS)
25
+ end
26
+
27
+ def test_cutoff_depends_on_app_setting
28
+ assert_time_matches (Time.now - Pasaporte::THROTTLE_FOR), Throttle.send(:cutoff)
29
+ silence_warnings{ Pasaporte.const_set(:THROTTLE_FOR, 14) }
30
+ assert_time_matches Time.now - 14, Throttle.send(:cutoff)
31
+ end
32
+
33
+ def test_throttle_response_depends_on_env_params
34
+ envs = [
35
+ {'HTTP_USER_AGENT' => 'KitchenSink, NOT like IE',
36
+ 'REMOTE_ADDR' => '164.10.10.1'},
37
+ {'HTTP_USER_AGENT' => 'WebKit (like Gecko)',
38
+ 'REMOTE_ADDR' => '164.10.10.1'},
39
+ {'HTTP_USER_AGENT' => 'KitchenSink, NOT like IE',
40
+ 'REMOTE_ADDR' => '164.10.10.1'},
41
+ ]
42
+
43
+ Throttle.set!(envs[0])
44
+ assert Throttle.throttled?(envs[0])
45
+ assert Throttle.throttled?(envs[2])
46
+ deny Throttle.throttled?(envs[1]), "This environment is not throttled"
47
+ end
48
+
49
+ def teardown
50
+ Throttle.delete_all
51
+ super
52
+ end
53
+
54
+ def test_throttle_autoexpiry_on_check
55
+ Throttle.set!(HEADERS)
56
+ assert_equal 1, Throttle.count
57
+ flexmock(Throttle).should_receive(:cutoff).at_least.once.and_return(Time.now + 10)
58
+
59
+ deny Throttle.throttled?(HEADERS)
60
+ assert_equal 0, Throttle.count
61
+ end
62
+
63
+ private
64
+ def assert_time_matches(ref, actual)
65
+ assert_kind_of Time, ref, "The reference value should be Time"
66
+ assert_kind_of Time, actual, "The actual value should be Time"
67
+ assert_in_delta(ref.to_i, actual.to_i, 2,
68
+ "The times passed should be within 2s")
69
+ end
70
+ end
@@ -0,0 +1,82 @@
1
+ # Implements OpenID::Fetcher. Will run the request through the mosquito test case instead of calling
2
+ # out via HTTP
3
+ class TestableOpenidFetcher
4
+ # Will be raised when the fetcher tries to get a URL which is
5
+ # not within the application being tested
6
+ class ExternalResource < RuntimeError; end
7
+
8
+ # We need a separate Mosquito tester class for things that will
9
+ # happen via POST, because this is a different flow -
10
+ # the requests of the server instead of the browser.
11
+ # If you post directly from the same test case you are wiring yourself into the
12
+ # session ID that has been gotten by the simulated browser, that's why we use that.
13
+ class OpenidPoster < Pasaporte::WebTest
14
+ attr_reader :request, :response
15
+ def test_foo; assert true; end
16
+ end
17
+
18
+ def initialize(test_case)
19
+ @browser_getter = test_case
20
+ @browser_getter.request.headers['HTTP_HOST'] = 'test.host'
21
+ @server_poster = OpenidPoster.new("test_foo")
22
+ @server_poster.setup # manually yes
23
+ end
24
+
25
+ # This is used by OpenID lib 2
26
+ def fetch(url, body=nil, headers=nil, redirect_limit=10)
27
+ url, url_stringified = URI::parse(url), url.dup
28
+
29
+ h = headers || {}
30
+
31
+ raise_on_external url, @browser_getter
32
+
33
+ camping_controller_with_response = (body.blank? ? get(url.request_uri, h) : post(url.request_uri, h, body))
34
+ ::OpenID::HTTPResponse._from_net_response(FakeResponse.new(camping_controller_with_response), url_stringified)
35
+ end
36
+
37
+ # An adapter to make a Mosquito response (Camping controller) behave like Net::HTTPResponse
38
+ class FakeResponse < ::Net::HTTPResponse
39
+ def initialize(mosquito_response)
40
+ @the = mosquito_response
41
+ super('1.0', @the.status.to_s, 'Found') # http version, resp code and message
42
+ flat_headers = @the.headers.inject({}) { |n, k| n.merge k[0] => k[1].to_s } rescue {}
43
+ initialize_http_header(flat_headers)
44
+ end
45
+
46
+ def body
47
+ @the.body
48
+ end
49
+
50
+ def code
51
+ @the.status.to_s
52
+ end
53
+ end
54
+
55
+ private
56
+ def get(uri, headers = {})
57
+ Pasaporte::LOGGER.debug "OpenID requested GET on #{uri}"
58
+ @browser_getter.get relativized(uri) # this fails somehow
59
+ @browser_getter.response
60
+ end
61
+
62
+ def post(uri, headers = {}, body = '')
63
+ Pasaporte::LOGGER.debug "OpenID requested POST on #{uri}"
64
+ @server_poster.post relativized(uri), body
65
+ @server_poster.response
66
+ end
67
+
68
+ def relativized(uri)
69
+ # Here we need to replace the mount point URL otherwise
70
+ # OpenID gets confused and actually posts into it
71
+ # - Mosquito does not like that
72
+ u = URI.parse(uri)
73
+ u.path.gsub(/^\/pasaporte/, '')
74
+ end
75
+
76
+ # Check if we are calling to the outside world
77
+ def raise_on_external(uri, testcase)
78
+ unless ((uri.host == testcase.request.http_host) || uri.host.blank?)
79
+ raise ExternalResource, "Called out to external resource: OpenID consumer wants to have #{uri}"
80
+ end
81
+ end
82
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pasaporte
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Julik Tarkhanov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-11-03 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: camping
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: ruby-openid
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.1.0
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: flexmock
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: hoe
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.8.2
64
+ version:
65
+ description: An OpenID server with a colored bar on top
66
+ email: me@julik.nl
67
+ executables:
68
+ - pasaporte-fcgi.rb
69
+ extensions: []
70
+
71
+ extra_rdoc_files:
72
+ - History.txt
73
+ - Manifest.txt
74
+ - README.txt
75
+ - TODO.txt
76
+ files:
77
+ - History.txt
78
+ - Manifest.txt
79
+ - README.txt
80
+ - Rakefile
81
+ - TODO.txt
82
+ - bin/pasaporte-fcgi.rb
83
+ - lib/pasaporte.rb
84
+ - lib/pasaporte/.DS_Store
85
+ - lib/pasaporte/assets/.DS_Store
86
+ - lib/pasaporte/assets/bgbar.png
87
+ - lib/pasaporte/assets/lock.png
88
+ - lib/pasaporte/assets/mainbg_green.gif
89
+ - lib/pasaporte/assets/mainbg_red.gif
90
+ - lib/pasaporte/assets/openid.png
91
+ - lib/pasaporte/assets/pasaporte.css
92
+ - lib/pasaporte/assets/pasaporte.js
93
+ - lib/pasaporte/assets/user.png
94
+ - lib/pasaporte/auth/cascade.rb
95
+ - lib/pasaporte/auth/remote_web_workplace.rb
96
+ - lib/pasaporte/auth/yaml_digest_table.rb
97
+ - lib/pasaporte/auth/yaml_table.rb
98
+ - lib/pasaporte/faster_openid.rb
99
+ - lib/pasaporte/iso_countries.yml
100
+ - lib/pasaporte/julik_state.rb
101
+ - lib/pasaporte/markaby_ext.rb
102
+ - lib/pasaporte/pasaporte_store.rb
103
+ - lib/pasaporte/timezones.yml
104
+ - test/fixtures/pasaporte_approvals.yml
105
+ - test/fixtures/pasaporte_profiles.yml
106
+ - test/fixtures/pasaporte_throttles.yml
107
+ - test/helper.rb
108
+ - test/mosquito.rb
109
+ - test/test_throttle.rb
110
+ - test/testable_openid_fetcher.rb
111
+ - test/test_approval.rb
112
+ - test/test_auth_backends.rb
113
+ - test/test_openid.rb
114
+ - test/test_pasaporte.rb
115
+ - test/test_profile.rb
116
+ - test/test_settings.rb
117
+ has_rdoc: true
118
+ homepage: http://pasaporte.rubyforge.org
119
+ post_install_message:
120
+ rdoc_options:
121
+ - --main
122
+ - README.txt
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: "0"
130
+ version:
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: "0"
136
+ version:
137
+ requirements: []
138
+
139
+ rubyforge_project: pasaporte
140
+ rubygems_version: 1.2.0
141
+ signing_key:
142
+ specification_version: 2
143
+ summary: Downgrades the OpenID providing business to the usual login-password stupidity.
144
+ test_files:
145
+ - test/test_approval.rb
146
+ - test/test_auth_backends.rb
147
+ - test/test_openid.rb
148
+ - test/test_pasaporte.rb
149
+ - test/test_profile.rb
150
+ - test/test_settings.rb
151
+ - test/test_throttle.rb